125 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			125 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| import Node, { addNodeClass } from '../core/Node.js';
 | |
| import { NodeUpdateType } from '../core/constants.js';
 | |
| import { nodeObject } from '../shadernode/ShaderNode.js';
 | |
| import { attribute } from '../core/AttributeNode.js';
 | |
| import { reference, referenceBuffer } from './ReferenceNode.js';
 | |
| import { add } from '../math/OperatorNode.js';
 | |
| import { normalLocal } from './NormalNode.js';
 | |
| import { positionLocal } from './PositionNode.js';
 | |
| import { tangentLocal } from './TangentNode.js';
 | |
| import { uniform } from '../core/UniformNode.js';
 | |
| import { buffer } from './BufferNode.js';
 | |
| 
 | |
| class SkinningNode extends Node {
 | |
| 
 | |
| 	constructor( skinnedMesh, useReference = false ) {
 | |
| 
 | |
| 		super( 'void' );
 | |
| 
 | |
| 		this.skinnedMesh = skinnedMesh;
 | |
| 		this.useReference = useReference;
 | |
| 
 | |
| 		this.updateType = NodeUpdateType.OBJECT;
 | |
| 
 | |
| 		//
 | |
| 
 | |
| 		this.skinIndexNode = attribute( 'skinIndex', 'uvec4' );
 | |
| 		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 );
 | |
| 
 | |
| 		}
 | |
| 
 | |
| 		this.bindMatrixNode = bindMatrixNode;
 | |
| 		this.bindMatrixInverseNode = bindMatrixInverseNode;
 | |
| 		this.boneMatricesNode = boneMatricesNode;
 | |
| 
 | |
| 	}
 | |
| 
 | |
| 	setup( builder ) {
 | |
| 
 | |
| 		const { skinIndexNode, skinWeightNode, bindMatrixNode, bindMatrixInverseNode, boneMatricesNode } = this;
 | |
| 
 | |
| 		const boneMatX = boneMatricesNode.element( skinIndexNode.x );
 | |
| 		const boneMatY = boneMatricesNode.element( skinIndexNode.y );
 | |
| 		const boneMatZ = boneMatricesNode.element( skinIndexNode.z );
 | |
| 		const boneMatW = boneMatricesNode.element( skinIndexNode.w );
 | |
| 
 | |
| 		// POSITION
 | |
| 
 | |
| 		const skinVertex = bindMatrixNode.mul( positionLocal );
 | |
| 
 | |
| 		const skinned = add(
 | |
| 			boneMatX.mul( skinWeightNode.x ).mul( skinVertex ),
 | |
| 			boneMatY.mul( skinWeightNode.y ).mul( skinVertex ),
 | |
| 			boneMatZ.mul( skinWeightNode.z ).mul( skinVertex ),
 | |
| 			boneMatW.mul( skinWeightNode.w ).mul( skinVertex )
 | |
| 		);
 | |
| 
 | |
| 		const skinPosition = bindMatrixInverseNode.mul( skinned ).xyz;
 | |
| 
 | |
| 		// NORMAL
 | |
| 
 | |
| 		let skinMatrix = add(
 | |
| 			skinWeightNode.x.mul( boneMatX ),
 | |
| 			skinWeightNode.y.mul( boneMatY ),
 | |
| 			skinWeightNode.z.mul( boneMatZ ),
 | |
| 			skinWeightNode.w.mul( boneMatW )
 | |
| 		);
 | |
| 
 | |
| 		skinMatrix = bindMatrixInverseNode.mul( skinMatrix ).mul( bindMatrixNode );
 | |
| 
 | |
| 		const skinNormal = skinMatrix.transformDirection( normalLocal ).xyz;
 | |
| 
 | |
| 		// ASSIGNS
 | |
| 
 | |
| 		positionLocal.assign( skinPosition );
 | |
| 		normalLocal.assign( skinNormal );
 | |
| 
 | |
| 		if ( builder.hasGeometryAttribute( 'tangent' ) ) {
 | |
| 
 | |
| 			tangentLocal.assign( skinNormal );
 | |
| 
 | |
| 		}
 | |
| 
 | |
| 	}
 | |
| 
 | |
| 	generate( builder, output ) {
 | |
| 
 | |
| 		if ( output !== 'void' ) {
 | |
| 
 | |
| 			return positionLocal.build( builder, output );
 | |
| 
 | |
| 		}
 | |
| 
 | |
| 	}
 | |
| 
 | |
| 	update( frame ) {
 | |
| 
 | |
| 		const object = this.useReference ? frame.object : this.skinnedMesh;
 | |
| 
 | |
| 		object.skeleton.update();
 | |
| 
 | |
| 	}
 | |
| 
 | |
| }
 | |
| 
 | |
| export default SkinningNode;
 | |
| 
 | |
| export const skinning = ( skinnedMesh ) => nodeObject( new SkinningNode( skinnedMesh ) );
 | |
| export const skinningReference = ( skinnedMesh ) => nodeObject( new SkinningNode( skinnedMesh, true ) );
 | |
| 
 | |
| addNodeClass( 'SkinningNode', SkinningNode );
 |