|
|
@@ -2,7 +2,7 @@ import Node from '../core/Node.js';
|
|
|
import { varyingProperty } from '../core/PropertyNode.js';
|
|
|
import { instancedBufferAttribute, instancedDynamicBufferAttribute } from './BufferAttributeNode.js';
|
|
|
import { normalLocal, transformNormal } from './Normal.js';
|
|
|
-import { positionLocal } from './Position.js';
|
|
|
+import { positionLocal, positionPrevious } from './Position.js';
|
|
|
import { nodeProxy, vec3, mat4 } from '../tsl/TSLBase.js';
|
|
|
import { NodeUpdateType } from '../core/constants.js';
|
|
|
import { buffer } from '../accessors/BufferNode.js';
|
|
|
@@ -99,6 +99,14 @@ class InstanceNode extends Node {
|
|
|
*/
|
|
|
this.bufferColor = null;
|
|
|
|
|
|
+ /**
|
|
|
+ * The previous instance matrices. Required for computing motion vectors.
|
|
|
+ *
|
|
|
+ * @type {?Node}
|
|
|
+ * @default null
|
|
|
+ */
|
|
|
+ this.previousInstanceMatrixNode = null;
|
|
|
+
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -136,51 +144,22 @@ class InstanceNode extends Node {
|
|
|
*/
|
|
|
setup( builder ) {
|
|
|
|
|
|
- const { instanceMatrix, instanceColor, isStorageMatrix, isStorageColor } = this;
|
|
|
-
|
|
|
- const { count } = instanceMatrix;
|
|
|
-
|
|
|
let { instanceMatrixNode, instanceColorNode } = this;
|
|
|
|
|
|
- if ( instanceMatrixNode === null ) {
|
|
|
-
|
|
|
- if ( isStorageMatrix ) {
|
|
|
-
|
|
|
- instanceMatrixNode = storage( instanceMatrix, 'mat4', Math.max( count, 1 ) ).element( instanceIndex );
|
|
|
-
|
|
|
- } else {
|
|
|
-
|
|
|
- // Both backends have ~64kb UBO limit; fallback to attributes above 1000 matrices.
|
|
|
-
|
|
|
- if ( count <= 1000 ) {
|
|
|
-
|
|
|
- instanceMatrixNode = buffer( instanceMatrix.array, 'mat4', Math.max( count, 1 ) ).element( instanceIndex );
|
|
|
-
|
|
|
- } else {
|
|
|
-
|
|
|
- const interleaved = new InstancedInterleavedBuffer( instanceMatrix.array, 16, 1 );
|
|
|
-
|
|
|
- this.buffer = interleaved;
|
|
|
+ // instance matrix
|
|
|
|
|
|
- const bufferFn = instanceMatrix.usage === DynamicDrawUsage ? instancedDynamicBufferAttribute : instancedBufferAttribute;
|
|
|
-
|
|
|
- const instanceBuffers = [
|
|
|
- bufferFn( interleaved, 'vec4', 16, 0 ),
|
|
|
- bufferFn( interleaved, 'vec4', 16, 4 ),
|
|
|
- bufferFn( interleaved, 'vec4', 16, 8 ),
|
|
|
- bufferFn( interleaved, 'vec4', 16, 12 )
|
|
|
- ];
|
|
|
-
|
|
|
- instanceMatrixNode = mat4( ...instanceBuffers );
|
|
|
-
|
|
|
- }
|
|
|
+ if ( instanceMatrixNode === null ) {
|
|
|
|
|
|
- }
|
|
|
+ instanceMatrixNode = this._createInstanceMatrixNode( true );
|
|
|
|
|
|
this.instanceMatrixNode = instanceMatrixNode;
|
|
|
|
|
|
}
|
|
|
|
|
|
+ // instance color
|
|
|
+
|
|
|
+ const { instanceColor, isStorageColor } = this;
|
|
|
+
|
|
|
if ( instanceColor && instanceColorNode === null ) {
|
|
|
|
|
|
if ( isStorageColor ) {
|
|
|
@@ -208,6 +187,12 @@ class InstanceNode extends Node {
|
|
|
const instancePosition = instanceMatrixNode.mul( positionLocal ).xyz;
|
|
|
positionLocal.assign( instancePosition );
|
|
|
|
|
|
+ if ( builder.needsPreviousData() ) {
|
|
|
+
|
|
|
+ positionPrevious.assign( this.getPreviousInstancedPosition( builder ) );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
// NORMAL
|
|
|
|
|
|
if ( builder.hasGeometryAttribute( 'normal' ) ) {
|
|
|
@@ -235,7 +220,7 @@ class InstanceNode extends Node {
|
|
|
*
|
|
|
* @param {NodeFrame} frame - The current node frame.
|
|
|
*/
|
|
|
- update( /*frame*/ ) {
|
|
|
+ update( frame ) {
|
|
|
|
|
|
if ( this.buffer !== null && this.isStorageMatrix !== true ) {
|
|
|
|
|
|
@@ -265,6 +250,85 @@ class InstanceNode extends Node {
|
|
|
|
|
|
}
|
|
|
|
|
|
+ if ( this.previousInstanceMatrixNode !== null ) {
|
|
|
+
|
|
|
+ frame.object.previousInstanceMatrix.array.set( this.instanceMatrix.array );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Computes the transformed/instanced vertex position of the previous frame.
|
|
|
+ *
|
|
|
+ * @param {NodeBuilder} builder - The current node builder.
|
|
|
+ * @return {Node<vec3>} The instanced position from the previous frame.
|
|
|
+ */
|
|
|
+ getPreviousInstancedPosition( builder ) {
|
|
|
+
|
|
|
+ const instancedMesh = builder.object;
|
|
|
+
|
|
|
+ if ( this.previousInstanceMatrixNode === null ) {
|
|
|
+
|
|
|
+ instancedMesh.previousInstanceMatrix = this.instanceMatrix.clone();
|
|
|
+
|
|
|
+ this.previousInstanceMatrixNode = this._createInstanceMatrixNode( false );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ return this.previousInstanceMatrixNode.mul( positionPrevious ).xyz;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Creates a node representing the instance matrix data.
|
|
|
+ *
|
|
|
+ * @private
|
|
|
+ * @param {boolean} assignBuffer - Whether the created interleaved buffer should be assigned to the `buffer` member or not.
|
|
|
+ * @return {Node} The instance matrix node.
|
|
|
+ */
|
|
|
+ _createInstanceMatrixNode( assignBuffer ) {
|
|
|
+
|
|
|
+ let instanceMatrixNode;
|
|
|
+
|
|
|
+ const { instanceMatrix } = this;
|
|
|
+ const { count } = instanceMatrix;
|
|
|
+
|
|
|
+ if ( this.isStorageMatrix ) {
|
|
|
+
|
|
|
+ instanceMatrixNode = storage( instanceMatrix, 'mat4', Math.max( count, 1 ) ).element( instanceIndex );
|
|
|
+
|
|
|
+ } else {
|
|
|
+
|
|
|
+ // Both backends have ~64kb UBO limit; fallback to attributes above 1000 matrices.
|
|
|
+
|
|
|
+ if ( count <= 1000 ) {
|
|
|
+
|
|
|
+ instanceMatrixNode = buffer( instanceMatrix.array, 'mat4', Math.max( count, 1 ) ).element( instanceIndex );
|
|
|
+
|
|
|
+ } else {
|
|
|
+
|
|
|
+ const interleaved = new InstancedInterleavedBuffer( instanceMatrix.array, 16, 1 );
|
|
|
+
|
|
|
+ if ( assignBuffer === true ) this.buffer = interleaved;
|
|
|
+
|
|
|
+ const bufferFn = instanceMatrix.usage === DynamicDrawUsage ? instancedDynamicBufferAttribute : instancedBufferAttribute;
|
|
|
+
|
|
|
+ const instanceBuffers = [
|
|
|
+ bufferFn( interleaved, 'vec4', 16, 0 ),
|
|
|
+ bufferFn( interleaved, 'vec4', 16, 4 ),
|
|
|
+ bufferFn( interleaved, 'vec4', 16, 8 ),
|
|
|
+ bufferFn( interleaved, 'vec4', 16, 12 )
|
|
|
+ ];
|
|
|
+
|
|
|
+ instanceMatrixNode = mat4( ...instanceBuffers );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ return instanceMatrixNode;
|
|
|
+
|
|
|
}
|
|
|
|
|
|
}
|