将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
} );
}
}
} );
答案 0 :(得分:1)
看看这个拉取请求:https://github.com/mrdoob/three.js/pull/8953/files
尤其是这部分:
groupid
因此,要烘焙变形,您必须执行以下步骤:
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
skinWeights
的坐标系Geometry
加权矩阵答案 1 :(得分:1)
在场景中烘焙,保留法线,不导出到 STL。
用法:
bakeSkeleton(mesh)
转换将应用于提供的对象及其所有子对象。 getBoneNormalTransform
由 boneTransform
上的内置 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 );
};
}())