I’ve reported this bug with a simple test case to show the issue. It’s currently triaged as bug IN-37607.
The issue is that materials don’t have the correct shader passes configured at Start/Awake on the first frame after entering Play Mode, or starting a Build. Instead of the materials having the expected shader passes, they’ll have only a single pass, named “<Unnamed Pass 0>”. Let a second pass, and the materials will have the expected passes.
Note that this does not happen in the built-in renderer. Under built-in renderer, accessing the shader passes works as expected even when called on the first frame after entering play mode.
This is a problem for at least one reason: HDRP checks whether a material has the GBuffer pass in order to make some decisions about stencils. But that check will be wrong if it’s performed when entering play mode.
Here’s a simple example script that shows this bug happening. Attach this script to a game object with a renderer, and enter play mode.
public class MatScript : MonoBehaviour
{
public Renderer X;
private void Awake()
{
Debug.LogError("On Awake:");
DisplayMatPasses();
StartCoroutine(DelayedDisplayMatPasses());
}
private IEnumerator DelayedDisplayMatPasses()
{
yield return new WaitForSeconds(1);
Debug.LogError("A second later:");
DisplayMatPasses();
}
private void DisplayMatPasses()
{
foreach (var mat in X.sharedMaterials)
{
for (int i = 0; i < mat.passCount; i++)
{
Debug.LogError(mat.GetPassName(i));
}
}
}
private void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
Scene scene = SceneManager.GetActiveScene();
SceneManager.LoadScene(scene.name);
}
}
}
The console will initially show the “<Unnamed Pass 0>” pass on the material. A second later, it will display all of the expected passes. Reloading the scene will show the expected passes, so it’s only an issue when initially entering play mode.
1 Like
This bug was changed internally to UUM-33303.
It was then promptly closed as “Won’t Resolve”, for the reason: “Active render pipeline is set during the same script Awake when loading the player or entering Play mode.” (I believe it was closed by @aleksandrk )
For one thing, another HDRP team developer (whoever committed the code changes I pointed out in Why does _StencilWriteMaskMV keep changing value (40 -> 42 -> 40, etc...) Starting in 2021.3.17/18? ) is currently trying to access material passes in Start/Awake, or at least they aren’t guarding against the value being “<Unnamed Pass 0>”.
Is the expectation that any time any code accesses a material’s shader passes, developers need to first test to make sure it’s not “<Unnamed Pass 0>”?
The bug I reported was closed without suggesting any workarounds to avoiding running into problems dealing with this. It also raises other biggest questions about what other things we shouldn’t be trying to access during Awake, out of fear that HDRP hasn’t bootstrapped itself yet?
As a workaround, one can check the current render pipeline before doing anything in Awake. If the pipeline is not set yet, the code should wait for the next frame.
That sounds like it breaks the entire concept around the difference between Awake and Start, and the expectations around when specific elements of a project are available. There are things I do in Awake, such that I know that by Start or Update, the class is fully configured. But if I now potentially need to defer things in Awake by one frame, that means everything in Start might need to be deferred by a frame, and that everything in Update needs to test whether Awake was really called yet, otherwise wait a frame before doing anything. This seems like such a disruptive change to the way I expect a Unity project to behave.
Case in point, the issue I linked above ( https://forum.unity.com/threads/why…0-42-40-etc-starting-in-2021-3-17-18.1397830/ ) your own developer isn’t performing that kind of check, and therefore has a bug where they’re misinterpretting material.GetPass() results that are being called on the first frame after entering Play Mode or running a build?
Is this really how HDRP is going to work from now on? That nothing in the pipeline can be trusted in Awake? What else besides shader passes do I need to be worried about not being properly initialized by the time Awake is being called? Is there actually no way to fix this issue?
I’ll check with HDRP folks
1 Like
Curious if this was ever discussed. I’m still not sure whether I’m really expected to be checking for the current render pipeline in various Awake calls just to be confident that HDRP exists.