Skip to content

Comments

TSL instancePositionNode#32873

Open
PoseidonEnergy wants to merge 1 commit intomrdoob:devfrom
PoseidonEnergy:enhancement/tsl-instance-position-node-1
Open

TSL instancePositionNode#32873
PoseidonEnergy wants to merge 1 commit intomrdoob:devfrom
PoseidonEnergy:enhancement/tsl-instance-position-node-1

Conversation

@PoseidonEnergy
Copy link
Contributor

Related issue: #32465

Description

This PR adds instancePositionNode to NodeMaterial to allow for accessing or setting positionLocal immediately after it is transformed by the instance matrix.

@github-actions
Copy link

📦 Bundle size

Full ESM build, minified and gzipped.

Before After Diff
WebGL 357.49
84.84
357.49
84.84
+0 B
+0 B
WebGPU 622.71
172.91
622.95
172.95
+247 B
+38 B
WebGPU Nodes 621.31
172.67
621.56
172.71
+247 B
+43 B

🌳 Bundle size after tree-shaking

Minimal build including a renderer, camera, empty scene, and dependencies.

Before After Diff
WebGL 490.47
119.9
490.47
119.9
+0 B
+0 B
WebGPU 693.82
188.21
694.07
188.24
+247 B
+30 B
WebGPU Nodes 643.2
175.31
643.45
175.34
+247 B
+34 B

@sunag
Copy link
Collaborator

sunag commented Jan 28, 2026

I'm thinking of adding a .transformNode so we can handle the vertex transformations, this should also be fix the #32872, so we can remove the .toStack() syntax as well, I was talking to @brunosimon a few days ago about this.

I'm still undecided about the names... but the concept should be similar

import { transform, instance, skinning } from ...

material.transformNode = Fn( ( { object } ) => {

	let finalTransform = transform;

	// transform is a struct or object with position,normal,tangent,bitangent

	if ( object.isSkinnedMesh ) finalTransform = skinning( finalTransform );
	if ( object.isInstancedMesh ) finalTransform = instance( finalTransform );
	// ...

	return finalTransform ;

} )();

or maybe only

import { instance, skinning } from ...

material.transformNode = Fn( ( { object } ) => {

	if ( object.isSkinnedMesh ) skinning( object );
	if ( object.isInstancedMesh ) instance( object );
	// ...

} )();

In this sense, we have access to any stage of vertex transformation, like, position, normal, etc.

@PoseidonEnergy
Copy link
Contributor Author

PoseidonEnergy commented Jan 28, 2026

@sunag Looks good to me. However, if I call this:

if ( object.isInstancedMesh ) finalTransform = instance( finalTransform );

Does this create a second InstanceNode in addition to the one that already gets created in NodeMaterial.js? See this code snippet:

if ( ( object.isInstancedMesh && object.instanceMatrix && object.instanceMatrix.isInstancedBufferAttribute === true ) ) {
instancedMesh( object ).toStack();
}

I'm worried about unnecessary creation of extra InstancedBufferAttribute objects and everything that goes along with the instance matrix. Would calling instance(object) double-apply the instance matrix in the shader?

@brunosimon
Copy link
Contributor

That would be so useful and make learning a lot easier.
Does positionLocal still makes sense?
Shouldn't it be something like positionTransformed after this node is applied?

@PoseidonEnergy
Copy link
Contributor Author

PoseidonEnergy commented Jan 30, 2026

That would be so useful and make learning a lot easier. Does positionLocal still makes sense? Shouldn't it be something like positionTransformed after this node is applied?

In my opinion, positionLocal should already be the position of an instance after the matrix has been applied. This is because it is identical to positionGeometry when accessed before the transformation. Simply moving the material.positionNode property to insert shader code after the transform would not result in a loss of functionality. If a developer wants to know what positionLocal was before it was transformed, they can just use positionGeometry. So, introducing another node like positionTransformed would just be taking the place of what positionLocal should be in the first place.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants