Animate object's size in THREEjs - javascript

Using THREE.js I would like to animate the size of an object so it slowly shrinks into nothingness.
Using answers from Three.js - Animate object size I can change the size of an object, but this size change is instant and I want the change to happen over a period of time (3 seconds). Plus the question is old :)
This is my current code. backwardMeshOct is simply a THREE.Mesh(geometry, material):
var time = 20;
function animate() {
backwardMeshOct.scale.x = Math.abs( Math.sin( time * 50 ) );
}
requestAnimationFrame(animate);
I've tried altering var time and what time is multiplied by but the result is still the same, an instant size scale on x.
Thanks for your help doods and doobs.

You might find it easier to use a library like Tween.JS. You'll be able to define a starting value, a target value, and a time delta for the change!
Check out the answer to this question for how it can work with Three: Tween JS basics on three JS cube
If you aren't able to use Tween, try a THREE.Clock object to keep track of the time and scale your mesh appropriately. I made one in a global scope (before init) and then used it to count to 3 seconds:
function render() {
mesh.rotation.x += 0.01;
mesh.rotation.y += 0.02;
var t = clock.getElapsedTime();
if (t >= 3.0)
{
clock = new THREE.Clock;
mesh.scale.set(1,1,1);
}
else
{
mesh.scale.x = 1-(t/3.0);
mesh.scale.y = 1-(t/3.0);
mesh.scale.z = 1-(t/3.0);
}
renderer.render(scene, camera);
}
full example here: http://jsfiddle.net/adamfinley/ac6zxgt6/1/

Related

Animate a flying bird in p5.js

I want to create an animation of a bird with p5 js. I have 6 pictures of the bird - when the wings are up, in the middle, and so on... When I press 'space bar' on the keyboard, the bird should fly - so all the pics should be shown as an animation (as if the bird is really flying). I want to build this code snippet without spritemap.
This is my code, but somehow it doesn't work..
let time = 0;
let frame = 0;
let img = [];
function preload() {
img.push(loadImage("assets/Bird/bird-1.png"));
img.push(loadImage("assets/Bird/bird-2.png"));
img.push(loadImage("assets/Bird/bird-3.png"));
img.push(loadImage("assets/Bird/bird-4.png"));
img.push(loadImage("assets/Bird/bird-5.png"));
}
function draw() {
function keyPressed() {
if (key == ' ') {
const speed = 1;
const numImage = img.length;
let current = frame % numImage;
let display = img[current];
image(display, width / 2, height / 2, display.width, display.length);
time += speed;
if (time > 5) {
time = 0;
frame++;
}
}
}
}
Looking forward to reading some ideas! Thank you in advance.
First things first you should not need to handle frames and such things. It is better to use keyPressed function outside of scope draw since it is a special event function and automatically called when a key is pressed.
It is better to use setup functionality instead of preload since preload is a little bit more early function then we needed. Setup is more relevant in such things like loading an array and so on.
I see that you forgot to create a canvas to draw an image on it. I added that on setup and also set the framerate of canvas regarding the img array's size.
function setup() {
createCanvas(400, 400);
background(51);
img.push(loadImage("1.png"));
img.push(loadImage("2.png"));
img.push(loadImage("3.png"));
img.push(loadImage("4.png"));
frameRate(img.length * 2); // double speed on animate sprites
}
From this point it is only a matter of checking the keyCode and looping through array.
function draw() {
if (keyIsDown(32)) {
background(51);
const numImage = img.length;
let current = frameCount % numImage;
let display = img[current];
image(display, width / 2 - display.width , height / 2 - display.height , display.width, display.length);
}
}
Here in the keyIsDown(32) check, 32 represents spacebar. You can check others from here easily : http://keycode.info/
You want to re-set the background of canvas on each sprite display. If not, they will still be showing on each render.
You can see the working version of your code in here :
https://editor.p5js.org/darcane/sketches/rVl22hkv7

STL loading and incorrect world matrix access

