get back to normal after the traverse in threejs - three.js

in threejs am working around with the traverse method to apply the WireframeHelper for the models that is loaded using OBJMTLLoder, for this kind of models we must use traverse to apply the Wireframe for child of the Object, so here i can apply the wireframes and so on using traverse but after the traverse i can't get back to my normal object meaning that i can't remove the wireframes with the traversed mesh, the mesh is added with the scene with scene.add( wfh ); where wfh is WireframeHelper , but if i use scene.remove( wfh ); to remove the meshed WireframeHelper it doesn't work
i need to know that after the traverse we can get back to normal ?? in most cases am using traverse to make changes on my model:
Here is the code:
scene.traverse ( function (child)
{
if (child instanceof THREE.Mesh)
{
wfh = new THREE.WireframeHelper( child, 0xffffff );
scene.add( wfh );
}
});
updated code:
globalObject.traverse ( function (child) {
if (child instanceof THREE.Mesh)
{
wfh = new THREE.WireframeHelper( child,whfcolor );
wfh.name = "wireframe_helper";
wfh.material.opacity = 0.2;
wfh.material.transparent = true;
globalObject.add( wfh );
}
});
here globalObject is global variable assigned to Object now i can see the wireframe_helper on the child of the Object and can remove the wireframe by following code
globalObject.traverse( function ( child ) {
if (child instanceof THREE.Object3D)
{
//alert(child.name);
if ( child.name && child.name === "wireframe_helper" && child.material ) {
//alert('hi');male-02-1noCullingID_male-02-1noCulling.JP
globalObject.remove( child );
//child.material.wireframe = true;
}
}
});
after removed the wireframe still wireframe is remains some part of the Object any clue on this ?? and am getting
TypeError: this.children[i] is undefined
this.children[ i ].traverse( callback );
on line three.js 7885

