Rendering only working when scrolling or moving mouse - three.js

I have a big problem getting my animation to work, nothing animates in the scene unless I look around with my mouse. And as soon I stop looking around the animation stops. Tried alot of things and canĀ“t figure it out what im doing wrong.
function onMouseMove(e) {
mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;
}
window.addEventListener( "mousemove", onMouseMove, false );
window.requestAnimationFrame(render);
function animate(){
controls.update();
renderer.render(scene, camera);
requestAnimationFrame(animate);
}
function render(){
sunArray[1].rotation.y += 0.01;
renderer.render(scene, camera);
};

You need to make it call requestAnimation frame repeatedly:
window.requestAnimationFrame(render);
should work

function animate(){
sunArray[1].rotation.y += 0.01;
controls.update();
renderer.render(scene, camera);
requestAnimationFrame(animate);
}
function render(){
renderer.render(scene, camera);
};

Related

How to change rotation direction in three.js

I'm new to three.js and having trouble finding documentation on how to change rotation direction. The current rotation is set so the sphere looks like it's spinning towards the viewer on a screen but I want it to rotate in a clockwise direction, so it looks like it's spinning from a side view if a viewer is looking at it.
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(50, 500 / 400, 1, 1000);
var renderer = new THREE.WebGLRenderer();
renderer.setSize(500, 400);
document.body.appendChild(renderer.domElement);
var geometry = new THREE.SphereGeometry(3, 50, 50, 0, Math.PI * 2, 0, Math.PI * 2);
var material = new THREE.MeshNormalMaterial();
var cube = new THREE.Mesh(geometry);
scene.add(cube);
camera.position.z = 10;
var render = function () {
requestAnimationFrame(render);
cube.rotation.x -= 0.10;
cube.rotation.y += 0.00;
renderer.render(scene, camera);
};
render();
http://jsfiddle.net/SF9tX/1968/
If I understand your question correctly, then rotation around different directions (or axis') can be achieved by incrementing different components of the objects rotation vector.
So for example, if you want to rotate the cube around the y-axis (ie to create a "spinning globe" effect) you can increment the .y component of the .rotation vector, as follows:
var render = function () {
requestAnimationFrame(render);
// This was casuing rotation around about the x-axis
// cube.rotation.x -= 0.10;
// Add this to cause rotation around the z-axis,
cube.rotation.z += 0.10;
renderer.render(scene, camera);
};
Ah I figured it out. It's as simple as replacing the cube.rotation.x to cube.rotation.z, so:
camera.position.z = 10;
var render = function () {
requestAnimationFrame(render);
cube.rotation.z -= 0.10;
cube.rotation.y += 0.00;
renderer.render(scene, camera);
};

touch controls: repeat action until touchend

I am trying to add touch controls to a three.js scene. I want to move the camera in whatever direction the user touches. It works great using the keyboard because you can press and hold the button and the camera moves continuously. But when I try the same thing using touchstart, you have to keep tapping the screen over and over to move, you can't just hold your finger down like on a keyboard or mouse.
I looked at touchmove, but if you just tap and hold without moving, there are no new touches.
Is there something similar to holding down the keyboard or mousekey using touch events?
There is no builtin callback for a touch event which fires repeatedly like the keyboard. You can, however, simply track the start and end of the touch and then call the move method at a set interval.
First, subscribe to the correct events and set a bool to track the state:
var isTouching = false;
window.addEventListener("touchstart", () => isTouching = true);
window.addEventListener("touchend", () => isTouching = false);
In Three.js you will most likely already have a render loop (e.g. a function called "animate"). Check the state variable at every iteration and apply the movement each time. You may need to also factor in deltaTime (the duration of the last frame), to make movement framerate independent.
function animate() {
requestAnimationFrame(animate);
mesh.rotation.x += 0.005;
mesh.rotation.y += 0.01;
if (isTouching) {
console.log("move camera");
}
renderer.render(scene, camera);
}
Here is a snippet which shows the basic approach. Click and hold in the left or right half of the output window to move the camera.
var camera, scene, renderer, mesh, material, clock;
init();
animate();
var isTouching = false;
var mousePositionX;
window.addEventListener("mousedown", (e) => {
isTouching = true;
mousePositionX = e.clientX;
});
window.addEventListener("mouseup", (e) => isTouching = false);
function init() {
renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
clock = new THREE.Clock();
camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.z = 400;
scene = new THREE.Scene();
material = new THREE.MeshPhongMaterial();
var geometry = new THREE.BoxGeometry(200, 200, 200);
mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
var light = new THREE.AmbientLight(0x404040);
scene.add(light);
var directionalLight = new THREE.DirectionalLight(0xffffff);
directionalLight.position.set(1, 1, 1).normalize();
scene.add(directionalLight);
window.addEventListener('resize', onWindowResize, false);
}
function animate() {
requestAnimationFrame(animate);
mesh.rotation.x += 0.005;
mesh.rotation.y += 0.01;
let deltaTime = clock.getDelta();
if (isTouching) {
let speed = 200; // px per second
let movement = speed * deltaTime;
if (mousePositionX > window.innerWidth / 2) {
camera.translateX(-movement);
} else {
camera.translateX(movement);
}
}
renderer.render(scene, camera);
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
body {
padding: 0;
margin: 0;
}
canvas {
display: block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/93/three.min.js"></script>

How to use Stereo Effect (VR) and Post Processing (THREE.JS R76)

I have a post processing bloom shader running and a VR (virtual reality) conditional stereo effect. They don't seem to want to work together. I am likely just implementing this wrong. Here is the code but where is the mistake?
In my Init()
effectPass = new THREE.ShaderPass(THREE.CopyShader);
bloomPass = new THREE.BloomPass(2);
renderPass = new THREE.RenderPass( scene, camera );
composer = new THREE.EffectComposer(renderer);
composer.addPass(renderPass);
composer.addPass(bloomPass);
composer.addPass(effectPass);
effectPass.renderToScreen = true;
renderer.autoClear = false;
if (vr) {
stereo = new THREE.StereoEffect(renderer);
stereo.setSize( window.innerWidth, window.innerHeight );
}
In my render()
renderer.clear();
composer.render();
renderFrame = requestAnimationFrame(render);
if (vr) { stereo.render(scene, camera); }
else { renderer.render(scene, camera); }

How to turn off animation in three.js

While testing code in three.js, animation is not needed. I can see the first rendered frame. This would use less power, and stop the fan on the laptop from kicking in as the graphics card heats up.
The examples in three.js have the following structure:
function init() {
animate()
}
function animate() {
requestAnimationFrame( animate );
render();
targetRotation = targetRotationOnMouseDown + ( mouseX - mouseXOnMouseDown ) * 0.05;
}
function render() {
group.rotation.y += ( targetRotation - group.rotation.y ) * 0.05;
renderer.render( scene, camera );
}
I do not see how to turn off the repeated calls to animate.
Is there any easy way to turn off animation?
You do not have to have an animation loop in three.js -- say, if you have a static scene. Just call
renderer.render( scene, camera );
You will need to re-render whenever the camera moves or when loaders finish loading models or loading textures.
If you are using OrbitControls with a static scene, you can instantiate OrbitControls like so:
controls = new THREE.OrbitControls( camera, renderer.domElement );
controls.addEventListener( 'change', render ); // use if there is no animation loop
where render() calls renderer.render( scene, camera ).
If you are loading models or textures, the three.js loaders have a callback function you can specify. For example,
var loader = new THREE.TextureLoader();
var texture = loader.load( 'myTexture.jpg', render );
Also
var manager = new THREE.LoadingManager();
var loader = new THREE.OBJLoader( manager );
loader.load( 'myModel.obj', function( object ) {
// your code...
render();
}
three.js r.75

Object always in front of camera

On a scene, I've got a camera and an obj.
I want my obj always looks at the camera.
I tried with:
function render() {
camera.updateProjectionMatrix();
var zCamVec = new THREE.Vector3(0,0,1);
camera.localToWorld(zCamVec);
obj.lookAt(zCamVec);
renderer.render(scene, camera);
}
but without luck: my obj stays static...
if i understand you right, the object needs to reposition in front of the camera, and look at the camera.
try this:
function render() {
camera.updateProjectionMatrix();
var zCamVec = new THREE.Vector3(0,0,1);
var position = camera.localToWorld(zCamVec);
obj.position.set(position.x, position.y, position.z);
obj.lookAt(camera.position);
renderer.render(scene, camera);
}

Resources