for a three.js project I have I have run into a few problems loading vertices from an STL and adequately converting them to world coordinates. It seems the matrix isn't being applied properly and, I think, it might be related to the loading mechanism itself.
loader.load( './assets/models/trajan_print.stl', function ( geometry ) {
var mesh = new THREE.Mesh( geometry, material );
mesh.name = "target";
mesh.position.set( 0, - 300, - 400 );
mesh.rotation.set( - Math.PI / 2, 0, Math.PI );
mesh.scale.set( 5, 5, 5 );
//mesh.castShadow = true;
//mesh.receiveShadow = true;
mesh.visible = false;
SCENE.add( mesh );
model.setTargets(mesh);
} );
the important function to note is the last one. model.setTargets(mesh). I'm interested in the vertices of the object in world coordinates and that's what that function does... kinda of:
setTargets(mesh){
this.matrixWorld = mesh.matrixWorld; //THIS WORKS, PRINTING IT REVEALS VALUES TRANSLATION/SCALE/ROTATION THAT MATCH THE MODEL'S
var buffer = mesh.geometry.attributes.position.array;
for(var i = 0; i < buffer.length /3; i = i + 3){
var point = new THREE.Vector3(buffer[i], buffer[i+1],buffer[i+2]);
point.applyMatrix4(this.matrixWorld);//DOES NOT WORK
this.unassignedVertices.push(point);
}
}
Now if I do the exact same operation outside of this function it will work as intended. This one is only called if this.unassignedVertices so it was my way around the fact that I needed to wait for the asynchronous load to happen.
insertParticle(part) {
var point = this.unassignedVertices.pop();
point.applyMatrix4(this.matrixWorld); //THIS WORKS BUT HERE BUT WHY?
part.setTargetPoint(point);
this.octree.add(part);
this.particles.add(part);
}
Problem number two, relates back to setTargets(mesh) I seem to only be loading around only half of the vertices from mesh.geometry.attributes.position.array. Now this can actually be caused by other parts in the code and I think that is something that falls outside the scope of a SO question so my question is if anything on that function could be responsible for it? Am I loading it improperly, am I converting it wrong, am I skipping points?
As for further context : the model loads and displays just fine if I remove the visible = false tag.
Ok so if anyone runs into this problem. The array will have duplicate positions as not all of them refer to vertices (probably). Simple case of if(position.x == ... cleans it right up to what's expected.

Three js tween js performance lag with many simultaneous tweens

Long time first time and all that - I'm new to Three.js and Tween.js and was hoping to see if it's possible to simultaneously tween 200k Three.js vertices from one position to another. Please excuse my interchangeable use of the words pixels and vertices.
I would like to display 200k pixels in a grid. A user can decide to sort these 200k pixels in a number of ways causing them to rearrange in the grid. I would like all pixels to simultaneously tween between their initial position and final position. Currently, I have the vertices simultaneously moving with tweens but I'm having severe performance issues once the animation nears completion. I hope someone can help!
For each of the 200k vertices I have a tween object associated with them living in this list that I create after drawing vertices in the scene,
var scPartVerts = scene.children[0].geometry.vertices;
var dataSetLen = 200000;
tweenList = []
for (i=0; i<dataSetLen; i ++){
tweenList.push(new TWEEN.Tween(scPartVerts[i]))
}
Using D3 (just what I was familiar with for handling click events), I provide each tween with a new XY position to move to
d3.select("#key").on("click", function() {
for (i = 0; i < dataSetLen; i ++){
var newX = desiredXPostionList[i]; //grab the new X from presorted list
var newY = desiredYPositionList[i]; //grab the new Y from presorted list
tweenList[i].to( {
x: newX,
y: newY
}, 2500)
.start();
}
I then update the tweens while rendering,
function render() {
scene.children[0].geometry.verticesNeedUpdate = true;
TWEEN.update();
renderer.render( scene, camera );
}
The animation appears to run fine for ~75% of the tween and then it comes to a grinding, stuttering, 0 FPS, screeching halt for around 30 seconds once the vertices are close to their final positions. I tried to look at the animation timeline and it appears that all of that time is being dumped into updating the tweens.
Am I somehow supplying redundant tween updates using my d3.select method? (Does javascript register one click as 10 and try to update the tween 10x?) Or can tween.js not smoothly tween 200k positions simultaneously? Thank you so much for any help!
My approach from scratch is to use loops for vertices. The solution is not the ultimate truth, of course.
The plan: set duration and current time of animation,
var duration = 10; // seconds
var currentTime = 10;
var clock = new THREE.Clock();
remember the end position of a vertex, set a random start position for it, find the vector between those positions (direction),
fieldGeom = new THREE.PlaneGeometry(500, 500, 500, 500);
fieldGeom.vertices.forEach(function(vertex){
vertex.startPosition = new THREE.Vector3(THREE.Math.randInt(-500,500),THREE.Math.randInt(-500,500),THREE.Math.randInt(-500,500));
vertex.endPosition = vertex.clone();
vertex.direction = vertex.startPosition.clone().sub(vertex.endPosition);
vertex.copy(vertex.startPosition);
});
then in animation loop add the result vector, multiplied with proportion of currentTime / duration
var delta = clock.getDelta();
currentTime -= delta;
if (currentTime < 0) currentTime = 0;
fieldGeom.vertices.forEach(function(vertex){
vertex.addVectors(vertex.endPosition,vertex.direction.clone().multiplyScalar(currentTime / duration));
});
fieldGeom.verticesNeedUpdate = true;
jsfiddle example with 250K points.

In Babylon.js how can I get/set a FreeCamera's rotation or pan angle?

I am trying to capture a FreeCamera's location and pan angle or rotation so I can reposition the camera later with the exact same view.
(I am working with an altered version of the Collision example at http://www.babylonjs-playground.com/)
I seem to be able to get camera.position.x, camera.position.y and camera.position.z ok but camera.cameraRotation.y always yields zero.
According to
http://www.html5gamedevs.com/topic/11380-rotate-camera-around-z-axis/
with upVector:
camera.noRotationConstraint=true;
camera.upVector = new BABYLON.Vector3(1, 0.2, -1);
Playground example:
http://www.babylonjs-playground.com/#2FNBTG#1
The method I've come up with that seems to work reliably is to first collect the various camera stats:
var firstPosition=camera.position.x.toFixed(2)+"/"+camera.position.z.toFixed(2)+"/"+camera.rotation.x.toFixed(2)+"/"+camera.rotation.y.toFixed(2)+"/"+camera.rotation.z.toFixed(2);
which I store in a database. Then, when needed, I get the camera position by:
var firstArray=firstPositionL.split("/");
var firstX=Number(firstArray[0]);
var firstZ=Number(firstArray[1]);
var firstRx=Number(firstArray[2]);
var firstRy=Number(firstArray[3]);
var firstRz=Number(firstArray[4]);
Then when recreating the scene I add this just at the last of the scene creation. I put it into a delay function to give the scene time to establish itself:
var myVar = setInterval(function(){ myTimer() }, 1000);
function myTimer() {
camera.position.x=firstX;
camera.position.z=firstZ;
camera.rotation.x=firstRx;
camera.rotation.y=firstRy;
camera.rotation.z=firstRz;
clearInterval(myVar);
}

Move Camera to make all objects fit exactly inside the frustum - three.js

EDIT : I have rephrased my question to help users with the same problem.
I have a three.js scene on which I have added some spheres.
I want to move the camera towards a specific direction until all the objects (which are randomly positioned inside the scene) are "fitting exactly" the user's screen.
I have found the answer to my problem!
1. I move the camera (zooming to the desired direction) inside a loop, and in every repeat I create a new frustum using the camera's matrix
2. I check if any of my spheres intersects with a plane of the frustum. If it does, that means that part of one of my objects is outside the frustum so I break the loop and move the camera to its last position.
The above might also works for any object (not only spheres) because every object has a boundingSphere that can be calculated (it might not be very precise the result though).
It also works when zooming out, you 'd just have to move the camera from the object until none of the has a negative distance from all the planes (negative distance means object is "outside" the plane of the frustum).
Code (only for zooming out - r72) :
var finished = false;
var camLookingAt = /* calc. */ ;
while( finished === false ){
var toDirection= camera.position.clone().sub(camLookingAt.clone());
toDirection.setLength(vec.length() - 1); // reduce length for zooming out
camera.position.set(toDirection.x, toDirection.y, toDirection.z);
camera.updateMatrix(); // make sure camera's local matrix is updated
camera.updateMatrixWorld(); // make sure camera's world matrix is updated
var frustum = new THREE.Frustum();
frustum.setFromMatrix( new THREE.Matrix4().multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse ) );
for (var j = frustum.planes.length - 1; j >= 0; j--) {
var p = frustum.planes[j];
for (var i = myMeshSpheres.length - 1; i >= 0; i--) {
var sphere = new THREE.Sphere(myMeshSpheres[0].position.clone(), myMeshSpheres[0].radius);
if( p.distanceToSphere(sphere) < 1 ){ // if is negative means part of sphere is outside plane/frustum
finished = true;
}
}
}

Categories