WebGPU NodeMaterial: How do I sample material textures in UVs other than model UV?

I’m currently trying to create a custom Material / LightingModel using the NodeMaterial implementation (namely, MToon for three-vrm.)

I have bumped into an issue that, when I create MaterialReferenceNode in texture type, I cannot sample the referenced texture with irregular UVs (specifically, I want to sample the texture in MatCap UV.)
Do you have any idea to achieve this?

@sunag Sorry for the ping but you are probably the only person able to help me (not in a rush, don’t worry)

LightingModel is not designed to replace UV, but this could work by extending some NodeMaterial class.

class ToonNodeMaterial extends MeshBasicNodeMaterial {

	setup( builder ) {
		builder.setContext( { ...builder.context, 
			getUVNode: ( /*reqNode*/ ) => {
				return uv(); // return a custom uv
		} );	
		return super.setup( builder );


In this case, the texture() that does not have UV defined will be replaced by the one defined in the context.

@sunag Sorry for the ping but you are probably the only person able to help me (not in a rush, don’t worry)

Feel free to ping me if you need to.


Thank you for the reply!

Yes, I’m already extending NodeMaterial and LightingModel and the material already uses the default uv for ordinary map textures like map or emissiveMap.
AND I need another uv for the matcap use. Looking at the codes you’ve mentioned,

I noticed that TextureNode has a node inlet .uvNode, and MaterialReferenceNode has a property .node which is an actual TextureNode under the hood.
If I change the .uvNode like this it samples using matcap uv.
Is this an intended way to use this?

export const refMatcapTexture = Nodes.materialReference('matcapTexture', 'texture');
refMatcapTexture.node.uvNode = Nodes.matcapUV.mul(1.0, -1.0).add(0.0, 1.0);

You can try something like this too.

export const refMatcapTexture = materialReference( 'matcapTexture', 'texture' ).context( {
	getUVNode: ( /*reqNode*/ ) => {
		return matcapUV.mul( vec2( 1.0, -1.0 ) ).add( vec2( 0.0, 1.0 ) );
} );

This manipulation can also be controlled within setup().

1 Like

Ahhh, ContextNode exists, interesting.
Is the builder.context an object that we can put any stuff we need to use to build nodes?

Each Node can use builder.context differently, this helps to apply settings that cannot be passed at declaration time, creating a layer in which the Node can retrieve the ideal settings for that flow.


for record:

r159 will change the context.getUVNode to context.getUV.