提交 cea5e0c9 编写于 作者: T Takahiro

Support glTF 2.0 morph animation

上级 882ee9d3
......@@ -821,7 +821,8 @@ THREE.GLTF2Loader = ( function () {
var PATH_PROPERTIES = {
scale: 'scale',
translation: 'position',
rotation: 'quaternion'
rotation: 'quaternion',
weights: 'morphTargetInfluences'
};
var INTERPOLATION = {
......@@ -2111,6 +2112,94 @@ THREE.GLTF2Loader = ( function () {
meshNode = new THREE.Mesh( geometry, material );
meshNode.castShadow = true;
if ( primitive.targets !== undefined ) {
geometry.morphTargets = [];
var targets = primitive.targets;
var morphAttributes = geometry.morphAttributes;
for ( var i = 0, il = targets.length; i < il; i ++ ) {
var target = targets[ i ];
geometry.morphTargets.push( { name: 'morphTarget' + i } );
if ( target.POSITION !== undefined ) {
material.morphTargets = true;
if ( morphAttributes.position === undefined ) morphAttributes.position = [];
// Three.js morph formula is
// position
// + weight0 * ( morphTarget0 - position )
// + weight1 * ( morphTarget1 - position )
// ...
// while the glTF one is
// position
// + weight0 * morphTarget0
// + weight1 * morphTarget1
// ...
// then adding position to morphTarget.
// motphTarget should depend on mesh, so cloning attribute.
var attribute = dependencies.accessors[ target.POSITION ].clone();
var position = geometry.attributes.position;
for ( var j = 0, jl = attribute.array.length; j < jl; j ++ ) {
attribute.array[ j ] += position.array[ j ];
}
morphAttributes.position.push( attribute );
}
if ( target.NORMAL !== undefined ) {
material.morphNormals = true;
if ( morphAttributes.normal === undefined ) morphAttributes.normal = [];
// see target.POSITION's comment
var attribute = dependencies.accessors[ target.NORMAL ].clone();
var normal = geometry.attributes.normal;
for ( var j = 0, jl = attribute.array.length; j < jl; j ++ ) {
attribute.array[ j ] += normal.array[ j ];
}
morphAttributes.normal.push( attribute );
}
// TODO: implement
if ( target.TANGENT !== undefined ) {
console.log( dependencies.accessors[ target.NORMAL ] );
}
}
meshNode.updateMorphTargets();
if ( mesh.weights !== undefined ) {
for ( var i = 0, il = mesh.weights.length; i < il; i ++ ) {
meshNode.morphTargetInfluences[ i ] = mesh.weights[ i ];
}
}
}
} else if ( primitive.mode === WEBGL_CONSTANTS.LINES ) {
geometry = new THREE.BufferGeometry();
......@@ -2273,6 +2362,7 @@ THREE.GLTF2Loader = ( function () {
var target = channel.target;
var name = target.node || target.id; // NOTE: target.id is deprecated.
var input = animation.parameters !== undefined ? animation.parameters[ sampler.input ] : sampler.input;
var output = animation.parameters !== undefined ? animation.parameters[ sampler.output ] : sampler.output;
......@@ -2286,22 +2376,70 @@ THREE.GLTF2Loader = ( function () {
node.updateMatrix();
node.matrixAutoUpdate = true;
var TypedKeyframeTrack = PATH_PROPERTIES[ target.path ] === PATH_PROPERTIES.rotation
? THREE.QuaternionKeyframeTrack
: THREE.VectorKeyframeTrack;
var TypedKeyframeTrack;
switch ( PATH_PROPERTIES[ target.path ] ) {
case PATH_PROPERTIES.weights:
TypedKeyframeTrack = THREE.NumberKeyframeTrack;
break;
case PATH_PROPERTIES.rotation:
TypedKeyframeTrack = THREE.QuaternionKeyframeTrack;
break;
case PATH_PROPERTIES.position:
case PATH_PROPERTIES.scale:
default:
TypedKeyframeTrack = THREE.VectorKeyframeTrack;
break;
}
var targetName = node.name ? node.name : node.uuid;
var interpolation = sampler.interpolation !== undefined ? INTERPOLATION[ sampler.interpolation ] : THREE.InterpolateLinear;
var targetNames = [];
if ( PATH_PROPERTIES[ target.path ] === PATH_PROPERTIES.weights ) {
// node should be THREE.Group here but
// PATH_PROPERTIES.weights(morphTargetInfluences) should be
// the property of a mesh object under node.
// So finding targets here.
node.traverse( function ( object ) {
if ( object.isMesh === true && object.material.morphTargets === true ) {
targetNames.push( object.name ? object.name : object.uuid );
}
} );
} else {
targetNames.push( targetName );
}
// KeyframeTrack.optimize() will modify given 'times' and 'values'
// buffers before creating a truncated copy to keep. Because buffers may
// be reused by other tracks, make copies here.
tracks.push( new TypedKeyframeTrack(
targetName + '.' + PATH_PROPERTIES[ target.path ],
THREE.AnimationUtils.arraySlice( inputAccessor.array, 0 ),
THREE.AnimationUtils.arraySlice( outputAccessor.array, 0 ),
interpolation
) );
for ( var i = 0, il = targetNames.length; i < il; i ++ ) {
tracks.push( new TypedKeyframeTrack(
targetNames[ i ] + '.' + PATH_PROPERTIES[ target.path ],
THREE.AnimationUtils.arraySlice( inputAccessor.array, 0 ),
THREE.AnimationUtils.arraySlice( outputAccessor.array, 0 ),
interpolation
) );
}
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册