Per Object Uniforms

OK so I have successfully been able to extend materials to use the same image for diffuse/normal/specular maps. My next step was to use the same image also for all diffuse variants.

This is an example image: https://www.titansoftime.com/stitchtextures2/118_2048.jpg

I got this working by cloning the cached base material. The clone method had some draw backs. For one initial scene rendering took forever. Like way too long. So to get around this I used a method that I found in a discussion on github regarding per object uniforms.

This SO post contains a similar question. WestLangley’s solution was to clone the material and not worry about it. This may be ok in small little demo’s but in large applications it’s not ideal on the CPU side although GPU side seems ok.

The second solution from Elias (which I also read about on github here: https://github.com/mrdoob/three.js/issues/9741) is imo the better way to go.

Problem… I cannot seem to get this to work correctly. With only one object being rendered at a time, it works fine. But when two objects sharing a material but with different uniforms set by onBeforeRender, it breaks down.

Here is a live demonstration (pan the camera to screen left, so that only the left most Mesh is on screen and you will see what I mean).

https://jsfiddle.net/titansoftime/Ley8j7k4/

What am I doing wrong? I’ve tried and tried.

I’ve added a per mesh uniform solution here Chainable onBeforeCompile + Uniforms access (per Mesh)

You can also use just one material for all meshes and store the per-mesh properties in the meshes.

Hmm this example appears to be broken: https://codepen.io/Fyrestar/pen/ymjqMm

While no doubt this is awesome (I’ll probably wind up using it), I would like to see what is going wrong in my demo.

Also, that grass texture in your plugin looks pretty… pretty familiar :wink:

Thanks, it was a minor change after the latest update, fixed it.

Yeah i used the linked fiddle as template, for a example usecase :smile_cat:

Assigning uniforms on the fly is a little tricky, i described it in the thread, in order for all objects having uniforms assigned your plugin should use the object passed in the compile callback and use it’s properties as initial uniform value. You can also not do this, but it means the first mesh using the material will not have the values assigned for the first frame. The addon basically sets the uniforms directly as THREE does internally, since standard materials don’t have a exposed uniforms object.

Edit: It seems in your example the uniforms are only set once, then the next calls will stay with these values, i had a similar result at the beginning when i made the plugin

Hmm, I though this would set the uniform per object each frame:

mesh.onBeforeRender = function(renderer, scene, camera, geometry, material){
	
	if( this.userData.customUniforms ){				
		
		if( material.userData.shader ){		

			for( var name in this.userData.customUniforms ){
				
				material.userData.shader.uniforms[name].value = this.userData.customUniforms[name];															
			
			}
			
		}
		
	}
	
};

Am I misunderstanding this?

jsfiddle

While your plugin is super cool, I would like to have this working in “raw” three.js. I probably will wind up using your plugin though. It’s too bad onBeforeRender doesn’t just work out of the box without adding frame sync operations and such.

The issue seems that only ShaderMaterial is able to do this with uniformsNeedUpdate i’ve set on your material isShaderMaterial and uniformsNeedUpdate to true and it works, though this could cause side effects since standard materials are different from ShaderMaterial.

https://jsfiddle.net/Fyrestar/xczvwdf6/1/

The plugin already is designed for being used with a plugin style for clean managed code and chainable what it’s major purpose is about.

In this example i made a new mesh class with per-object uniforms:
https://codepen.io/Fyrestar/pen/XvYWXW

1 Like

Oof… hacky. But it works! Although with forcing a reload of uniforms every object, I may be defeating the whole point of this which was to improve performance. I guess using onBeforeRender for per object uniforms is alone not a complete solution.

Thanks for looking into this. I’ll also take a stab at implementing your plugin. My primary concern of course is three.js pushing a change that breaks it.

Yes, in the plugin you only update the uniforms that change in the render callback.

It patches THREE without any conflicts, i highly doubt they change something about onBeforeCompile, but if i’d adapt it as long as it doesn’t cover all you can do with the plugin, especially chaining shader plugins in a modular way, having various kind of features patched into one material.

When you include the plugin and call THREE.MaterialCallback.use() it will assign THREE.MaterialCallback to the prototype of THREE.Mesh and THREE.SkinnedMesh, you can do that manually too if you want, THREE calls a empty function anyway. If you need to implemented onBeforeRender yourself somewhere just call THREE.MaterialCallback with the parameters. You can find all relevant details in the thread though.

1 Like

Yea, thanks man. I’m going to use your plugin.

1 Like

I got it integrated and it works perfectly! Good stuff.

One question, why is the header shared between both shaders? I had to separate mine to silence console warning about adding attributes to the fragment shader. No big deal at all though of course.

1 Like

Can you elaborate on what’s going on here?
Several onBeforeRender encounter the same material and you want to copy the values into the same uniforms?

@pailhead this topic is solved

@titansoftime what header do you mean?

curious about the use case

Using different uniform values per mesh with the same material

Yes. I’m curious why do this? We’re not copying values into the same materials over and over, but instead make copies of materials with their own colors and values, when working with regular materials.

As the title suggests, for per-mesh uniform values without having a lot materials, it’s also easier to deal with instead manually assigning them. It also saves unecessary uploads of other uniforms

Not sure if it’s all that easier to deal with :slight_smile: there used to be a dynamic uniform class but it got nuked and I didn’t quite like it. This wouldn’t be an issue if there was smarter about diffing uniforms and batching stuff?

I didn’t meant the experimental approach of the OP, i mean via the plugin system. It’s easier to setup and better for code managment. Like in this example, the THREE.Mesh class gets extended with the per-mesh values stored directly on the mesh. It depends on if there are different values per-mesh expected.

Sorry, I should have been more specific =]

I was referring to the header parameter of the object send to THREE.patchShader.

image

Oh that’s the other plugin :smile:

The header property is just for code that is supposed to be the same on vertex and fragment code like varyings or similar. It is prepended to both, you souldn’t declare vertex shader related things here like attributes, for vertex specific you can always insert at #include <common>, this line is available on all type of materials.