I'am trying to change position/translate dinamicaly of TubeBufferGeometry.parameters.path which i will use for camera animation
(all are based on this example: webgl_geometry_extrude_splines)
here is my peace of code so far
full code: Link to codesandbox with full code
Important part of code:
function init(){
// initial scene render etc. for full code take a look at codesanbox
// tube
var extrudePath = new Curves.GrannyKnot();
tubeGeometry = new THREE.TubeBufferGeometry( extrudePath, 50, 2, 1, true );
tubeGeometry.dynamic = true;
//unsuccessful approach to change the parameters of position
tubeGeometry.translate(100, 0, 0)
tubeGeometry.attributes.position.needsUpdate = true;
}
function animate() {
requestAnimationFrame( animate );
render();
}
function render() {
// animate camera along spline
var time = Date.now();
var looptime = 20 * 1000;
var t = ( time % looptime ) / looptime;
var pos = tubeGeometry.parameters.path.getPointAt( t );
pos.multiplyScalar( 1 );
splineCamera.position.copy( pos );
renderer.render( scene, splineCamera );
}
The resault is giving me no translation of camera its moving around GrannyKnot curve in default position.
What i'm expecting is to dynamic change position/translate of TubeBufferGeometry.parameters.path in some direction (for example position X + 100) which affects on my camera movement
EDIT
I just realised that i could change camera by adding
function render() {
// animate camera along spline
var time = Date.now();
var looptime = 20 * 1000;
var t = ( time % looptime ) / looptime;
var pos = tubeGeometry.parameters.path.getPointAt( t );
pos.x += 100; //<----this line added
pos.multiplyScalar( 1 );
splineCamera.position.copy( pos );
renderer.render( scene, splineCamera );
}
But if someone would show me how to change TubeBufferGeometry.parameters.path without changing definite pos.x like in code above it. I would be very glad for that.
Related
I am rotating a cube by 90 degrees using tween.js but there are these things that are not working as expected,
I am using this code:
var start = {x:cube[1].rotation.x, y:cube[1].rotation.y, z:cube[1].rotation.z};
var end = {x:cube[1].rotation.x, y:cube[1].rotation.y + degreeToRadians(90),z:cube[1].rotation.z};
var tween = new TWEEN.Tween(start)
.to(end, 1000)
.easing( TWEEN.Easing.Exponential.InOut )
.onUpdate(function(){
cube[1].rotation.x = this.x;
cube[1].rotation.y = this.y;
cube[1].rotation.z = this.z;
})
.start()
console.log(cube[1].rotation.y);
by using this the cube rotates by 90 degress along y axis
but in the console it gives value for rotation 0
and when i rotate it again as many times it adds 1.570796 to the rotation value every time.So, I am confused why it does not add this value only the first time.
So to solve the problem i did this
cube[1].rotation.y+=1.57079632679; //1
i added this after every rotation but instead of increasing the value every time which should create problem after first rotation it only increases it once.Value of cube[1].rotation.y goes like this
rotation 1st
before rotation 0
after rotation 1.57.... //because of 1
rotation 2nd
before rotation 1.57....
after rotation 3.14.... //when it should have been 3.14...+ 1.57...
and so my code works even though it shouldn't
and if i add 1.57 only after the first rotation,the rotation lags by 1.
So can anyone explain this.
And when I added this
cube[1].rotation.y+=1.57079632679;
Shouldn't it supposed to not only increase its value but rotate the cube without any animation as well but instead it only does the first part.Why?
EDIT
Actually i haven't placed it in render function but instead I am rotating it on mouse click,here is the code for it:
var mouseDown = false,
pageX = 0;
function onMouseDown(evt)
{
evt.preventDefault();
mouseDown = true;
pageY = evt.pageY;
pageX = evt.pageX;
var x = event.x;
var y = event.y;
mouse.x = ( event.clientX / renderer.domElement.clientWidth ) * 2 - 1;
mouse.y = - ( event.clientY / renderer.domElement.clientHeight ) * 2 + 1;
raycaster.setFromCamera( mouse, camera );
var intersects = raycaster.intersectObjects( objects );
if ( intersects.length > 0 ) {
if(intersects[ 0 ].object==cube[1])
{
move();
}
}
}
function move (){
var start = {x:cube[1].rotation.x, y:cube[1].rotation.y, z:cube[1].rotation.z};
var end = {x:cube[1].rotation.x , y:cube[1].rotation.y + degreeToRadians(90),
z:cube[1].rotation.z};
var tween = new TWEEN.Tween(start)
.to(end, 1000)
.easing( TWEEN.Easing.Exponential.InOut )
.onUpdate(function(){
cube[1].rotation.x = this.x;
cube[1].rotation.y = this.y;
cube[1].rotation.z = this.z;
})
.start()
console.log(cube[1].rotation.y);
cube[1].rotation.y+=1.57079632679;
console.log(cube[1].rotation.y);
}
function degreeToRadians(degrees) {
return degrees * Math.PI / 180;
}
function onMouseUp(evt)
{
evt.preventDefault();
mouseDown = false;
}
function animate() {
requestAnimationFrame( animate );
render();
stats.update();
}
function render() {
TWEEN.update();
renderer.render( scene, camera );
}
You try to move the increment of Y rotation before the tween
function move (){
cube[1].rotation.y+=1.57079632679; // HERE !!!
var start = {x:cube[1].rotation.x, y:cube[1].rotation.y, z:cube[1].rotation.z};
var end = {x:cube[1].rotation.x , y:cube[1].rotation.y + degreeToRadians(90),
z:cube[1].rotation.z};
var tween = new TWEEN.Tween(start)
.to(end, 1000)
.easing( TWEEN.Easing.Exponential.InOut )
.onUpdate(function(){
cube[1].rotation.x = this.x;
cube[1].rotation.y = this.y;
cube[1].rotation.z = this.z;
})
.start()
console.log(cube[1].rotation.y);
// NOT HERE !!!!
console.log(cube[1].rotation.y);
}
In your code you correct rotate the cube by 90°, but at the first render loop the rotation is forced to the tween count value.
Moving first you start the tween with the correct value (rotation + 90°)
I hope I understood your problem!
I'm using Three.js and have a question. Within particle function, I'm adding image, which flying around. Code:
function makeParticles() {
var particle, material;
// we're gonna move from z position -1000 (far away)
// to 1000 (where the camera is) and add a random particle at every pos.
for ( var zpos= -1000; zpos < 1000; zpos+=20 ) {
// we make a particle material and pass through the
// colour and custom particle render function we defined.
var particleTexture = THREE.ImageUtils.loadTexture('img/fly.png');
material = new THREE.ParticleBasicMaterial( { map: particleTexture, transparent: true, program: particleRender } );
// make the particle
particle = new THREE.Particle(material);
// give it a random x and y position between -500 and 500
particle.position.x = Math.random() * 1000 - 500;
particle.position.y = Math.random() * 1000 - 500;
// set its z position
particle.position.z = zpos;
// scale it up a bit
particle.scale.x = particle.scale.y = 0.3;
// add it to the scene
scene.add( particle );
// and to the array of particles.
particles.push(particle);
}
}
Problem is, when I'm resizing page, all those images gets their width crushed and does not keep proportions. How to keep size of images, while resizing page?
Full code:
<script>
// the main three.js components
var camera, scene, renderer,
// to keep track of the mouse position
mouseX = 0, mouseY = 0,
// an array to store our particles in
particles = [];
// let's get going!
init();
function init() {
// Camera params :
// field of view, aspect ratio for render output, near and far clipping plane.
camera = new THREE.PerspectiveCamera(-50, window.innerWidth / window.innerHeight, -20, -10000 );
// move the camera backwards so we can see stuff!
// default position is 0,0,0.
camera.position.z = 80;
// the scene contains all the 3D object data
scene = new THREE.Scene();
// camera needs to go in the scene
scene.add(camera);
// and the CanvasRenderer figures out what the
// stuff in the scene looks like and draws it!
renderer = new THREE.CanvasRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
// the renderer's canvas domElement is added to the body
document.body.appendChild( renderer.domElement );
makeParticles();
// add the mouse move listener
document.addEventListener( 'mousemove', onMouseMove, false );
// render 30 times a second (should also look
// at requestAnimationFrame)
setInterval(update,1000/30);
}
// the main update function, called 30 times a second
function update() {
updateParticles();
// and render the scene from the perspective of the camera
renderer.render( scene, camera );
}
// creates a random field of Particle objects
function makeParticles() {
var particle, material;
// we're gonna move from z position -1000 (far away)
// to 1000 (where the camera is) and add a random particle at every pos.
for ( var zpos= -1000; zpos < 1000; zpos+=20 ) {
// we make a particle material and pass through the
// colour and custom particle render function we defined.
var particleTexture = THREE.ImageUtils.loadTexture('img/fly.png');
material = new THREE.ParticleBasicMaterial( { map: particleTexture, transparent: true, program: particleRender } );
// make the particle
particle = new THREE.Particle(material);
// give it a random x and y position between -500 and 500
particle.position.x = Math.random() * 1000 - 500;
particle.position.y = Math.random() * 1000 - 500;
// set its z position
particle.position.z = zpos;
// scale it up a bit
particle.scale.x = particle.scale.y = 0.3;
// add it to the scene
scene.add( particle );
// and to the array of particles.
particles.push(particle);
}
}
// there isn't a built in circle particle renderer
// so we have to define our own.
function particleRender( context ) {
// we get passed a reference to the canvas context
context.beginPath();
// and we just have to draw our shape at 0,0 - in this
// case an arc from 0 to 2Pi radians or 360ยบ - a full circle!
context.arc( 0, 0, 1, 0, Math.PI * 2, true );
context.fill();
};
// moves all the particles dependent on mouse position
function updateParticles() {
// iterate through every particle
for(var i=0; i<particles.length; i++) {
particle = particles[i];
// and move it forward dependent on the mouseY position.
particle.position.z += mouseY * 0.02;
// if the particle is too close move it to the back
if(particle.position.z>1500) particle.position.z-=2300;
}
}
// called when the mouse moves
function onMouseMove( event ) {
// store the mouseX and mouseY position
mouseX = event.clientX;
mouseY = event.clientY;
}
</script>
I guess, you need to resize the renderer and update the camera aspect ratio. The following code can be found in almost every three.js example, but I don't see it in your code.
window.addEventListener( 'resize', onWindowResize, false );
function onWindowResize() {
var canvasWidth = window.innerWidth;
var canvasHeight = window.innerHeight;
renderer.setSize( canvasWidth, canvasHeight );
camera.aspect = canvasWidth / canvasHeight;
camera.updateProjectionMatrix();
}
I have my current position of the camera, and the final position (focusing on an element). I would like to make an animation of the camera going from the beginning to the end.
Thank you.
An idea is create a unit vector which represents direction from camera to object. Then using this value for changing camera's vector position in time:
var speed = 4;
var p = camera.position;
var dt = p.clone();
dt.normalize();
dt.multiplyScalar(speed);
And then in render function:
function render () {
if (camera.position.length() > 0) {
camera.position.sub(dt);
}
renderer.render(scene, camera);
requestAnimationFrame(render);
}
https://jsfiddle.net/dc3La82y/
Thanks! I applied that, the problem is that I try to render in bucle while the camera is approaching the element, but it only shows it when it reached it, nothing shows in the way to the object.
Here is the code:
var cameraPos = new THREE.Vector3().addVectors(elementCenter, new THREE.Vector3(distance, distance, distance));
var cameraLook = new THREE.Vector3(elementCenter.x, elementCenter.y, elementCenter.z);
//camera.position.set(cameraPos.x, cameraPos.y, cameraPos.z);
camera.lookAt(new THREE.Vector3(cameraLook.x, cameraLook.y, cameraLook.z));
var dx = camera.position.x - cameraPos.x;
var dy = camera.position.y - cameraPos.y;
var dz = camera.position.z - cameraPos.z;
var p = new THREE.Vector3(dx, dy, dz);
var speed = 400;
var dt = p.clone();
dt.normalize();
dt.multiplyScalar(speed);
var times = p.length() / speed;
for ( i = 0; i < times; i++ ) {
camera.position.sub(dt);
camera.lookAt(new THREE.Vector3(cameraLook.x, cameraLook.y, cameraLook.z)); //because it is changed when camera moves, I have to give it its value again
render();
requestAnimationFrame(render);
}
I think this is really simple question (I'm just learning three.js) and I'm failing to find the right words to search by, but here we go.
I'm working on animated a spinning Earth. I want the Earth to always start its rotation from the same point when the viewer loads the page. Since I'm learning as I go along, I started with a boilerplate from http://jeromeetienne.github.com/threejsboilerplatebuilder/ and have subtracted elements I don't require and tried to add things that I need based on other examples found around the web. The animation works fine other than the initial direction issue. Right now if I reload the animation, the globe position picks up where it was before I hit reload instead of reseting to an initial position. Here's my script:
var scene, renderer, composer;
var camera, cameraControl;
var globe;
if( !init() ) animate();
// init the scene
function init(){
if( Detector.webgl ){
renderer = new THREE.WebGLRenderer({
antialias : true, // to get smoother output
});
}else{
renderer = new THREE.CanvasRenderer();
}
renderer.setSize( 567,567 );
document.getElementById('Stage_globe3d').appendChild(renderer.domElement);
// create a scene
scene = new THREE.Scene();
// put a camera in the scene
var cameraH = 3;
var cameraW = cameraH / 567 * 567;
camera = new THREE.OrthographicCamera( -cameraW/2, +cameraW/2, cameraH/2, -cameraH/2, -10000, 10000 );
camera.position.set(0, 0, 5);
scene.add(camera);
// here you add your objects
var light = new THREE.DirectionalLight(0xffffff, 2 );
light.position.set( 0,0,10 ).normalize();
scene.add( light );
var geometry = new THREE.SphereGeometry( 1.45, 50, 50 );
var material = new THREE.MeshLambertMaterial({map: THREE.ImageUtils.loadTexture("images/world.jpg")});
var globe = new THREE.Mesh( geometry, material );
// tried adding this, but it didn't work
//globe.rotation.y = 100;
scene.add( globe );
}
// animation loop
function animate() {
// loop on request animation loop
// - it has to be at the begining of the function
// - see details at http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating
requestAnimationFrame( animate );
// do the render
render();
}
// render the scene
function render() {
var PIseconds = Date.now() * Math.PI;
// animation of all objects
for( var i = 0; i < scene.objects.length; i ++ ){
scene.objects[ i ].rotation.y = PIseconds*0.00003 * (i % 2 ? 1 : 1);
}
// actually render the scene
renderer.render( scene, camera );
}
I thought it might have to do with the rotation animation being based on the current time (which I got from the boilerplate) but I've seen other examples that do something similar but still always start from the same initial position (Walt Disney head from the three.js examples on github, for example). Could someone tell me what I'm doing wrong and steer me in the right direction?
Thanks.
In your init() routine set
globe.rotation.y = initialValueInRadians;
Then in your render() loop, set
globe.rotation.y += delta;
where delta is defined as a constant, like 0.01, or as a function of elapsed time.
Is there any way to move an object forward in Three.js?
Maybe I should convert the rotation.x,y,z to a vector, and deal with it. But I'm beginner, and I don't have any idea how to do it.
Object3D has some handy methods for that.
object.translateZ( 10 );
Please use above answer of #mrdoob, creator of ThreeJS:
object.translateZ( delta );
===OLD ANSWER===
A tutorial that worked for older ThreeJS version:
http://www.aerotwist.com/tutorials/getting-started-with-three-js/
// set position of YOUR_OBJECT
YOUR_OBJECT.position.x = 10;
YOUR_OBJECT.position.y = 50;
YOUR_OBJECT.position.z = 130;
More options:
var STEP = 10;
var newCubeMatrix = cube.matrix;
newCubeMatrix.identity();
//newCubeMatrix.multiplySelf(THREE.Matrix4.rotationYMatrix(cube.rotation.y));
newCubeMatrix.multiplySelf(THREE.Matrix4.translationMatrix(cube.position.x, cube.position.y, cube.position.z + STEP));
cube.updateMatrix();
details posted here https://gamedev.stackexchange.com/questions/7490/translate-object-in-world-space-usings-its-local-rotation
The camera is a point in space.
"Forward" is another point in space.
so you can simply use the coordinates of a second point, and make the camera location closer to the "forward" location.
however, you may also need to turn left and right, which might involve polar coordinates.
adjust these values for your convenience:
var scene;
var camera;
var playerDirection = 0;//angles 0 - 2pi
var dVector;
var angularSpeed = 0.01;
var playerSpeed = 0.075;
var playerBackwardsSpeed = playerSpeed * 0.4;
this function will initialize the scene:
function init(){
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
camera.position.z = 5;
dVector = new THREE.Vector3( 0, 0, 0 ) ;
camera.lookAt( dVector );
animate();
}
movement of the player is stopped when the player presses the up key.
function key_up(event){
playerIsMovingForward = 0;
playerIsMovingBackwards = 0;
playerIsRotatingLeft = 0;
playerIsRotatingRight = 0;
playerGoesUp = 0;
playerGoesDown = 0;
}
when the player is moving, we update the position:
function updatePlayer(){
if(playerIsRotatingLeft){ // rotate left
playerDirection -= angularSpeed;
}
if(playerIsRotatingRight){ // rotate right
playerDirection += angularSpeed;
}
if(playerIsRotatingRight || playerIsRotatingLeft){
setPlayerDirection();
}
if(playerIsMovingForward){ // go forward
moveForward(playerSpeed);
}
if(playerIsMovingBackwards){ // go backwards
moveForward(-playerBackwardsSpeed);
}
}
We assume by forward you meant "using the WASD keys"
function key_down(event){
var W = 87;
var S = 83;
var A = 65;
var D = 68;
var minus = 189;
var plus = 187;
var k = event.keyCode;
console.log(k);
if(k == A){ // rotate left
playerIsRotatingLeft = 1;
}
if(k == D){ // rotate right
playerIsRotatingRight = 1;
}
if(k == W){ // go forward
playerIsMovingForward = 1;
}
if(k == S){ // go back
playerIsMovingBackwards = 1;
}
}
player will only move as fast as his browser.
so maybe adjust this code?
function animate() {
requestAnimationFrame( animate );
updatePlayer();
renderer.render( scene, camera );
}
this is the code that moves the camera into the position of the dVector object
and also repositions the direction vector (dVector), so that it is always forward from the camera.
function moveForward(speed){
var delta_x = speed * Math.cos(playerDirection);
var delta_z = speed * Math.sin(playerDirection);
var new_x = camera.position.x + delta_x;
var new_z = camera.position.z + delta_z;
camera.position.x = new_x;
camera.position.z = new_z;
var new_dx = dVector.x + delta_x;
var new_dz = dVector.z + delta_z;
dVector.x = new_dx;
dVector.z = new_dz;
camera.lookAt( dVector );
}
moving forward usually involves turning left and right, here is some code that does that, it also uses polar coordinates, to move the point in relation to the camera (which is the center of the "circle" by a given amount of degrees (in radians)
function setPlayerDirection(){
//direction changed.
var delta_x = playerSpeed * Math.cos(playerDirection);
var delta_z = playerSpeed * Math.sin(playerDirection);
var new_dx = camera.position.x + delta_x;
var new_dz = camera.position.z + delta_z;
dVector.x = new_dx;
dVector.z = new_dz;
console.log(dVector);
camera.lookAt( dVector );
}
animate();
I hope that helps.
Another option is to use Vector3's set method/function.
position.set(x, y, z);