instanceMatrix in TSL // webGPU in vertexNode

Hey there!
I’m experimenting with TSL and instancedMesh and i’m kinda lost on how to get the instanceMatrix for each element when i replace the entire vertexNode

Somehow now i’m doing
const instMat = buffer(this.instanceMatrix.array, 'mat4', this.count).element(instanceIndex).toMat4().toVar()

but is not the proper way to do it. It works but it fails with a large amount of instances due on how he use the buffer, it goes beyond limits.
I tried to use another approach like
const instanceMatrixNode = instancedBufferAttribute(this.instanceMatrix)

but doesn’t work neither.
Can’t find any ref in the docs, neither in the exported values from three/tsl

Any help? Any idea? How should i get that value?

I recently spent some time trying the same thing (accessing the instanceMatrix for each instance of an InstancedMesh inside the vertexNode), and the short answer is:

No, as of version 180 of three.js and after many days of research, I never found a way to get the original instanceMatrix. But, if each instance’s scale and rotation are unset, you can “reconstruct” the instance matrix, or just simply get the instance’s position in world coordinates. Like this:

material.vertexNode = tsl.Fn(() => {
    const posLoc = tsl.positionLocal;
    const posGeo = tsl.positionGeometry;
    const posMod = tsl.modelPosition;
    // Get the instance's center in world coordinates.
    // NOTE: This only works if each instance's scale and rotation are unset.
    // In other words, the scale is {x:1,y:1,z:1} and rotation is {x:0,y:0,z:0,w:1} for each instance.
    const instanceCenter = posLoc.sub(posGeo).add(posMod).toVar();
    // Now you can do something with the instance center in world coordinates...
})();

What specifically are you trying to do with the instanceMatrix? I might be able to help depending on what you’re doing.

well, this is kinda useless in terms of the usage of instance matrix unfortunately because it takes in consideration just the position unfortunately.
I need to have access on all the props, pos-rot-scale, like the good old way in GLSL :pensive_face:

Can you show a basic GLSL version of what you described.

wdym?

gl_Position = projectionMatrix  * modelViewMatrix * instanceMatrix * vec4(position, 1.0)

I need to have access to that instanceMatrix in my vertexNode due the fact i’m replacing the entire node, so at some point i need to use the instance matrix value

here is a working THREE.InstancedMesh demo using three.webgpu.js and the THREE.WebGPURenderer

And this is the vertex shader it creates. Maybe there is a clue in it.

// Three.js r180 - Node System

// directives


// structs


// uniforms

struct NodeBuffer_823Struct {
	value : array< mat4x4<f32>, 64 >
};
@binding( 1 ) @group( 1 )
var<uniform> NodeBuffer_823 : NodeBuffer_823Struct;
struct renderStruct {
	cameraViewMatrix : mat4x4<f32>,
	cameraProjectionMatrix : mat4x4<f32>
};
@binding( 1 ) @group( 0 )
var<uniform> render : renderStruct;

struct objectStruct {
	nodeUniform6 : mat3x3<f32>,
	nodeUniform14 : mat4x4<f32>
};
@binding( 2 ) @group( 1 )
var<uniform> object : objectStruct;

// varyings

struct VaryingsStruct {
	@location( 3 ) v_normalViewGeometry : vec3<f32>,
	@location( 4 ) v_positionViewDirection : vec3<f32>,
	@builtin( position ) Vertex : vec4<f32>
};
var<private> varyings : VaryingsStruct;

// codes


@vertex
fn main( @builtin( instance_index ) instanceIndex : u32,
	@location( 0 ) position : vec3<f32>,
	@location( 1 ) normal : vec3<f32> ) -> VaryingsStruct {

	// vars
	
	var normalLocal : vec3<f32>;
	var modelViewMatrix : mat4x4<f32>;
	var nodeVar72 : vec4<f32>;
	var positionLocal : vec3<f32>;
	var v_modelViewProjection : vec4<f32>;
	var v_positionView : vec3<f32>;


	// flow
	// code

	positionLocal = position;
	positionLocal = ( NodeBuffer_823.value[ instanceIndex ] * vec4<f32>( positionLocal, 1.0 ) ).xyz;
	normalLocal = normal;
	normalLocal = ( mat3x3<f32>( NodeBuffer_823.value[ instanceIndex ][ 0 ].xyz, NodeBuffer_823.value[ instanceIndex ][ 1 ].xyz, NodeBuffer_823.value[ instanceIndex ][ 2 ].xyz ) * ( normalLocal / vec3<f32>( dot( mat3x3<f32>( NodeBuffer_823.value[ instanceIndex ][ 0 ].xyz, NodeBuffer_823.value[ instanceIndex ][ 1 ].xyz, NodeBuffer_823.value[ instanceIndex ][ 2 ].xyz )[ 0u ], mat3x3<f32>( NodeBuffer_823.value[ instanceIndex ][ 0 ].xyz, NodeBuffer_823.value[ instanceIndex ][ 1 ].xyz, NodeBuffer_823.value[ instanceIndex ][ 2 ].xyz )[ 0u ] ), dot( mat3x3<f32>( NodeBuffer_823.value[ instanceIndex ][ 0 ].xyz, NodeBuffer_823.value[ instanceIndex ][ 1 ].xyz, NodeBuffer_823.value[ instanceIndex ][ 2 ].xyz )[ 1u ], mat3x3<f32>( NodeBuffer_823.value[ instanceIndex ][ 0 ].xyz, NodeBuffer_823.value[ instanceIndex ][ 1 ].xyz, NodeBuffer_823.value[ instanceIndex ][ 2 ].xyz )[ 1u ] ), dot( mat3x3<f32>( NodeBuffer_823.value[ instanceIndex ][ 0 ].xyz, NodeBuffer_823.value[ instanceIndex ][ 1 ].xyz, NodeBuffer_823.value[ instanceIndex ][ 2 ].xyz )[ 2u ], mat3x3<f32>( NodeBuffer_823.value[ instanceIndex ][ 0 ].xyz, NodeBuffer_823.value[ instanceIndex ][ 1 ].xyz, NodeBuffer_823.value[ instanceIndex ][ 2 ].xyz )[ 2u ] ) ) ) );
	varyings.v_normalViewGeometry = normalize( ( render.cameraViewMatrix * vec4<f32>( ( object.nodeUniform6 * normalLocal ), 0.0 ) ).xyz );
	modelViewMatrix = ( render.cameraViewMatrix * object.nodeUniform14 );
	v_positionView = ( modelViewMatrix * vec4<f32>( positionLocal, 1.0 ) ).xyz;
	varyings.v_positionViewDirection = ( - v_positionView );
	nodeVar72 = ( render.cameraProjectionMatrix * vec4<f32>( v_positionView, 1.0 ) );
	v_modelViewProjection = nodeVar72;

	// result

	varyings.Vertex = v_modelViewProjection;

	return varyings;

}

How to completely replace all that with your own shader code? I don’t know.

2 Likes