如何克隆蒙皮网格?

时间:2017-07-29 20:30:39

标签: animation three.js

我需要在场景中拥有多个相同的动画模型。如果可能的话,我希望他们有一个共享的几何和材料,但如果不可能,那么每个模型实例化它们就足够了。

不幸的是,我发现实现此结果的唯一方法是为每个模型实例通过JSONLoader。

SkinnedMesh确实有一个clone()方法,但似乎还没有完全实现。如果使用并且场景中存在原始网格和克隆网格,则只会出现一个,克隆一个将没有动画。

我试图将此示例用于共享骨架: https://github.com/mrdoob/three.js/pull/11666

......确实它有效,但我需要能够为每个模型实例播放不同的动画,让它们都玩相同的动画是不够的,遗憾的是。我希望我可以做类似的hax并插入我自己的骨架(由JSON文件中的骨骼制成),但它的表现非常类似于我只使用了SkinnedMesh中的clone()。

我正在使用此代码: https://github.com/arturitu/threejs-animation-workflow/blob/master/js/main.js

基本上我想要实现的是

 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);

(...)

我需要任何线索......当我等待帮助时,我忙着为SkinnedMesh和JSONLoader解构构造函数以获取线索;)

提前致谢!

1 个答案:

答案 0 :(得分:0)

我在此拉取请求中找到了解决方案: https://github.com/mrdoob/three.js/pull/14494

简而言之,添加了两个功能:

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 );

    }

}

据我了解,它会将克隆的骨架重新绑定到克隆的网格。 所以主题示例可能像这样:

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);
    (...)