Is it possible to create a dynamic animation by applying transformations to the bones of a 3D model using three.js? I tried moving and rotating the bones of a SkinnedMesh, but the mesh was not updated.
loader = new THREE.JSONLoader();
loader.load('/JS-Projects/Virtual-Jonah/Modelos/initialPose.js',function jsonReady( geometry )
{
mesh = new THREE.SkinnedMesh( geometry, new THREE.MeshNormalMaterial({skinning : true}) );
mesh.scale.set( 10, 10, 10 );
mesh.position.z = mesh.position.y = mesh.position.x = 0;
mesh.geometry.dynamic = true;
scene.add( mesh );
var index = 0;
for (var i = 0; i < mesh.bones.length; i++)
{
if (mesh.bones[i].name == "forearm_R")
{
index = i;
break;
}
}
setInterval (function ()
{
mesh.bones[index].useQuaternion = false;
mesh.bones[index].position.z += 10;
mesh.bones[index].matrixAutoUpdate = true;
mesh.bones[index].matrixWorldNeedsUpdate = true;
mesh.geometry.verticesNeedUpdate = true;
mesh.geometry.normalsNeedUpdate = true;
renderer.render(scene, camera);
}, 33);
renderer.render(scene, camera);
});
The model I am using was created with makeHuman (nightly build), exported to Collada, imported in Blender and exported to the three.js JSON model. The link to the model is the following:
https://www.dropbox.com/sh/x1606vnaoghes1y/gG_BcZcEKd/initial
Thank you!
Yes, you can!
You need to set mesh.skeleton.bones[i], both mesh.skeleton.bones[i].rotation and mesh.skeleton.bones[i].position. Rotation is of type Euler. Position is of type Vector3. I have actually tested this using my code from here https://github.com/lucasdealmeidasm/three-mm3d (that includes a working skinned mesh with bone-attachable objects) and one can indeed do that.
Note that Inateno's answer is very wrong, there are many instances where this is necessary.
For example, in a FPS, one uses both dynamic and non-dynamic animation.
When a character runs and holds a gun, the direction he points the gun at is dynamically set (one could use mesh.skeleton.bones[i].rotation where "i" is the index for bone assigned to the arm for that) while the rest of the animation, including the walking, is made in the editor and loaded. One can, in three.js, use "THREE.AnimationHandler.update(delta);" and then change single bones' position and rotation in code to solve those issues.
I know you can export a bone driven animation from Blender in JSON format, for use in THREE.js, there are a few tutorials of that around the web. I hope this helps. Good Luck.
If I understund you want to create animations yourself inside the code ?
You are note supposed to do this, in Unity you have a simple animation editor, you never manipulate bones directly in code.
It's long, boring, unperforming. To animate a model use animation directly.
Here's a result of animation with some bones manipulation but there is an animation over.
http://threejs.org/examples/webgl_animation_skinning_morph.html
Here is a tutorial about making simple animation if you need http://blog.romanliutikov.com/post/60461559240/rigging-and-skeletal-animation-in-three-js
And here a related post about animations problems just in case
Blender exports a three.js animation - bones rotate strangely
Hope this will help you :)
Related
I'm trying to make an environement to train a neural network.
At first I just made a 3d canvas and rendered that which worked fine (#canvas in the code), then I converted that to an image.
Later I found out that I needed to convert the canvas to 2d to be able to get the image data I need to input into the AI (according to the advice I got here.
I also discovered a bug which made me call animate() twice.
The weird thing is that if I now try to remove either the image-rendering or the extra call to animate(), the 2d canvas wont render when the camera is moved in Chrome, while it renders irregularly in IE. Any idea how I can fix this?
I have cut down the code to the essentials in this
fiddle, the animation loop is below:
function animate(){
requestAnimationFrame( animate );
movement();
hudUpdate();
//fps-calculation
newTime = Date.now();
sumTime += (newTime - oldTime);
if(framesElapsed === 60){
document.getElementById("fps").innerHTML=
(Math.floor(600000/sumTime))/10;
framesElapsed = 0;
sumTime = 0;
} else {
framesElapsed+=1;
}
oldTime = newTime;
//Converts the canvas to an image and then draws it on a 2d surface.
// CHECKT THIS! Has to be run before renderer.renderer, but will be blank
if movvement occurs and the segment below is left out.
var image = convertCanvasToImage(drawingSurface);
var AIInputImage = convertImageToCanvas(image);
renderer.render(scene, camera);
// CHECK THIS! the above conversion stops working while moving unless the
the line below is present, no idea why..
$("#interim-img").attr("src",drawingSurface.toDataURL("image/png"));
};
animate();
animate();
Edit: updated fiddlelink.
I am creating a Geometry in three.js and populating it with vertices to build a 2D terrain. I am pushing all of the Vector3s and Face3s to the geometry as soon as my terrain is created, and then modifying each vertex and face every frame.
Because I am modifying the face vertices every frame, I need to tell three.js to update the faces. I am doing this using geometry.elementsNeedUpdate = true. This works, however I have noticed it causes a substantially large amount of memory usage (my app uses an extra ~50mb of RAM every second).
The following code demonstrates what I'm trying to do:
function pushEverything(geom) {
for (var i = 0; i < 10000; i++) {
geom.vertices.push(new THREE.Vector3(...));
geom.faces.push(new THREE.Face3(...));
geom.faces.push(new THREE.Face3(...));
}
}
function rebuild(geom) {
for (var face of geom.faces) {
face.a = ...
face.b = ...
face.c = ...
}
geom.elementsNeedUpdate = true
}
var renderer = new THREE.WebGLRenderer({
canvas: document.getElementById("my-canvas")
});
var geom = new THREE.Geometry();
var camera = new THREE.PerspectiveCamera(...);
pushEverything(geom);
while (true) {
// Perform some terrain modifications
rebuild(geom);
renderer.render(geom, camera);
sleep(1000 / 30);
}
I have already followed the advice of this question, which suggested using geometry.vertices[x].copy(...) instead of geometry.vertices[x] = new Vector3(...).
My question is: why is my memory usage so high when using geometry.elementsNeedUpdate = true? Is there an alternative method to updating a Geometry's faces?
I am using three.js 0.87.1 from NPM.
I have found and solved the issue. It was not a memory leak on three.js' part, but it was a memory leak on my part.
I was creating a Geometry and allowing myself to clone it, perform modifications to the clone, and then merge it back into the original. What I didn't realise is that I should call geometry.dispose() on the cloned geometry when I was done with it. So, I was basically cloning the geometry every frame, which explains the huge memory usage.
I have fixed my issue by converting the Geometry to a BufferGeometry, and calling geometry.dispose() on the geometry when I am done with it. I now have expected memory usage.
I have a three.js project where I'm adding in 100 meshes, that are divided into 10 scenes:
//add 100 meshes to 10 scenes based on an array containing 100 elements
for (var i = 0; i < data.length; i++) {
mesh = new THREE.Mesh(geometry, material);
//random positions so they don't spawn on same spot
mesh.position.x = THREE.Math.randInt(-500, 500);
mesh.position.z = THREE.Math.randInt(-500, 500);
They're added in by a loop, and all these meshes are assigned to 10 scenes:
// Assign 10 meshes per scene.
var sceneIndex = Math.floor(i/10);
scenes[sceneIndex].add(mesh);
I also wrote a functionality where I can rotate a mesh around the center of the scene.
But I don't know how to apply the rotation functionality to all meshes while still keeping them divided into their corresponding scenes. This probably sounds way too vague so I have a fiddle that holds all of the relevant code.
If you comment these two lines back in you'll see that the meshes all move to scenes[0], and they all rotate fine the way I wanted, but I still need them divided in their individual scenes.
spinningRig.add(mesh);
scenes[0].add(spinningRig);
How is the code supposed to look like? Waht is the logic to it?
The logic is fairly simple. The simplest format would be to have a separate spinningRig for each scene -- essentially a grouping of the meshes for each scene.
When you create each scene, you'll also create a spinningRig and add + assign it to that scene:
// Setup 10 scenes
for(var i=0;i<10;i++) {
scenes.push(new THREE.Scene());
// Add the spinningRig to the scene
var spinningRig = new THREE.Object3D();
scenes[i].add(spinningRig);
// Track the spinningRig on the scene, for convenience.
scenes[i].userData.spinningRig = spinningRig;
}
Then instead of adding the meshes directly to the scene, add them to the spinningRig for the scene:
var sceneIndex = Math.floor(i/10);
scenes[sceneIndex].userData.spinningRig.add(mesh);
And finally, rotate the spinningRig assigned to the currentScene:
currentScene.userData.spinningRig.rotation.y -= 0.025;
See jsFiddle: https://jsfiddle.net/712777ee/4/
I am currently working on a small project using the new Babylon.js framework. One of the issues I have run into is that I basically have two meshes. One of the meshes is supposed to be the background, and the other is supposed to follow the cursor to mark where on the other mesh you are targeting. The problem is that when I move the targeting mesh to the position of the cursor, it blocks the background mesh when I use scene.pick, resulting in the other mesh having its position set on its self.
Is there any way to ignore the targeting mesh when using scene.pick so that I only pick the background mesh or is there some other method I could use? If not, what would be the steps to implement this sort of feature to essentially raycast only through certain meshes?
If you need code samples or any other forms of description, let me know. Thanks!
Ok, it's easy.
So, we have two meshes. One is called "ground", the second "cursor". If you want to pick only on the ground you have two solutions :
First:
var ground = new BABYLON.Mesh("ground",scene);
ground.isPickable = true ;
var cursor = new BABYLON.Mesh("cursor", scene);
cursor.isPickable = false;
...
var p = scene.pick(event.clientX, event.clientY); // it return only "isPickable" meshes
...
Second:
var ground = new BABYLON.Mesh("ground",scene);
var cursor = new BABYLON.Mesh("cursor", scene);
...
var p = scene.pick(event.clientX, event.clientY, function(mesh) {
return mesh.name == "ground"; // so only ground will be pickable
});
...
regards.
In Three.js, I want a camera to be pointed at a point in 3D space.
For this purpose, I tried using the camera.lookAt function like so:
camera.lookAt(new THREE.Vector3(-100,-100,0));
However, I found out that the call has no effect whatsoever. It just does nothing at all. I tried changing the numbers in the vector, and I always get the same look on screen, when it should be changing.
I just found now that if I remove the THREE.TrackballControls I have in my code, the camera.lookAt() works as it should. Is there something wrong with how I use THREE.TrackballControls? This is how I initialize them:
controls = new THREE.TrackballControls( camera, renderer.domElement );
controls.rotateSpeed = 10.0;
controls.zoomSpeed = 1.2;
controls.panSpeed = 0.2;
controls.noZoom = false;
controls.noPan = false;
controls.staticMoving = true;
controls.dynamicDampingFactor = 1.0;
var radius = 5;
controls.minDistance = radius * 1.1;
controls.maxDistance = radius * 100;
controls.keys = [ 65, 83, 68 ]; // [ rotateKey, zoomKey, panKey ]*/
And then in my render function I do:
function render() {
controls.update();
renderer.render(scene, camera);
}
Documentation on Three.js is pretty scarce, so I thought I'd ask here. Am I doing something wrong?
Looking at the source code of THREE.TrackballControls, I figured out that I can make the camera look where I want by setting trackballControls.target to the THREE.Vector3 I want it to look at, and then rerendering the scene.
Yes Please beware... It seems that having THREE.TrackballControls or THREE.OrbitControls seems to override the camera.lookAt function as your are passing in your camera when you instantiate an instance of the controls. You might want to get rid of the controls and then performing camera.lookAt() or tween your camera some other way to verify that the controls are having a overriding effect on your Camera. I googled for a while why camera.lookat() seemed to have no effect.
In my opinion, we are not supposed to mess with the original code. I found a way around to achieve the objective of looking at any particular point.
After having declared your "control" variable, simply execute these two lines of code:
// Assuming you know how to set the camera and myCanvas variables
control = new THREE.OrbitControls(camera, myCanvas);
// Later in your code
control.object.position.set(camX, camY, camZ);
control.target = new THREE.Vector3(targetX, targetY, targetZ);
Keep in my mind that this will switch the center of the focus to your new target. In other words, your new target will be the center of all rotations of the camera. Some parts will be difficult to look at as you became familiar to manipulate the camera assuming the default center. Try zoom in as much as you can and you will have a sense of what I am saying
Hope this help.
I figured it out. To prevent THREE.TrackballControls or THREE.OrbitControls from overriding camera.lookAt upon initialization, you need to change the line that sets the control's target property to equal the sum of the camera.position vector and the camera.getWorldDirection() vector, instead of how it's currently implemented using a new THREE.Vector3() (which defaults to (0, 0, 0)).
So, for THREE.TrackballControls, change line 39 to:
this.target = new THREE.Vector3().addVectors(/*new line for readability*/
object.position, object.getWorldDirection());
Same goes for THREE.OrbitControls, on line 36.
I actaully haven't tested it on TrackballControls.js but it does work on OrbitControls.js. Hope this helps.
Here's an alternative solution: create an object (i.e. cube) with 0 dimensions.
var cameraTarget = new THREE.Mesh( new THREE.CubeGeometry(0,0,0));
In the render function set the camera.lookAt to the position of the cameraTarget.
function render() {
camera.lookAt( cameraTarget.position );
renderer.render( scene, camera );
}
Then just move cameraTarget around as you wish.
I ran into the same problem and was able to make it work by using OrbitControls.target. Below is what I did after declaring a controller.
controller = new THREE.OrbitControls(camera, renderer.domElement);
controller.addEventListener('change', renderer.domElement);
controller.target = new THREE.Vector3(0, 1, 0);