Which FBX BlendShape parameters are used to control them with the DatGui?

Hello everybody

I’m try to give some life to an FBX character. I wil to connect the Blendshapes and the bones with the DatGui. Now I’m not sure which parameters have to be used. In the latest FBX loader, I see that are supported morphTargetInfluences . In my case that should actually work, but it does not. Is any one know what else is missing?

var params = {						  
    influence1: 0,
    influence2: 0,
		 
    bone1: 0,
    bone1: 0
};
	
var gui = new dat.GUI({    });  							                                                                                    																				
	
var folder = gui.addFolder( 'Morph Targets' );			
    folder.add( params, 'influence1', 0, 1 ).step( 0.01 ).name('Mouph_open').listen().onChange( function( value ) { object.morphTargetInfluences[ 81432448 ] = value});
    folder.add( params, 'influence2', 0, 1 ).step( 0.01 ).name('Eye_Close_R').listen().onChange( function( value ) { mesh.morphTargetInfluences[ 81773264 ] = value});			
    folder.open();
	
var folder = gui.addFolder( 'Bones' );
    folder.add( params, 'bone1', -1, 1 ).step( 0.01 ).name('Neck').listen().onChange( function( value ) { mesh.skeleton.bones[ 78891648 ].rotation.x = value;});
    folder.open();

Geometry

Deformer

For the morph targets, try this:

var params = {
	influence0: 0,
	influence1: 0,
}

var gui = new dat.GUI();
var folder = gui.addFolder( 'Morph Targets' );

folder.add( params, 'influence0', 0, 1 ).step( 0.01 ).onChange( function( value ) { mesh.morphTargetInfluences[ 0 ] = value; } );
folder.add( params, 'influence1', 0, 1 ).step( 0.01 ).onChange( function( value ) { mesh.morphTargetInfluences[ 1 ] = value; } );
			

Where are you getting these huge numbers like object.morphTargetInfluences[ 81432448 ] from? Take a look at the actual geometry created by the loader to see what the correct number for each target is.

Hi looeee, thanks for the answer, this number comes from the loader. The entries you see in the section above, come from the console. I do not have another number. I’m currently testing 5 different characters. Everyone shows me a similar list of these big numbers.

Console Output from two different BlendShapes.Shapes

I have the FBX transmitted to an ASCII to see other numbers maybe. It look like that. Do you have an example of how it looks at them at you?

Asci%20FBX

Log the actual geometry created like this:

var loader = new THREE.FBXLoader();

loader.load( 'yourModel.fbx', function ( object ) { 

    object.traverse( function ( child ) {

        if ( child.isMesh ) { console.log( child.geometry ) }

    }
}

Thank you, I can not integrate this function without error.

var loader = new THREE.FBXLoader(); 
    loader.load( "./three/models/Model/FBX/TestModel.fbx", function ( object ) {      

    object.scale.set( 0.25, 0.22, 0.35 );            
    object.position.set( 0.0, 0.0, 0.0 );	         
    object.rotation.set( 0.0, 1.57, 0.0 );           
    scene.add( object );

    object.traverse( function ( child )) {            
        if ( child.isMesh ) { console.log( child.geometry ) }
    }

});

var params = {
    influence0: 0,
    influence1: 0,			
}

var gui = new dat.GUI();
var folder = gui.addFolder( 'Morph Targets' );

    folder.add( params, 'influence0', 0, 1 ).step( 0.01 ).listen().onChange( function( value ) { mesh.morphTargetInfluences[ 0 ] = value; } );
    folder.add( params, 'influence1', 0, 1 ).step( 0.01 ).onChange( function( value ) { mesh.morphTargetInfluences[ 1 ] = value; } );
    folder.open();

What’s your error? And what’s the purpose of calling .listen() ?

Looeee, .listen was for a test. "Missing { in the top " written on the console.

"Missing { in the top "

I guess that means you are missing a “{” in your code somewhere.

Yes, that is so certain. but when I moving out your function, everything works.

You’ve added an extra )

object.traverse( function ( child ))

Hi Looeee, the ) was the first problem and } the second, so I tried that and that. I have found the error but meanwhile. For this I have rewritten everything in a highly reducted form. Now that runs. Your Code is correct, thank you !! :+1:

Now I see the following on the console:


folder.add( params, 'influence0', 0, 1 ).step( 0.01 ).onChange( function( value ) { mesh.morphTargetInfluences[ 1 ] = value; } );
folder.add( params, 'influence1', 0, 1 ).step( 0.01 ).onChange( function( value ) { object.morphTargetInfluences[ 1 ] = value; } );

Error

Shapes:

I’m testing, but unfortunately still get no movements over the DatGui. Are you sure that it has to be named mesh.morphTargetInfluences not child or object ?

Log the mesh as well and check that it has morphTargetInfluences

if ( child.isMesh ) { console.log( child) }

Remember that you need to call object.morphTargetInfluences[ 1 ] = value; on the correct object - that is, you need to call it on a mesh that has a geometry with morph targets defined. It seems likely that you are calling it on the wrong object here. Please copy and paste your entire code here, snippets are not much use when trying to track down bugs.

<!DOCTYPE html>
<html>
<head>
    <title>____________FBX_Loader_________</title>
	<meta charset="utf-8">
	<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">

	<style>
	body { margin: 0; }
	canvas { width: 100%; height: 100% }
	</style>

</head>

<body>

<script src="./three/build/three.min.js"></script>
<script src="./three/examples/js/libs/inflate.min.js"></script>
<script src="./three/examples/js/controls/OrbitControls.js"></script>		
<script src="./three/examples/js/loaders/FBXLoader2.js"></script>		
<script src="./three/examples/js/libs/dat.gui.min.js"></script>
	
<script>

var scene;
var camera;
var renderer;
var control;	

