Title: How to Access instanceMatrix in Custom Vertex Shader with Three.js TSL (InstancedMesh)?

I’m working with Three.js’s latest TSL to create a custom vertex shader for an InstancedMesh . However, I’m struggling to access the instanceMatrix values in the shader. It seems TSL doesn’t yet support the built-in instanceMatrix property directly in the shader’s scope.
Is there any solution? :worried:

1 Like

In r169 I used this construction to get access to instanceMatrix:

const instMat = buffer( this.instanceMatrix.array, 'mat4', this.count ).element( instanceIndex ).toMat4().toVar();

Warning: I haven’t tested it with the latter revisions.
The example of the using:

5 Likes

EDIT: Did not work for me in r174

 const buffy = buffer(instancedMesh.instanceMatrix.array, 'mat4', instancedMesh.count);

  const positionAlter = Fn(() => {
    const instMat = buffy.element(instanceIndex).toMat4().toVar();

fails with errors :frowning:

Here’s what worked for me in r174.

Update March 25 2025

It is afaik impossible I think mostly due to under-the hood magic not exposed. Your best bet is to roll your own attributes. These attributes can then be accessed and updated from both custom CPU-side logic like render loop updates AND inside TSL shader-land logic:

Setup:

// INITIALIZE ATTRIBUTES
// GPU Space For InstanceMatrixes
const insty = storage(new THREE.StorageInstancedBufferAttribute(new Float32Array(totalInstances * 16), 16, instancedMesh.count));
// GPU Space For InstanceColor
const colsty = storage(new THREE.StorageInstancedBufferAttribute(new Float32Array(totalInstances * 3), 3, instancedMesh.count));


// CPU Attribute Acccess Example
for (let i = 0; i < instancedMesh.count; i++) {
   // Setting RGB color to Red per each instance
   colsty.value.array.set([1,0,0],i*3);
}




// GPU Attribute  Access Example
import { instanceIndex } from 'three/tsl'
//...
yourColorNode = Fn(()=>{
    const instanceColor = colsty.element(instanceIndex);
    return vec4(colsty,1);
})
yourInstancedMesh.colorNode=yourColorNode();

Original Answer

import { positionGeometry, Fn, instanceIndex, cameraProjectionMatrix, modelViewMatrix, modelWorldMatrix, storage, mul } from 'three/tsl'
//...
const instanceMatrix = storage(new THREE.StorageInstancedBufferAttribute(
  instancedMesh.instanceMatrix.array, 
  16, 
  instancedMesh.count
));
const vNodeOverride = Fn(()=>{
  return mul(
    cameraProjectionMatrix, 
    modelWorldMatrix, 
    modelViewMatrix,
    instanceMatrix.element(instanceIndex),
    vec4(positionGeometry.xyz, 1)
  )
})
instancedMesh.vertexNode=vNodeOverride();

Crappy hack in terms of performance – needlessly doubles a GPU memory footprint and you can’t use any of the convenience methods built into InstanceMesh but it works.

See issue 30778 where I ramble about TSL accessors for varyings/uniforms/attributes

1 Like

it seems not work in r176

I’ve used my above solution in 177, 178, there are additional footguns I’ve encountered with instancedMesh but the approach for this specifically should work. Can’t remember if I tested in 176 but I assume it does?

There was also a bug fixed in 177 for instancedMesh where now positionLocal.xyz works properly in a custom vertexShader. Not the direct matrix per say but pretty useful.