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 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
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.