Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TSL: Using a custom vertexNode is breaking the normalLocal of a BatchedMesh #29393

Closed
Robpayot opened this issue Sep 12, 2024 · 6 comments
Closed
Labels
TSL Three.js Shading Language
Milestone

Comments

@Robpayot
Copy link

Robpayot commented Sep 12, 2024

Description

I'm using TSL with a MeshStandardNodeMaterial on a BatchedMesh. I have a custom vertexNode reusing the logic of BatchNode so I can apply custom bending effect on it later on.

However when doing that the lights of my BatchedMesh are broken (not in the correct direction). When I remove the vertexNode (using the default shader) it fixes it.

Does it mean the vertexNode is overwriting the normalLocal so the fragment doesn't have the correct vNormals anymore? but weirdly I have the normalLocal assigned.

Does it also mean if I want to customise the fragment part I will have to rewrite the whole StandardNodeMaterial fragment shader in the outputNode to get the lights right?

Thank you

Reproduction steps

  1. Using a MeshStandardNodeMaterial on a BatchedMesh
  2. Apply a custom vertexNode
  3. Lights are breaking

Code

const material = new MeshStandardNodeMaterial()
const mesh = new BatchedMesh(50, 4000, 4000, material)
const geometry1 = new BoxGeometry(1.5, 1, .5)
const geometry2 = new ConeGeometry(1, 1, 32)
mesh.addGeometry(geometry1, geometry2)

material.vertexNode = Fn((builder) => {
	// Reusing BatchNode logic
	let batchingIdNode = null

	// WebGL fallback if
	if (batchingIdNode === null) {
		// check if https://github.com/mrdoob/three.js/blob/841ea631018e0bf40c7de1b54811101f77f1e1b3/src/renderers/webgl-fallback/nodes/GLSLNodeBuilder.js#L626
		if (builder.getDrawIndex() === null) {
			batchingIdNode = instanceIndex
		} else {
			batchingIdNode = drawIndex
		}
	}

	const getIndirectIndex = Fn(([id]) => {
		const size = textureSize(textureLoad(mesh._indirectTexture), 0)
		const x = int(id).modInt(int(size))
		const y = int(id).div(int(size))
		return textureLoad(mesh._indirectTexture, ivec2(x, y)).x

	}).setLayout({
		name: 'getIndirectIndex',
		type: 'uint',
		inputs: [{ name: 'id', type: 'int' }]
	})

	const matriceTexture = mesh._matricesTexture

	const size = textureSize(textureLoad(matriceTexture), 0)
	const j = float(getIndirectIndex(int(batchingIdNode))).mul(4).toVar()

	const x = int(j.mod(size))
	const y = int(j).div(int(size))
	const batchingMatrix = mat4(
		textureLoad(matriceTexture, ivec2(x, y)),
		textureLoad(matriceTexture, ivec2(x.add(1), y)),
		textureLoad(matriceTexture, ivec2(x.add(2), y)),
		textureLoad(matriceTexture, ivec2(x.add(3), y))
	)

	const bm = mat3(batchingMatrix)
	const batchPos = batchingMatrix.mul(positionLocal).xyz

	// Now I can apply custom code here
	const transformed = modelViewMatrix.mul(batchPos)
	const mvPosition = vec4(transformed.xyz, transformed.w)

	// Normals
	const transformedNormal = normalLocal.div(vec3(bm[ 0 ].dot(bm[ 0 ]), bm[ 1 ].dot(bm[ 1 ]), bm[ 2 ].dot(bm[ 2 ])))
	const batchingNormal = bm.mul(transformedNormal).xyz
	normalLocal.assign(batchingNormal)

	if (builder.hasGeometryAttribute('tangent')) {
		tangentLocal.mulAssign(bm)
	}

	return cameraProjectionMatrix.mul(mvPosition)
})()

// Positions are good but lights are now broken

Version

0.168.0

@Robpayot Robpayot changed the title TSL: Using a custom vertexNode is breaking the normals of an InstancedMesh (and BatchedMesh) TSL: Using a custom vertexNode is breaking the normals of a BatchedMesh Sep 12, 2024
@Robpayot Robpayot reopened this Sep 12, 2024
@Robpayot
Copy link
Author

Sorry I reopened it because I found a fix for InstancedMesh using normalLocal.assign() but not for BatchedMesh it still doesn't work

@Robpayot Robpayot changed the title TSL: Using a custom vertexNode is breaking the normals of a BatchedMesh TSL: Using a custom vertexNode is breaking the normalLocal of a BatchedMesh Sep 12, 2024
@Mugen87 Mugen87 added the TSL Three.js Shading Language label Sep 16, 2024
@Robpayot
Copy link
Author

Robpayot commented Sep 18, 2024

I added a jsfiddle example here, I hope this can help:
https://jsfiddle.net/dfw7hroL/

You can see here the lighting is broken when I use my custom vertexNode (I used a directionnal light), if I comment this line : material.vertexNode = customVertexNode the light is fixed

Screenshot 2024-09-18 at 08 17 32

@Robpayot
Copy link
Author

Robpayot commented Sep 19, 2024

I found a fix using const varNormalLocal = varying(vec3(0)), then I assign the normalLocal to it in the vertexNode, and just apply it to the material.normalNode = transformNormalToView(varNormalLocal). It seems to work now, here is an example:

https://jsfiddle.net/jh4wvyd7/1/

Capture d'écran 2024-09-19 084352

@Makio64
Copy link
Contributor

Makio64 commented Sep 29, 2024

When adding a point light to the scene, the lights seems totally broken again : https://jsfiddle.net/oc0gkyqa/8/
Screenshot 2024-09-30 at 06 48 53

@RenaudRohlinger
Copy link
Collaborator

@Makio64 To handle lights you also need to update the positionView accodingly: positionView.assign(transformed).

https://jsfiddle.net/0Lc2jbg6/10/

@Makio64
Copy link
Contributor

Makio64 commented Sep 30, 2024

@Makio64 To handle lights you also need to update the positionView accodingly: positionView.assign(transformed).

https://jsfiddle.net/0Lc2jbg6/10/

@RenaudRohlinger Merci! This was bugging me so hard! 🙇‍♂️

@Mugen87 Mugen87 closed this as completed Nov 7, 2024
@Mugen87 Mugen87 added this to the r171 milestone Nov 7, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
TSL Three.js Shading Language
Projects
None yet
Development

No branches or pull requests

4 participants