var scene = new THREE.Scene();

var camera = new THREE.PerspectiveCamera(1, window.innerWidth/window.innerHeight, 1, 10000);
    camera.position.x = 2670;		    
    camera.position.y = 050;			
    camera.position.z = 030;			
    camera.target = new THREE.Vector3( 0, 0, 0 );	

    renderer = new THREE.WebGLRenderer( { alpha: false } );
    renderer.setClearColor( 0x000000 );
    renderer.setPixelRatio( window.devicePixelRatio );
    renderer.setSize( window.innerWidth, window.innerHeight );
    document.body.appendChild( renderer.domElement );		

var controls = new THREE.OrbitControls( camera, renderer.domElement );    

var light = new THREE.AmbientLight( 0xffffff, 0.5 );
    light.position.set( 0.0, 0.0, 0.0 ).normalize();           
    scene.add( light );

var loader = new THREE.FBXLoader(); 
    loader.load( "./three/models/Model/FBX/TestModel.fbx", function ( object ) {                 

    object.scale.set( 0.25, 0.22, 0.35 );            
    object.position.set( 0.0, 0.0, 0.0 );	         
    object.rotation.set( 0.0, 1.57, 0.0 );           
    scene.add( object );

   object.traverse( function ( child ) {
        if ( child.isMesh ) { console.log( child.geometry ) }
	if ( child.isMesh ) { console.log( child ) } 
   }

)
});

var params = {
     influence0: 0.0,
     influence1: 0.0,         
}

 var gui = new dat.GUI();
 var folder = gui.addFolder( 'Morph Targets' );

     folder.add( params, 'influence0', 0, 1 ).step( 0.01 ).onChange( function( value ) { object.morphTargetInfluences[ 1 ] = value; } );
     folder.add( params, 'influence1', 0, 1 ).step( 0.01 ).onChange( function( value ) { object.morphTargetInfluences[ 2 ] = value; } );
     folder.open();     


function animate() {
	render();
	requestAnimationFrame( animate );		
	}

function render() {
	renderer.clear();        
	renderer.render( scene, camera );		
	}	

animate();

</script>
</body>
</html>

Dictionarry

On console :weary:
object%20undefined

OK, so you need to do some studying on how scope works in JavaScript. In this line:

object.morphTargetInfluences[ 1 ] = value; }

object is undefined, because it is only available in the scope of the loader.load method.

But the object returned by the loader is currently a group - you need to search through this group and find the mesh with the morph targets, and then set up the GUI to control the morph target influences on that.

Without seeing how the hierarchy of your particular model is set up, I can’t say for sure, but something similar to this should work:


var scene;
var camera;
var renderer;
var control;
var mesh; // use this to get a reference to to the mesh outside the scope of loader.load

var scene = new THREE.Scene();

var camera = new THREE.PerspectiveCamera(1, window.innerWidth/window.innerHeight, 1, 10000);
    camera.position.x = 2670;		    
    camera.position.y = 050;			
    camera.position.z = 030;			
    camera.target = new THREE.Vector3( 0, 0, 0 );	

    renderer = new THREE.WebGLRenderer( { alpha: false } );
    renderer.setClearColor( 0x000000 );
    renderer.setPixelRatio( window.devicePixelRatio );
    renderer.setSize( window.innerWidth, window.innerHeight );
    document.body.appendChild( renderer.domElement );		

var controls = new THREE.OrbitControls( camera, renderer.domElement );    

var light = new THREE.AmbientLight( 0xffffff, 0.5 );
    light.position.set( 0.0, 0.0, 0.0 ).normalize();           
    scene.add( light );

var loader = new THREE.FBXLoader(); 
loader.load( "./three/models/Model/FBX/TestModel.fbx", function ( object ) {                 

    object.scale.set( 0.25, 0.22, 0.35 );            
    object.position.set( 0.0, 0.0, 0.0 );	         
    object.rotation.set( 0.0, 1.57, 0.0 );           
    scene.add( object );

    mesh = object.children[ 0 ]; // this is a guess, you may have to change this

});

var params = {
     influence0: 0.0,
     influence1: 0.0,         
}

 var gui = new dat.GUI();
 var folder = gui.addFolder( 'Morph Targets' );

// influences are on the mesh 
folder.add( params, 'influence0', 0, 1 ).step( 0.01 ).onChange( function( value ) { mesh.morphTargetInfluences[ 1 ] = value; } ); 
folder.add( params, 'influence1', 0, 1 ).step( 0.01 ).onChange( function( value ) { mesh.morphTargetInfluences[ 2 ] = value; } );
folder.open();     


function animate() {
	render();
	requestAnimationFrame( animate );		
	}

function render() {
	    
	renderer.render( scene, camera );		
}	

animate();

I’ve also removed renderer.clear(); since you shouldn’t need it.

Exactly this mesh = object.children [0]; was missing. I had already played with the variable mesh before. Looeee, thank you for your help. :ok_hand::+1:

1 Like

Hello, I have to ask again, because of the control of the morphTargetInfluences over the DatGui. Of 5 models, I have only one model in which everything moves (Bones and MorphTargets). The other 4 move not, only the bones although they are almost identical in construction. The bones move correctly on all models. The morphTargets only move be one model.

There is no error message.

The bones move, if either
mesh = object.children[ 0 ];
or
mesh = object.children[ 1 ];

Actually, the morphTargets should move then, but they do not. Interestingly, the slides on the DatGui can be moved, but nothing happens to the model. Does anyone know what could be the reason ?

I also have no success with this:

if ( child instanceof THREE.Object ) {	  //or THREE.Mesh
     child.material.morphtargets = true;
     child.morphTargetInfluences[0] = 1;  //or [1] = 0
     child.updateMorphTargets();
}