Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WebGPURenderer: Better skinning performance #27753

Merged
merged 3 commits into from
Feb 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions examples/jsm/nodes/Nodes.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,15 +87,15 @@ export { default as CubeTextureNode, cubeTexture } from './accessors/CubeTexture
export { default as InstanceNode, instance } from './accessors/InstanceNode.js';
export { default as MaterialNode, materialAlphaTest, materialColor, materialShininess, materialEmissive, materialOpacity, materialSpecularColor, materialSpecularStrength, materialReflectivity, materialRoughness, materialMetalness, materialNormal, materialClearcoat, materialClearcoatRoughness, materialClearcoatNormal, materialRotation, materialSheen, materialSheenRoughness, materialIridescence, materialIridescenceIOR, materialIridescenceThickness, materialLineScale, materialLineDashSize, materialLineGapSize, materialLineWidth, materialLineDashOffset, materialPointWidth } from './accessors/MaterialNode.js';
export { default as MaterialReferenceNode, materialReference } from './accessors/MaterialReferenceNode.js';
export { default as MorphNode, morph } from './accessors/MorphNode.js';
export { default as MorphNode, morphReference } from './accessors/MorphNode.js';
export { default as TextureBicubicNode, textureBicubic } from './accessors/TextureBicubicNode.js';
export { default as ModelNode, modelDirection, modelViewMatrix, modelNormalMatrix, modelWorldMatrix, modelPosition, modelViewPosition, modelScale } from './accessors/ModelNode.js';
export { default as ModelViewProjectionNode, modelViewProjection } from './accessors/ModelViewProjectionNode.js';
export { default as NormalNode, normalGeometry, normalLocal, normalView, normalWorld, transformedNormalView, transformedNormalWorld, transformedClearcoatNormalView } from './accessors/NormalNode.js';
export { default as Object3DNode, objectDirection, objectViewMatrix, objectNormalMatrix, objectWorldMatrix, objectPosition, objectScale, objectViewPosition } from './accessors/Object3DNode.js';
export { default as PointUVNode, pointUV } from './accessors/PointUVNode.js';
export { default as PositionNode, positionGeometry, positionLocal, positionWorld, positionWorldDirection, positionView, positionViewDirection } from './accessors/PositionNode.js';
export { default as ReferenceNode, reference, referenceIndex } from './accessors/ReferenceNode.js';
export { default as ReferenceNode, reference, referenceBuffer } from './accessors/ReferenceNode.js';
export { default as ReflectVectorNode, reflectVector } from './accessors/ReflectVectorNode.js';
export { default as SkinningNode, skinning } from './accessors/SkinningNode.js';
export { default as SceneNode, backgroundBlurriness, backgroundIntensity } from './accessors/SceneNode.js';
Expand Down
4 changes: 2 additions & 2 deletions examples/jsm/nodes/accessors/MaterialNode.js
Original file line number Diff line number Diff line change
Expand Up @@ -227,11 +227,11 @@ class MaterialNode extends Node {

} else if ( scope === MaterialNode.IRIDESCENCE_THICKNESS ) {

const iridescenceThicknessMaximum = reference( 1, 'float', material.iridescenceThicknessRange );
const iridescenceThicknessMaximum = reference( '1', 'float', material.iridescenceThicknessRange );

if ( material.iridescenceThicknessMap ) {

const iridescenceThicknessMinimum = reference( 0, 'float', material.iridescenceThicknessRange );
const iridescenceThicknessMinimum = reference( '0', 'float', material.iridescenceThicknessRange );

node = iridescenceThicknessMaximum.sub( iridescenceThicknessMinimum ).mul( this.getTexture( scope ).g ).add( iridescenceThicknessMinimum );

Expand Down
14 changes: 2 additions & 12 deletions examples/jsm/nodes/accessors/MaterialReferenceNode.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,24 +24,14 @@ class MaterialReferenceNode extends ReferenceNode {

}*/

updateReference( frame ) {
setReference( state ) {

this.reference = this.material !== null ? this.material : frame.material;
this.reference = this.material !== null ? this.material : state.material;

return this.reference;

}

setup( builder ) {

const material = this.material !== null ? this.material : builder.material;

this.node.value = material[ this.property ];

return super.setup( builder );

}

}

export default MaterialReferenceNode;
Expand Down
6 changes: 3 additions & 3 deletions examples/jsm/nodes/accessors/MorphNode.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import Node, { addNodeClass } from '../core/Node.js';
import { NodeUpdateType } from '../core/constants.js';
import { nodeProxy, tslFn } from '../shadernode/ShaderNode.js';
import { uniform } from '../core/UniformNode.js';
import { referenceIndex } from './ReferenceNode.js';
import { reference } from './ReferenceNode.js';
import { positionLocal } from './PositionNode.js';
import { normalLocal } from './NormalNode.js';
import { textureLoad } from './TextureNode.js';
Expand Down Expand Up @@ -188,7 +188,7 @@ class MorphNode extends Node {

loop( morphTargetsCount, ( { i } ) => {

const influence = referenceIndex( 'morphTargetInfluences', i, 'float' );
const influence = reference( 'morphTargetInfluences', 'float' ).element( i );

if ( hasMorphPosition === true ) {

Expand Down Expand Up @@ -240,6 +240,6 @@ class MorphNode extends Node {

export default MorphNode;

export const morph = nodeProxy( MorphNode );
export const morphReference = nodeProxy( MorphNode );

addNodeClass( 'MorphNode', MorphNode );
114 changes: 86 additions & 28 deletions examples/jsm/nodes/accessors/ReferenceNode.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,54 +2,85 @@ import Node, { addNodeClass } from '../core/Node.js';
import { NodeUpdateType } from '../core/constants.js';
import { uniform } from '../core/UniformNode.js';
import { texture } from './TextureNode.js';
import { buffer } from './BufferNode.js';
import { nodeObject } from '../shadernode/ShaderNode.js';
import { uniforms } from './UniformsNode.js';
import ArrayElementNode from '../utils/ArrayElementNode.js';

class ReferenceElementNode extends ArrayElementNode {

constructor( referenceNode, indexNode ) {

super( referenceNode, indexNode );

this.referenceNode = referenceNode;

this.isReferenceElementNode = true;

}

getNodeType() {

return this.referenceNode.uniformType;

}

generate( builder ) {

const snippet = super.generate( builder );
const arrayType = this.referenceNode.getNodeType();
const elementType = this.getNodeType();

return builder.format( snippet, arrayType, elementType );

}

}

class ReferenceNode extends Node {

constructor( property, uniformType, object = null, indexNode = null ) {
constructor( property, uniformType, object = null, count = null ) {

super();

this.property = property;
this.indexNode = indexNode;

this.uniformType = uniformType;

this.object = object;
this.reference = null;
this.count = count;

this.properties = property.split( '.' );
this.reference = null;
this.node = null;

this.updateType = NodeUpdateType.OBJECT;

this.setNodeType( uniformType );

}

updateReference( frame ) {
element( indexNode ) {

this.reference = this.object !== null ? this.object : frame.object;

return this.reference;
return nodeObject( new ReferenceElementNode( this, nodeObject( indexNode ) ) );

}

setNodeType( uniformType ) {

let node = null;

if ( uniformType === 'texture' ) {
if ( this.count !== null ) {

node = texture( null );
node = buffer( null, uniformType, this.count );

} else if ( Array.isArray( this.getValueFromReference() ) ) {

node = uniforms( null, uniformType );

} else if ( this.indexNode !== null ) {
} else if ( uniformType === 'texture' ) {

node = uniforms( null, uniformType ).element( this.indexNode );
node = texture( null );

} else {

node = uniform( uniformType );
node = uniform( null, uniformType );

}

Expand All @@ -63,40 +94,67 @@ class ReferenceNode extends Node {

}

update( /*frame*/ ) {
getValueFromReference( object = this.reference ) {

const value = this.reference[ this.property ];
const { properties } = this;

if ( this.indexNode !== null ) {
let value = object[ properties[ 0 ] ];

this.node.node.array = value;
for ( let i = 1; i < properties.length; i ++ ) {

} else {

this.node.value = value;
value = value[ properties[ i ] ];

}

return value;

}

setup( builder ) {
setReference( state ) {

if ( this.indexNode !== null ) {
this.reference = this.object !== null ? this.object : state.object;

this.node.node.array = ( this.object !== null ? this.object : builder.object )[ this.property ];
return this.reference;

}
}

setup() {

this.updateValue();

return this.node;

}

update( /*frame*/ ) {

this.updateValue();

}

updateValue() {

if ( this.node === null ) this.setNodeType( this.uniformType );

const value = this.getValueFromReference();

if ( Array.isArray( value ) ) {

this.node.array = value;

} else {

this.node.value = value;

}

}

}

export default ReferenceNode;

export const reference = ( name, type, object ) => nodeObject( new ReferenceNode( name, type, object ) );
export const referenceIndex = ( name, index, type, object ) => nodeObject( new ReferenceNode( name, type, object, index ) );
export const referenceBuffer = ( name, type, count, object ) => nodeObject( new ReferenceNode( name, type, object, count ) );

addNodeClass( 'ReferenceNode', ReferenceNode );
41 changes: 31 additions & 10 deletions examples/jsm/nodes/accessors/SkinningNode.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,23 @@
import Node, { addNodeClass } from '../core/Node.js';
import { NodeUpdateType } from '../core/constants.js';
import { nodeProxy } from '../shadernode/ShaderNode.js';
import { nodeObject } from '../shadernode/ShaderNode.js';
import { attribute } from '../core/AttributeNode.js';
import { uniform } from '../core/UniformNode.js';
import { reference, referenceBuffer } from './ReferenceNode.js';
import { add } from '../math/OperatorNode.js';
import { buffer } from './BufferNode.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 ) {
constructor( skinnedMesh, useReference = false ) {

super( 'void' );

this.skinnedMesh = skinnedMesh;
this.useReference = useReference;

this.updateType = NodeUpdateType.OBJECT;

Expand All @@ -24,9 +26,25 @@ class SkinningNode extends Node {
this.skinIndexNode = attribute( 'skinIndex', 'uvec4' );
this.skinWeightNode = attribute( 'skinWeight', 'vec4' );

this.bindMatrixNode = uniform( skinnedMesh.bindMatrix, 'mat4' );
this.bindMatrixInverseNode = uniform( skinnedMesh.bindMatrixInverse, 'mat4' );
this.boneMatricesNode = buffer( skinnedMesh.skeleton.boneMatrices, 'mat4', skinnedMesh.skeleton.bones.length );
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;

}

Expand Down Expand Up @@ -88,16 +106,19 @@ class SkinningNode extends Node {

}

update() {
update( frame ) {

const object = this.useReference ? frame.object : this.skinnedMesh;

this.skinnedMesh.skeleton.update();
object.skeleton.update();

}

}

export default SkinningNode;

export const skinning = nodeProxy( SkinningNode );
export const skinning = ( skinnedMesh ) => nodeObject( new SkinningNode( skinnedMesh ) );
export const skinningReference = ( skinnedMesh ) => nodeObject( new SkinningNode( skinnedMesh, true ) );

addNodeClass( 'SkinningNode', SkinningNode );
2 changes: 1 addition & 1 deletion examples/jsm/nodes/accessors/TextureNode.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ class TextureNode extends UniformNode {

}

updateReference( /*frame*/ ) {
setReference( /*state*/ ) {

return this.value;

Expand Down
4 changes: 3 additions & 1 deletion examples/jsm/nodes/core/Node.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class Node extends EventDispatcher {

}

updateReference() {
setReference( /*state*/ ) {

return this;

Expand Down Expand Up @@ -231,6 +231,8 @@ class Node extends EventDispatcher {

if ( buildStage === 'setup' ) {

this.setReference( builder );

const properties = builder.getNodeProperties( this );

if ( properties.initialized !== true || builder.context.tempRead === false ) {
Expand Down
4 changes: 2 additions & 2 deletions examples/jsm/nodes/core/NodeFrame.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ class NodeFrame {
updateBeforeNode( node ) {

const updateType = node.getUpdateBeforeType();
const reference = node.updateReference( this );
const reference = node.setReference( this );

if ( updateType === NodeUpdateType.FRAME ) {

Expand Down Expand Up @@ -86,7 +86,7 @@ class NodeFrame {
updateNode( node ) {

const updateType = node.getUpdateType();
const reference = node.updateReference( this );
const reference = node.setReference( this );

if ( updateType === NodeUpdateType.FRAME ) {

Expand Down
Loading