@Mugen87 @sunag
I regularly see devs in the three.js community asking for a way to either directly access the instance matrix in TSL for an instance in an InstancedMesh, or simply just the ability to access positionLocal AFTER it has been transformed by the instance matrix. I am one of those who really really needs something like a material.instancePositionNode property.
I am aware of the tsl.instance() function described here:
dev ← sunag:dev-improve-instance
opened 08:04PM - 16 Nov 24 UTC
Related issue: https://github.com/mrdoob/three.js/issues/29071
**Description*… *
Introduce `instance()` for custom use.
```js
mesh = new THREE.Mesh( geometry, material );
mesh.count = count;
instanceMatrix = new THREE.InstancedBufferAttribute( new Float32Array( count * 16 ), 16 );
instanceMatrix.setUsage( THREE.DynamicDrawUsage );
mesh.material.positionNode = Fn( ( { object } ) => {
// object is the mesh here
// .append() will run instance() immediately, appying instanceMatrix transform in positionLocal and normalLocal
// this way you can get positionLocal before or after instance(()
instance( object.count, instanceMatrix ).append();
return positionLocal;
} )();
scene.add( mesh );
// update matrix
dummy.matrix.toArray( instanceMatrix.array, i ++ * 16 );
```
However, doesn’t that cause a re-upload of the same instance matrix array?
Are there plans for adding something like material.instancePositionNode so we can just insert shader code immediately after the transform has been applied? If not, are there plans for it?
Here are just a few of the requests I keep seeing pop up:
opened 07:26AM - 06 Aug 24 UTC
closed 06:28PM - 07 Nov 24 UTC
Documentation
### Description
I coudnt find the right way to access or use instance propertie… s in TSL from the doc ( [Three.js-Shading-Language](https://github.com/mrdoob/three.js/wiki/Three.js-Shading-Language) ) or examples.
Would be nice to get the explanation on how to access to the `ID` and `instanceMatrix` / `instanceColorMatrix` and i would be happy to create simple examples and update the documentation.
### Solution
- Update the doc for TSL including accessors for instance / batch
- Add minimal examples : The color of the material change depending of the x y z axis of the instance
### Alternatives
Another minimal example : the scale of the instance change depending of the luminosity of the instanceColorMatrix
### Additional context
_No response_
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?
opened 06:18AM - 03 Dec 25 UTC
Enhancement
TSL
### Description
Related to the discussion:
https://discourse.threejs.org/t/prop… osal-post-instancematrix-vertex-transformation-hook-for-instancedmesh-batchmesh/88362/7
In Three.js (TSL / WebGPU) vertex-level transforms like wind/displacement/animations cannot be applied *after* the instanceMatrix. positionNode and vertexNode run before instanceMatrix, which prevents consistent transformed-space effects across instances.
- instanceMatrix is applied in InstanceNode/BatchNode, but instanceMatrixNode is not exposed.
- positionNode/vertexNode hooks run before instanceMatrix.
- As a consequence, post-instance transforms are awkward/impossible to write reliably.
Otherwise, it would be very practical to also expose instanceMatrixNode in BatchedMesh, with the same color varyingProperty, to facilitate material compatibility between InstancedMesh and BatchedMesh, especially when batching InstanceMesh.
### Solution
1) Expose builder.instanceMatrixNode in InstanceNode and BatchNode so materials can read it.
2) Add optional material hook like _instancePositionNode_
I implemented in my project a local patch that:
- sets builder.instanceMatrixNode in InstanceNode/BatchNode setup
- calls material.instancePositionNode when defined
Tested ok in my project with lighting, shadows, reflection, refraction, fog, and postProcessing (v180).
Not tested with WEBGL / WEBGL2 fallback yet.
In the THREE.InstanceNode.prototype.setup function, after
`this.instanceMatrixNode = instanceMatrixNode`
add :
`builder.instanceMatrixNode = instanceMatrixNode`
At the end of THREE.InstanceNode.prototype.setup and THREE.BatchNode.prototype.setup, add:
```
if ( builder.material.instancePositionNode ){
positionLocal.assign( builder.material.instancePositionNode )
}
```
In the THREE.BatchNode.prototype.setup, add:
```
this.instanceMatrixNode = batchingMatrix
builder.instanceMatrixNode = batchingMatrix
varyingProperty ( 'vec3', 'vInstanceColor' ).assign( color ) // or rename vBatchColor as vInstanceColor ?
```
**Why this helps**
Enables proper world-space vertex effects after instance transform
Avoids hacks (double matrix multiply or CPU shadow proxies)
Keeps shadow/light consistency
**Example of use:**
```
myMaterial.instancePositionNode = /*#__PURE__*/ Fn( ( builder ) => {
const { object, instanceMatrixNode }=builder
// get the local position transformed by instanceMatrixNode
const pos=positionLocal.toVar()
// some deal with the position in instance space
pos.yz.addAssign( myWindNode.yz )
// some deal with the normal in instance space
normalLocal.assign( normalLocal.mul( myPerturbNormalNode ).normalize() )
// some deal with the color after the instance color has been applyed
varyingProperty( 'vec3', 'vInstanceColor' ).mulAssign( myCustomColor )
// some deal with uv and the instance matrix with stretched scale correction according to instance space
const getInstanceScale = vec3( length( instanceMatrixNode[0].xyz ), length( instanceMatrixNode[1].xyz ), length( instanceMatrixNode[2].xyz ) )
myCustomUV.assign( makeTriplanarUV( positionGeometry, normalGeometry, getInstanceScale ) )
// return the positionLocal
return pos
})()
```
**Request**
Would the core team consider adding official instancePositionNode hook and exposing instanceMatrixNode to NodeMaterial pipelines?
Thank you — happy to provide more tests or a PR if the team is interested.
### Alternatives
Right now the only alternative is to override InstanceNode.prototype.setup() and BatchNode.prototype.setup() in my local project. This lets me expose instanceMatrixNode and apply post-instance transformations, but it’s fragile and incompatible with upstream changes. It also forces maintaining a custom patched version of THREE.JS.
### Additional context
_No response_
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 instanceMatri…
Yes, you’re right. And we also need to think about WebGL backward compatibility, which was never designed for that.
It’s great to see that there are such dedicated people willing to carefully answer questions from newcomers like me.
I’ll see soon if I can play around with GitHub and suggest a clearer improvement.
Thank you for your clear answers.
In the meantime, for those who might be interested, here’s a less disruptive temporary hack that works according to my latest tests, with lighting,…
Since the related issue at GitHub is still open, we consider this as a TODO. We just have a lot of tasks on our plate so certain features are implemented at a later point.