Having a spatial shader with a custom uniform parameter, currently it is not possible to set it to a different value per object. To do so, you have to duplicate the material for each object using it.
For example, Godot sets the WORLD_MATRIX uniform to a different value for each object, even if multiple objects share the same material. Something similar could be done for custom uniforms.
A use case would be to render several different meshes with a transparent material, but with the ALPHA value set by the pixel shader to be defined per mesh. Setting the ALBEDO alpha channel in the material works, but affects all other meshes using the same material.
Duplicating the material for each object and then changing the custom uniform value has some drawbacks:
After duplicating the material you can no longer change a material property and have an effect on all objects using it
Do you want a uniform to affect all instances of the object using the material, or just one? You can't have both. There is no possible way that the engine could guess when you change a uniform whether you want it to affect just that object or all objects sharing the same material.
Having many objects with their own material copy might affect performance
The performance impact is small as long as the materials share a shader resource. In that case it is very much like when the internal shader switches WORLD_MATRIX
The engine wouldn't have to guess if you can explicitly specify what you want. You could have the material properties and then separate per-node overrides which will take precedence if present.
What are you envisioning from a UX perspective? Would this exist as a separate layer over Material? or would each uniform have two fields, one for default and one for particular setting?
Also note, you can set a default value in the shader for most uniform types. Then if you use the same shader but make the material unique each material will carry the default value from the shader but you will be able to override it without affecting the others.
Can you set the default values for a shader uniform programatically? Or else how would you set the uniform for all nodes using a material?
I didn't envision any particular UI, and I'm not sure you would put it under the material since it wouldn't make sense as a property of the material. Maybe CanvasItem and Spatial could have a uniform overrides category.
Can you set the default values for a shader uniform programatically? Or else how would you set the uniform for all nodes using a material?
You set it in the shader itself http://docs.godotengine.org/en/latest/tutorials/shading/shading_reference/shading_language.html#uniforms
Maybe CanvasItem and Spatial could have a uniform overrides category.
Im not sure either. This wouldn't work for any spatial or for Particles2D as they both can have multiple materials. It would have to be on a per-material basis. But then you are left with the material having two sets of uniforms, one for shared values, and one for override values.
Maybe there is a better way of doing material inheritence. Like having an "inherets_from" property where you select another material to inheret from, but then any uniform you set in your material will override the one it inherets from.
You set it in the shader itself http://docs.godotengine.org/en/latest/tutorials/shading/shading_reference/shading_language.html#uniforms
The reason I asked is because there doesn't seem to be a way to change the uniform for all users of the material dynamically, does this mean you can't?
EDIT: I mean that you can't do it while using non-default values as overrides in the current state of Godot, since you suggested that as a solution.
But then you are left with the material having two sets of uniforms, one for shared values, and one for override values.
This doesn't make sense because then the properties displayed by the material would have to be different depending which node you're looking at.
Maybe there is a better way of doing material inheritence. Like having an "inherets_from" property where you select another material to inheret from, but then any uniform you set in your material will override the one it inherets from.
That does seem better. You could also have an OverrideMaterial separating out the override behavior for a more compositional style. (I guess that would be called a decorator in terms of design patterns)
I support it
@nagasawamaki Please don't bump issues without contributing significant new information; use the :+1: reaction button on the first post instead.
@Calinou sorry for that.
Let me explain more.
I find this would be useful if we can set the param of shader per object.
If you have experience in UE4, there is something like Material Instance which let user to adjust the material parameters.
Use case: Let say I have some enemies, some are visible to player in a FOV but some are not.
I would like to fade-in/out the enemies when player rotate the FOV. So what I think how to achieve this is I adjust the alpha in albedo of the enemies. But since the enemies share the same material, currently in Godot the alpha will affects all enemies.
So I support this feature
Our equivalent of Material Instance is making material unique per mesh.
Our equivalent of Material Instance is making material unique per mesh.
@Zireael07 Let say in my use case above, if I have lots of enemies, I need to make material of enemies unique one by one? What if I have hundred enemies? I need to make it unique hundred times?
Also, what if the enemies are spawned by code? how can I make the material unique of the enemies spawned by code? Thanks
Also, what if the enemies are spawned by code? how can I make the material unique of the enemies spawned by code? Thanks
You can call .duplicate() on the material resource, or edit the resource in the Inspector and check Local to Scene at the bottom. This way, the resource will always be made unique when you instance the scene.
I think the main gripe in the OP is that you might want some parameters shared and others unique to each object. If you make each material unique then to set a shared parameter you would need to keep track of all the objects and set the parameter individually.
Should a separate issue be opened for CanvasItems? Or does it not really matter since it's planned anyway?
@raymoo it's already done. No need to create a proposal for something that is already implemented in the engine.
What about this comment? https://github.com/godotengine/godot/pull/37949#issuecomment-615243951
It sounded like it would take some time for it to be implemented for CanvasItems. Did he do it since the comment?
Ah. Thanks for pointing that out. My mistake.
I still wouldn't bother making a proposal for it though. A proposal is a lot of work and if it's planned already you'd just waste your time.
Most helpful comment
You can call
.duplicate()on the material resource, or edit the resource in the Inspector and check Local to Scene at the bottom. This way, the resource will always be made unique when you instance the scene.