【问题标题】:Three.js - Bake skeleton transform into geometryThree.js - 将骨架转换为几何图形
【发布时间】:2018-12-03 14:05:42
【问题描述】:

在不使用 GPU 的情况下,将bone 矩阵应用于顶点以使实际几何图形表示转换后的形状的正确方法是什么?

我有一个角色模型,我正在应用skeleton,我想以不同的姿势进行 3D 打印,所以我想使用STLExporter 导出一个 3D 可打印文件,但它只导出原始几何图形。

如果我可以在每个SkinnedMeshgeometry.applyMatrix(???) 上以正确的顺序使用正确的骨骼矩阵scene.traverse(),我应该能够导出一个应用了变换的STL,对吧?

var objects = [];
var triangles = 0;
scene.traverse( function ( object ) {
    if ( object.isMesh ) {
        var geometry = object.geometry;
        if ( geometry.isBufferGeometry ) {
            geometry = new THREE.Geometry().fromBufferGeometry( geometry );
        }
        // TODO: Apply skeleton transform
        if ( geometry.isGeometry ) {
            triangles += geometry.faces.length;
            objects.push( {
                geometry: geometry,
                matrixWorld: object.matrixWorld
            } );
        }
    }
} );

【问题讨论】:

    标签: three.js 3d


    【解决方案1】:

    看看这个拉取请求:https://github.com/mrdoob/three.js/pull/8953/files

    尤其是这部分:

    THREE.SkinnedMesh.prototype.boneTransform = 
    ...snip...
    for ( var i = 0; i < 4; i ++ ) {
    +
    +           var skinWeight = skinWeights[ properties[ i ] ];
    +
    +           if ( skinWeight != 0 ) {
    +
    +               var boneIndex = skinIndices[ properties[ i ] ];
    +               tempMatrix.multiplyMatrices( this.skeleton.bones[ boneIndex ].matrixWorld, this.skeleton.boneInverses[ boneIndex ] );
    +               result.add( temp.copy( clone ).applyMatrix4( tempMatrix ).multiplyScalar( skinWeight ) );
    +
    +           }
    +
    +       }
    

    因此,要烘焙变形,您必须执行以下步骤:

    1. 遍历所有顶点
    2. 获取他们对应的skinIndicesskinWeights
    3. 获取每个顶点的关联骨骼及其权重
    4. 检查所有骨头
    5. 获取骨骼的变换矩阵并将其转换为Geometry的坐标系
    6. 通过关联的skinWeights[boneIdx] 加权矩阵
    7. 应用最终矩阵

    edit:修复问题的导出器版本。 (https://github.com/mrdoob/three.js/blob/1be00d5ad075b2305b86c6385403d0e56b4621dd/examples/js/exporters/STLExporter.js)

    【讨论】:

    • 欢迎来到 Stack Overflow。谢谢你回答我的问题。看来我需要做一些工作来调整该代码。
    • 谢谢准解释。 @wizulus 您是否设法将其合并到导出器中。如果没有,我将在接下来的几周内尽力而为,因为我目前遇到的问题与您上面描述的完全相同。当前 master 中的 STL 导出器只是忽略了 skinnedMesh 顶点上的所有骨骼变换。 gist.github.com/jcarletto27/e271bbb7639c4bed2427这是旧版本的解决方案,但是由于skinIndices和skinWeights的存储方式不同,可能是由于新的动画系统,这不再起作用了。
    • 我制作了一个版本的导出器,它与当前主控器一起工作,并在 SkinnedMesh 对象上合并了顶点骨骼变换。 github.com/mrdoob/three.js/blob/…
    【解决方案2】:

    在场景中烘焙,保留法线,不导出到 STL。

    用法:

    bakeSkeleton(mesh)

    转换将应用于提供的对象及其所有子对象。 getBoneNormalTransformSkinnedMesh 上的内置 boneTransform 制成,但适用于法线。

    
    function bakeSkeleton ( target ) {
      var v1 = new Vector3();
    
      target.traverse( function ( object ) {
        if ( !object.isSkinnedMesh ) return;
        if ( object.geometry.isBufferGeometry !== true ) throw new Error( 'Only BufferGeometry supported.' );
    
        var positionAttribute = object.geometry.getAttribute( 'position' );
        var normalAttribute = object.geometry.getAttribute( 'normal' );
    
        for ( var j = 0; j < positionAttribute.count; j ++ ) {
          object.boneTransform( j, v1 );
          positionAttribute.setXYZ( j, v1.x, v1.y, v1.z);
    
          getBoneNormalTransform.call( object, j, v1 );
          normalAttribute.setXYZ( j, v1.x, v1.y, v1.z );
        }
    
        positionAttribute.needsUpdate = true;
        normalAttribute.needsUpdate = true;
    
        object.skeleton.bones.forEach(bone => bone.rotation.set(0,0,0));
      } );
    }
    
    
    const getBoneNormalTransform = (function () {
    
      var baseNormal = new Vector3();
    
      var skinIndex = new Vector4();
      var skinWeight = new Vector4();
    
      var vector = new Vector3();
      var matrix = new Matrix4();
      var matrix3 = new Matrix3();
    
      return function ( index, target ) {
    
        var skeleton = this.skeleton;
        var geometry = this.geometry;
    
        skinIndex.fromBufferAttribute( geometry.attributes.skinIndex, index );
        skinWeight.fromBufferAttribute( geometry.attributes.skinWeight, index );
    
        baseNormal.fromBufferAttribute( geometry.attributes.normal, index ).applyNormalMatrix( matrix3.getNormalMatrix(this.bindMatrix) );
    
        target.set( 0, 0, 0 );
    
        for ( var i = 0; i < 4; i ++ ) {
    
          var weight = skinWeight.getComponent( i );
    
          if ( weight !== 0 ) {
    
            var boneIndex = skinIndex.getComponent( i );
    
            matrix.multiplyMatrices( skeleton.bones[ boneIndex ].matrixWorld, skeleton.boneInverses[ boneIndex ] );
    
            target.addScaledVector( vector.copy( baseNormal ).applyNormalMatrix( matrix3.getNormalMatrix(matrix) ), weight );
    
          }
    
        }
        matrix3.getNormalMatrix(this.bindMatrixInverse);
        return target.applyNormalMatrix( matrix3 );
    
      };
    
    }())
    
    

    【讨论】:

      猜你喜欢
      • 2020-07-11
      • 1970-01-01
      • 2021-12-21
      • 2014-12-13
      • 2012-11-20
      • 2020-06-19
      • 1970-01-01
      • 1970-01-01
      • 2013-08-24
      相关资源
      最近更新 更多