I set a texture on the material of a DecalProjector from script using material.SetTexture. No result. I check the inspector for the material and I clearly see the texture that I’ve just set. I click ANY setting in the inspector for the material and BOOM the texture is applied and I see the result in the scene.
So I looked at DecalProjectorEditor.cs in the hope that I would find some magic function that is called around EditorGUI.EndChangeCheck() that would update some magic undocumented state in the decalprojector. But I found none.
So. What is the corret way of setting the texture of a decal projector from script in HDRP (v. 12.1)?
EDIT: I also tried calling OnValidate on the DecalProjector using reflection after setting the texture on the material. No luck.
hey, if you set a material property at runtime, you need to enable its associated keyword for Unity to know which shader variant to use.
If you’re using the newest version of HDRP, there’s been a new static function that helps you with that.
What it does, is the same that what is done when fiddling with inspector, i.e go through the properties of the material and adds/remove missing keywords so that Unity can find the proper variant.
using UnityEngine.Rendering.HighDefinition;
using UnityEditor.Rendering.HighDefinition;
...
HDMaterial.ValidateMaterial(this.GetComponent<DecalProjector>().material);
On older version, you can just enable the proper keyword, “by hand”. In your case it would something like that.
using UnityEditor.Rendering.HighDefinition;
...
this.GetComponent<DecalProjector>().material.EnableKeyword("_COLORMAP");
If you want to find another keyword, you can use the editor in debug mode when selecting a material and see what keyword is enabled in editor so that you can activate them at runtime.
And it is not specific to HDRP at all, it will behave the same way in Built-in for example.
Thanks @chap-unity that is exactly what I was looking for. I just had to enable “_NORMALMAP” and “_MATERIAL_AFFECTS_NORMAL” using material.EnableKeyword().
I’m on HDRP 12.1 so no luck there. And is it not part of the UnityEditor assembly? How would that help at runtime?
I have used Unity for years, and somehow this case surprises me. Perhaps because I tend to access materials indirectly through components that use them, or because in most cases I write my own components that manage custom materials/shaders (and their keywords/variants). From a UX perspective, keeping track of which keywords to enable and disable really should not be my problem as a user of a build-in tool. I would prefer to set decal properties on the decal projector, not the material. However, I do understand it would be misleading if a property I set on the decal projector happen to be unsupported by the particular material/shader it holds. Perhaps there is some kind of layer missing for runtime. Something that does the job of the component inspector; enabling and disabling keywords.
I didn’t want my texture generating MonoBehaviour to deal with this. It should be ignorant to the reciever and just send out the texture using a UnityEvent. So I ended up writing this little helper script to decouple the code. I still think the job of keeping track of keywords should not be put on users, and so I consider this script a necessary evil until a more user firendly solution is found.
It will help in editor in play mode because, it will compile the shader variant on the fly and then be able to find it because the keyword are properly setup, so you’ll get your material displayed as expected.
However, when bulding a standalone, you need to have the shader variant already present (having a material using that variant in your asset) because it won’t be able to compile the variant on the fly, so no shader variant present and no way to find it will result in missing material feature.
I completely agree with that, and that is the reasons behind the “HDMaterial.ValidateMaterial” function that does exactly what the inspector is doing when you use a new shader feature (read, add a normal map) to avoid users to do it themselves.
Sorry to sound critical, but this “solution” cause more problems than it solves. Tell me this …
Why was this solution designed to only work in the editor? This means all the solutions I build on top will also only work in the editor.
Why was this solution made specifically for HDRP? Is this a a temporary fix while we wait for a global cross-RP solution … or can I expect to see novel solutions for every RP? Will I see UMaterial.ValidateMaterial? Unity is already being torn into what feels like three very separate and incompatible engines. Please tell me how this is not another example of this.
The point of the forum is to get feedback from the community, so it’s okay to be critical !
This solution is designed to work only in editor because we don’t have any other choice. Unity (not only in HDRP) forbids to compile shader variants in a standalone because of performance reasons (it can cause player freeze etc…).
For this point, I personally don’t have the big picture, maybe you will have better luck elsewhere in the forum rather than on the HDRP specific section of the forum.
I was under the impression that all possible shader variants are compiled at build time, while at build runtime the correct shader is chosen by evaluating the enabled and disabled keywords. How else would a simple script like the one I posted above work when the keyword states are unknown at build time?
This only adds to my fear that Unity is becoming departmentalised to the point where no one knows what’s happening next door. Each department may be solving the exact same problem, but invent their own novel solution. Meanwhile the user has to suffer the consequence, and learn all the solutions. This kills creativity, because energy is wasted on figuring out how to do things, rather than iterating on an idea.
It is painful to watch how an engine I love for it’s simplicity is becoming unnecessarily complex. Not because people used to be smarter, but perhaps because they sit in isolated silos and don’t coordinate.
Unity will compile at build time only the “needed” variants for your build, not every possible variants.
So, shader variants references indirectly by the scenes in you build settings and addressable assets/resources are taken into account. Some additional keywords are also taken into account under the hood (like the normal ones I think).
Every other variant defined by a keyword only in the build will not exist.
Unity has now grown to a company with a few thousand people, it’s unrealistic to think that everybody knows about everything done by all the other ones.
Thank you, this is useful. What is the equivalent for compute shaders?
If all coordination at Unity is relying on everyone talking with everyone in the cantina, then that would explain some of the recent design decisions :p.
Joke aside, as a user, I do expect features that belong to the core engine to reside in the core engine. With the current scale of Unity, this is of course an organisational problem, and not anyone’s fault in particular. @chap-unity 's very honest answer “I personally don’t have the big picture”, is of course valid. Hopefully, someone at Unity has the big picture … but I would not expect the same people to be capable of making a good decision on whether something like HDMaterial.Validate really should be Material.Validate. You, the developers, have to raise a flag when you see something that could perhaps be relevant to other departments. And of course this only works if there is a efficient organisational structure in place. I rather want one well designed engine with fewer features and fewer updates, than three engines.