如何克隆蒙皮网格?

Posted

技术标签:

【中文标题】如何克隆蒙皮网格?【英文标题】:How to clone a Skinned Mesh? 【发布时间】:2018-01-05 17:16:49 【问题描述】:

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

不幸的是,我发现实现这个结果的唯一方法是对每个模型实例都通过 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】:

我在这个拉取请求中找到了一个解决方案: 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);
    (...)

【讨论】:

您能否编辑答案并添加更多有关这些功能的作用的信息?

以上是关于如何克隆蒙皮网格?的主要内容,如果未能解决你的问题,请参考以下文章

Forge Viewer - 如何在场景中访问(或获取渲染/片段代理)克隆的网格?

在网格加载和处理期间如何转换蒙皮网格?

如何在THREE.js中克隆Line对象的Mesh?

怎样在3DMAX里克隆某个物体的一个面

关于Unity中蒙皮网格和布料的使用

更换蒙皮网格上的材质