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?
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:
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
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