WireframeHelper() creates an object that is added to the scene-graph. When you are using the helper inside a traverse() operation you are adding many objects to the scene. So if you want to remove them, you have to save them off to a variable (array in this case since you have many of them). So something like this should work:
First name the helper inside the first traverse():
wfh = new ...
wfh.name = "wireframe_helper";
scene.add( wfh );
then you should be able to do:
scene.traverse ( function (child)
{
if (child.name === "wireframe_helper")
{
scene.remove( child );
}
}
The code above would probably crash when trying to traverse a child that has been removed.
Here is updated code:
to_remove = [];
scene.traverse ( function (child)
{
if (child.name === "wireframe_helper")
to_remove.push( child );
}
for (var i = 0; i < to_remove.length(); i++)
scene.remove( to_remove[i] );

Related

How to clone a Skinned Mesh?

I need to have multiple identical, animated models on a scene. If possible, I would like them to have a shared geometry and material, but if it is impossible, having them instanced per model will suffice too.
Unfortunately, the only way to achieve this result I found is to go through JSONLoader for every model instance.
SkinnedMesh does have a clone() method, but it seems not to be fully implemented yet. If used and both original and cloned mesh are present on the scene, only one will appear, and cloned one will be without animation.
I have attempted to use this example with shared skeletons:
https://github.com/mrdoob/three.js/pull/11666
...and indeed it works, but I need to be able to play different animations for every model instance, having them all play the same one is not sufficient, sadly. I hoped I could do similar hax and insert my own skeleton (made out of bones from the JSON file), but it behaves very much like if I just used clone() from SkinnedMesh.
I am using this code:
https://github.com/arturitu/threejs-animation-workflow/blob/master/js/main.js
Basically what I'd like to achieve is
var onLoad = function (geometry, materials) {
window.geometry = geometry;
character = new THREE.SkinnedMesh(
geometry,
new THREE.MeshFaceMaterial(materials)
);
character2 = character.someMagicalClone();
scene.add(character);
scene.add(character2);
(...)
I need any clue... and while I wait for help, I am busily deconstructing constructor for SkinnedMesh and JSONLoader for clues ;)
Thanks in advance!
I found a solution in this pull request:
https://github.com/mrdoob/three.js/pull/14494
in short, there are two functions added:
function cloneAnimated( source ) {
var cloneLookup = new Map();
var clone = source.clone();
parallelTraverse( source, clone, function ( sourceNode, clonedNode ) {
cloneLookup.set( sourceNode, clonedNode );
} );
source.traverse( function ( sourceMesh ) {
if ( ! sourceMesh.isSkinnedMesh ) return;
var sourceBones = sourceMesh.skeleton.bones;
var clonedMesh = cloneLookup.get( sourceMesh );
clonedMesh.skeleton = sourceMesh.skeleton.clone();
clonedMesh.skeleton.bones = sourceBones.map( function ( sourceBone ) {
if ( ! cloneLookup.has( sourceBone ) ) {
throw new Error( 'THREE.AnimationUtils: Required bones are not descendants of the given object.' );
}
return cloneLookup.get( sourceBone );
} );
clonedMesh.bind( clonedMesh.skeleton, sourceMesh.bindMatrix );
} );
return clone;
}
function parallelTraverse( a, b, callback ) {
callback( a, b );
for ( var i = 0; i < a.children.length; i ++ ) {
parallelTraverse( a.children[ i ], b.children[ i ], callback );
}
}
As I understand it rebinds cloned skeleton to the cloned mesh.
so topic example could look like:
var onLoad = function (geometry, materials) {
window.geometry = geometry;
character = new THREE.SkinnedMesh(
geometry,
new THREE.MeshFaceMaterial(materials)
);
character2 = cloneAnimated(character); // <-- used that new function
scene.add(character);
scene.add(character2);
(...)

Define prototype.updatePosition so that when an Object is clicked it animates/rotates/scales to certain value

Having problem understanding the class system in Three.js
I have a code in player.js :
function Player() {
var mesh = new THREE.Object3D();
this.player = null;
this.loader = new THREE.JSONLoader();
this.name = 'player';
this.loader.load(
'obj/models/minecraft_sole.json',
function ( geometry, materials ) {
var material = new THREE.MultiMaterial( materials );
this.player = new THREE.Mesh( geometry, material );
this.player.position.set(0, 0, 0);
this.player.scale.set(.5,.5,.5);
this.player.castShadow = true;
this.player.receiveShadow = false;
mesh.add( this.player );
}
);
Player.prototype.constructor = Player;
Player.prototype = Object.create(THREE.Object3D.prototype);
}
Player.prototype.updatePosition = function(){
this.mesh.position.y += 0.05;
}
And basically what I'm trying to achieve:
In main.js after all standard setup for init()/render()/animate() and all...
I create variable called johny:
var johny = new Player();
Now everything loads great and all, but in player.js i want to be able to define some prototype ? method, and in that method I want to listen for a click event. After that event is called I want my player mesh to animate to certain position or start rotating/scaling.
My pseudo code for better understanding is:
var Player = function(){
// define mesh and all
}
player.add.eventListener( 'click' ){
//code to animate player
}
Remember that all this; I want to be a part of player.js so that after calling:
var johny = new Player();
I don't have to add event listening functions to the main.js and all that.
And second of all I want my code to be modular, as You may already noticed :)
So I did managed to understand it.

Object color apply does not work?

I have loaded object in three js. When i apply the color it does not work.
I have below code used i got error in,
child.material.color is undefined
I have used below code
var geometry = new THREE.PlaneGeometry( 0.8, 1 );
var loader = new THREE.OBJLoader( manager );
loader.load( file, function ( object ) {
object.traverse( function ( child ) {
if ( child instanceof THREE.Mesh ) {
child.material.ambient.setHex(0xFF0000);
child.material.color.setHex(0x00FF00);
}
} );
I think child.material.color.setHex() is enough to apply/set the color of an object.
So try to remove the following line from your code.
child.material.ambient.setHex(0xFF0000);
Here is the working fiddle sample: http://jsfiddle.net/ev3tuLuc/109/

Three.js make the text created with THREE.ShapeGeometry face the camera

I created a shapegeometry with the text. How can I keep the text face the camera on move the camera?
...
this.textGeometry = new THREE.ShapeGeometry(THREE.FontUtils.generateShapes(value, parameters));
this.textValue = new THREE.Mesh(this.textGeometry, new THREE.MeshBasicMaterial({ color: color, side: THREE.DoubleSide }));
this.textValue.matrixAutoUpdate = true;
this.add(this.textValue)
...
I think my problem is that I modified the parent quaternion 3D object:
this.quaternion.setFromAxisAngle (axis, radians);
then the only operation:
textValue.quaternion.copy (camera.quaternion);
is not sufficient
how can I fix the rotation considering the state of the quaternion?
If you don't care about calling the base updateMatrix function,
this can be a solution
yourShapeGeometry.prototype.updateMatrix = function(){
// THREE.Object3D.prototype.updateMatrix.call(this);
fixOrientation(this.textValue);
}
function fixOrientation(mesh){
mesh.setRotationFromQuaternion(camera.quaternion);
mesh.updateMatrix();
}
or simply edit the updateMatrix of your text mesh like
textMesh.updateMatrixWorld = updateSpriteWorld;
function updateSpriteWorld(){
if ( this.matrixWorldNeedsUpdate === true || force === true ) {
this.setRotationFromQuaternion(camera.quaternion);
this.updateMatrix();
this.matrixWorld.copy( this.matrix );
this.matrixWorldNeedsUpdate = false;
force = true;
}
// update children
for ( var i = 0, l = this.children.length; i < l; i ++ ) {
this.children[ i ].updateSpriteWorld( force );
}
}
I think this should do the trick:
this.textValue.lookAt( camera.position );

visibility of LOD DAE object in Three JS

i'm trying to use the THREE.LOD object in my ThreeJS scene. i've been inspired by http://threejs.org/examples/webgl_lod.html
But I wanted to push the idea further and use DAE model (using this loader : http://threejs.org/examples/webgl_loader_collada.html)
Problem is i can't switch the visibility of the lod level. First, i tried an automated one in my Render function (based on distance to camera, found in the example):
this.m_Scene.traverse( function ( object ) {
if ( object instanceof THREE.LOD ) {
object.update( that.m_Camera );
}
} );
As it wasn't working (All my lod were displayed at the same time). I try something more manual. and it appears the Object3D.visibility attribute isn't really used by the renderer, or not inherited by children.
As far as I understand, this attribute is for meshes. But i'm not sure it's checked at render time.
So this doesn't work as expected:
var LodTemporaryObject = new THREE.LOD();
function LoadLod1()
{
//TEST COLLADA LOADER
var loader = new THREE.ColladaLoader();
loader.options.convertUpAxis = true;
loader.load(Lod2Path, function ( collada ) {
dae = collada.scene;
dae.scale.x = dae.scale.y = dae.scale.z = 0.1;
dae.updateMatrix();
dae.visible = false; //THIS HAS NO EFFECT
LodTemporaryObject.addLevel(dae,100);
AddLodToScene(LodTemporaryObject ); //where the lod is added to the threeJS scene object
} );
}
so question : how do I actually set (in)visible any Object3D or subScene ?
EDIT: The answer below is outdated. Visibility is now inherited. See, for example, Show children of invisible parents.
three.js r.71
Visibility is not inherited by children with WebGLRenderer.
The work-around is to use a pattern like so:
object.traverse( function( child ) {
if ( child instanceof THREE.Mesh ) {
child.visible = false;
}
}
three.js r.64
Thx to WestLangley answer above, i came up with an recursive solution to my problem:
first, a recursive function to update visibility of children to match the parent's:
function SetChildrenVisible(parent)
{
if(parent instanceof THREE.Object3D)
{
for(var i = 0; i< parent.children.length; i ++)
{
parent.children[i].visible = parent.visible;
SetChildrenVisible(parent.children[i]);
}
}
}
then in my render loop:
this.m_Scene.traverse( function ( object ) {
if ( object instanceof THREE.LOD ) {
//save all lodLevel state before updating
var oldVisible =[]; object.visible;
for(var i = 0; i< object.children.length; i++)
{
oldVisible.push(object.children[i].visible)
}
//Update Lod
object.update( that.m_Camera );
//Check for changes and update accordingly
for(var i = 0; i< object.children.length; i++)
{
if(oldVisible[i] != object.children[i].visible )
{
SetChildrenVisible(object.children[i]);
}
}
}
} );
Goal is to only update object whose attribute changed.

Resources