|
|
@@ -10,6 +10,9 @@ import { tangentLocal } from './Tangent.js';
|
|
|
import { uniform } from '../core/UniformNode.js';
|
|
|
import { buffer } from './BufferNode.js';
|
|
|
import { getDataFromObject } from '../core/NodeUtils.js';
|
|
|
+import { storage } from './StorageBufferNode.js';
|
|
|
+import { InstancedBufferAttribute } from '../../core/InstancedBufferAttribute.js';
|
|
|
+import { instanceIndex } from '../core/IndexNode.js';
|
|
|
|
|
|
const _frameId = new WeakMap();
|
|
|
|
|
|
@@ -31,9 +34,8 @@ class SkinningNode extends Node {
|
|
|
* Constructs a new skinning node.
|
|
|
*
|
|
|
* @param {SkinnedMesh} skinnedMesh - The skinned mesh.
|
|
|
- * @param {boolean} [useReference=false] - Whether to use reference nodes for internal skinned mesh related data or not.
|
|
|
*/
|
|
|
- constructor( skinnedMesh, useReference = false ) {
|
|
|
+ constructor( skinnedMesh ) {
|
|
|
|
|
|
super( 'void' );
|
|
|
|
|
|
@@ -44,14 +46,6 @@ class SkinningNode extends Node {
|
|
|
*/
|
|
|
this.skinnedMesh = skinnedMesh;
|
|
|
|
|
|
- /**
|
|
|
- * Whether to use reference nodes for internal skinned mesh related data or not.
|
|
|
- * TODO: Explain the purpose of the property.
|
|
|
- *
|
|
|
- * @type {boolean}
|
|
|
- */
|
|
|
- this.useReference = useReference;
|
|
|
-
|
|
|
/**
|
|
|
* The update type overwritten since skinning nodes are updated per object.
|
|
|
*
|
|
|
@@ -75,42 +69,40 @@ class SkinningNode extends Node {
|
|
|
*/
|
|
|
this.skinWeightNode = attribute( 'skinWeight', 'vec4' );
|
|
|
|
|
|
- let bindMatrixNode, bindMatrixInverseNode, boneMatricesNode;
|
|
|
-
|
|
|
- if ( useReference ) {
|
|
|
-
|
|
|
- bindMatrixNode = reference( 'bindMatrix', 'mat4' );
|
|
|
- bindMatrixInverseNode = reference( 'bindMatrixInverse', 'mat4' );
|
|
|
- boneMatricesNode = referenceBuffer( 'skeleton.boneMatrices', 'mat4', skinnedMesh.skeleton.bones.length );
|
|
|
-
|
|
|
- } else {
|
|
|
-
|
|
|
- bindMatrixNode = uniform( skinnedMesh.bindMatrix, 'mat4' );
|
|
|
- bindMatrixInverseNode = uniform( skinnedMesh.bindMatrixInverse, 'mat4' );
|
|
|
- boneMatricesNode = buffer( skinnedMesh.skeleton.boneMatrices, 'mat4', skinnedMesh.skeleton.bones.length );
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
/**
|
|
|
* The bind matrix node.
|
|
|
*
|
|
|
* @type {Node<mat4>}
|
|
|
*/
|
|
|
- this.bindMatrixNode = bindMatrixNode;
|
|
|
+ this.bindMatrixNode = reference( 'bindMatrix', 'mat4' );
|
|
|
|
|
|
/**
|
|
|
* The bind matrix inverse node.
|
|
|
*
|
|
|
* @type {Node<mat4>}
|
|
|
*/
|
|
|
- this.bindMatrixInverseNode = bindMatrixInverseNode;
|
|
|
+ this.bindMatrixInverseNode = reference( 'bindMatrixInverse', 'mat4' );
|
|
|
|
|
|
/**
|
|
|
* The bind matrices as a uniform buffer node.
|
|
|
*
|
|
|
* @type {Node}
|
|
|
*/
|
|
|
- this.boneMatricesNode = boneMatricesNode;
|
|
|
+ this.boneMatricesNode = referenceBuffer( 'skeleton.boneMatrices', 'mat4', skinnedMesh.skeleton.bones.length );
|
|
|
+
|
|
|
+ /**
|
|
|
+ * The current vertex position in local space.
|
|
|
+ *
|
|
|
+ * @type {Node<vec3>}
|
|
|
+ */
|
|
|
+ this.positionNode = positionLocal;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * The result of vertex position in local space.
|
|
|
+ *
|
|
|
+ * @type {Node<vec3>}
|
|
|
+ */
|
|
|
+ this.toPositionNode = positionLocal;
|
|
|
|
|
|
/**
|
|
|
* The previous bind matrices as a uniform buffer node.
|
|
|
@@ -127,10 +119,10 @@ class SkinningNode extends Node {
|
|
|
* Transforms the given vertex position via skinning.
|
|
|
*
|
|
|
* @param {Node} [boneMatrices=this.boneMatricesNode] - The bone matrices
|
|
|
- * @param {Node<vec3>} [position=positionLocal] - The vertex position in local space.
|
|
|
+ * @param {Node<vec3>} [position=this.positionNode] - The vertex position in local space.
|
|
|
* @return {Node<vec3>} The transformed vertex position.
|
|
|
*/
|
|
|
- getSkinnedPosition( boneMatrices = this.boneMatricesNode, position = positionLocal ) {
|
|
|
+ getSkinnedPosition( boneMatrices = this.boneMatricesNode, position = this.positionNode ) {
|
|
|
|
|
|
const { skinIndexNode, skinWeightNode, bindMatrixNode, bindMatrixInverseNode } = this;
|
|
|
|
|
|
@@ -225,6 +217,7 @@ class SkinningNode extends Node {
|
|
|
* Setups the skinning node by assigning the transformed vertex data to predefined node variables.
|
|
|
*
|
|
|
* @param {NodeBuilder} builder - The current node builder.
|
|
|
+ * @return {Node<vec3>} The transformed vertex position.
|
|
|
*/
|
|
|
setup( builder ) {
|
|
|
|
|
|
@@ -236,8 +229,9 @@ class SkinningNode extends Node {
|
|
|
|
|
|
const skinPosition = this.getSkinnedPosition();
|
|
|
|
|
|
+ if ( this.toPositionNode ) this.toPositionNode.assign( skinPosition );
|
|
|
|
|
|
- positionLocal.assign( skinPosition );
|
|
|
+ //
|
|
|
|
|
|
if ( builder.hasGeometryAttribute( 'normal' ) ) {
|
|
|
|
|
|
@@ -253,6 +247,8 @@ class SkinningNode extends Node {
|
|
|
|
|
|
}
|
|
|
|
|
|
+ return skinPosition;
|
|
|
+
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -266,7 +262,7 @@ class SkinningNode extends Node {
|
|
|
|
|
|
if ( output !== 'void' ) {
|
|
|
|
|
|
- return positionLocal.build( builder, output );
|
|
|
+ return super.generate( builder, output );
|
|
|
|
|
|
}
|
|
|
|
|
|
@@ -279,8 +275,7 @@ class SkinningNode extends Node {
|
|
|
*/
|
|
|
update( frame ) {
|
|
|
|
|
|
- const object = this.useReference ? frame.object : this.skinnedMesh;
|
|
|
- const skeleton = object.skeleton;
|
|
|
+ const skeleton = frame.object && frame.object.skeleton ? frame.object.skeleton : this.skinnedMesh.skeleton;
|
|
|
|
|
|
if ( _frameId.get( skeleton ) === frame.frameId ) return;
|
|
|
|
|
|
@@ -307,11 +302,25 @@ export default SkinningNode;
|
|
|
export const skinning = ( skinnedMesh ) => nodeObject( new SkinningNode( skinnedMesh ) );
|
|
|
|
|
|
/**
|
|
|
- * TSL function for creating a skinning node with reference usage.
|
|
|
+ * TSL function for computing skinning.
|
|
|
*
|
|
|
* @tsl
|
|
|
* @function
|
|
|
* @param {SkinnedMesh} skinnedMesh - The skinned mesh.
|
|
|
+ * @param {Node<vec3>} [toPosition=null] - The target position.
|
|
|
* @returns {SkinningNode}
|
|
|
*/
|
|
|
-export const skinningReference = ( skinnedMesh ) => nodeObject( new SkinningNode( skinnedMesh, true ) );
|
|
|
+export const computeSkinning = ( skinnedMesh, toPosition = null ) => {
|
|
|
+
|
|
|
+ const node = new SkinningNode( skinnedMesh );
|
|
|
+ node.positionNode = storage( new InstancedBufferAttribute( skinnedMesh.geometry.getAttribute( 'position' ).array, 3 ), 'vec3' ).setPBO( true ).toReadOnly().element( instanceIndex ).toVar();
|
|
|
+ node.skinIndexNode = storage( new InstancedBufferAttribute( new Uint32Array( skinnedMesh.geometry.getAttribute( 'skinIndex' ).array ), 4 ), 'uvec4' ).setPBO( true ).toReadOnly().element( instanceIndex ).toVar();
|
|
|
+ node.skinWeightNode = storage( new InstancedBufferAttribute( skinnedMesh.geometry.getAttribute( 'skinWeight' ).array, 4 ), 'vec4' ).setPBO( true ).toReadOnly().element( instanceIndex ).toVar();
|
|
|
+ node.bindMatrixNode = uniform( skinnedMesh.bindMatrix, 'mat4' );
|
|
|
+ node.bindMatrixInverseNode = uniform( skinnedMesh.bindMatrixInverse, 'mat4' );
|
|
|
+ node.boneMatricesNode = buffer( skinnedMesh.skeleton.boneMatrices, 'mat4', skinnedMesh.skeleton.bones.length );
|
|
|
+ node.toPositionNode = toPosition;
|
|
|
+
|
|
|
+ return nodeObject( node );
|
|
|
+
|
|
|
+};
|