Three.js-将骨骼烘焙到几何

时间:2018-06-25 03:37:53

标签: three.js 3d

bone矩阵应用于顶点以使实际的几何图形表示不使用GPU的变换形状的正确方法是什么?

我有一个角色模型,我要对其应用skeleton,以便以不同的姿势进行3D打印,因此我想使用STLExporter来导出3D可打印文件,但只能导出原始的几何形状。

如果我可以按正确的顺序用正确的骨骼矩阵在scene.traverse()SkinnedMesh上进行geometry.applyMatrix(???)的操作,那么我应该能够导出应用了转换的STL,对吗? / p>

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

2 个答案:

答案 0 :(得分:1)

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

尤其是这部分:

groupid

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

  1. 遍历所有顶点
  2. 获取相应的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 ) ); + + } + + } skinIndices
  3. 获取每个顶点的相关骨骼及其权重
  4. 遍及一切
  5. 获取骨骼的变换矩阵并将其转换为skinWeights的坐标系
  6. 通过关联的Geometry加权矩阵
  7. 应用最终矩阵

答案 1 :(得分:1)

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

用法:

bakeSkeleton(mesh)

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


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

  };

}())