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 at this time is to not use the built-in instanceMesh utility and instead roll your own attributes like so:

Setup:

// 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));

These attributes can then be accessed and updated from both custom CPU-side logic like render loop updates AND inside TSL shader-land logic:

CPU Access 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 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