Stencil overwrites mark scene dirty on load

Avatar
  • updated
  • Under Review

I had the problem for quite some time now, that my scenes always got dirty as soon as I opened them. I finally took the time to take a look what is causing it: The stencil overwrite on any shapes component auto-changes the scene at every opening.

Image 373

This alone will mark the scene dirty every time it is opened. This is especially annoying when using a vcs. Only the file id and position in the .unity yaml file is changing.

Image 374

Also happens for me for the gallery scene.

Reporting a bug? please specify Unity version:
2021.1.4f1
Reporting a bug? please specify Shapes version:
3.2.3
Reporting a bug? please specify Render Pipeline:
URP
Avatar
Freya Holmér creator
  • Under Review

yep, this has been an issue for a long time, and I honestly don't know what the best solution is right now. it's a bit of a serialization nightmare~

either I have a material cache in each scene, or a global one in your assets, but then it's going to be tricky to figure out how to delete materials you're no longer using. It might be possible to just tell Unity not to serialize the custom materials at all, and regenerate on load, but I recall that having issues too where I'd get situations where it would need a material but it isn't present.

I want to fix this! it's just been a low prio since it's more of an annoyance than a game breaking thing, and because I don't know of a solid solution yet

Avatar
Johannes Deml

Thanks for the response! I guessed you already knew this annoyance. I totally understand the priority here.


Am I right in the believe, that the material cache in scene is the current implementation? I haven't completly thought this through, but couldn't you use the data in `rnd.Materials` instead of calling `PopulateAll` if they are present? I guess there would be edge cases when switching between instanced and non-instanced materials, but maybe this could be a simple solution instead of creating a caching asset?

Avatar
Freya Holmér creator
Quote from Johannes Deml

Thanks for the response! I guessed you already knew this annoyance. I totally understand the priority here.


Am I right in the believe, that the material cache in scene is the current implementation? I haven't completly thought this through, but couldn't you use the data in `rnd.Materials` instead of calling `PopulateAll` if they are present? I guess there would be edge cases when switching between instanced and non-instanced materials, but maybe this could be a simple solution instead of creating a caching asset?

currently there's no cache, they only exist as references in the renderer itself already, like you suggest, so I think what happens is that they technically serialize to where the asset lives (scene or prefab), but somehow something goes wrong somewhere, so it keeps re-serializing, and you now get a changed scene

Avatar
dawn

was a solution ever found for this? it's a bit of a nightmare with constant scene dirtying and merge conflicts

Avatar
Freya Holmér creator
Quote from dawn

was a solution ever found for this? it's a bit of a nightmare with constant scene dirtying and merge conflicts

not yet I'm afraid

Avatar
daniel rinaldi

HelIo, 

I was facing a similar issue where I work. The scene would get dirtied everytime we would run the scene in the editor. I "fixed" it in a way with the following solution:

I added the following to ShapesRenderer.cs:
```csharp
[SerializeField]
bool shouldUpdateMaterialPropertiesInEditor = false;

public bool ShouldUpdateMaterialPropertiesInEditor {
    get => shouldUpdateMaterialPropertiesInEditor;
    set => shouldUpdateMaterialPropertiesInEditor = value;
}


private protected void UpdateMaterial() {
#if UNITY_EDITOR
    if (IsUsingUniqueMaterials && !UnityEditor.EditorApplication.isPlaying && 

        !shouldUpdateMaterialPropertiesInEditor)
        return;
#endif

// ...

}


internal void UpdateAllMaterialProperties()
{
#if UNITY_EDITOR
    if (IsUsingUniqueMaterials && !UnityEditor.EditorApplication.isPlaying && 

        !shouldUpdateMaterialPropertiesInEditor)
        return;
#endif

// ...

}

```

I also modified ShapesRendererEditor.cs with the following:

```csharp
SerializedProperty propShouldUpdateMaterialPropertiesInEditor = null;


protected void BeginProperties( bool showColor = true, bool canEditDetailLevel = true ) 

{

// ...

if( uniqueCount > 0 ) {
    using (ShapesUI.Horizontal)
    {
        GUIContent icon = EditorGUIUtility.IconContent("console.warnicon.sml");

        GUILayout.Label(icon);

        string note = "Note: Current configuration will cause scene to be dirtied when entering and exiting 

    play mode. " +
    "For now, the fix is to toggle off shapes material updates in edit mode. Use the button on the right to " +
"toggle it on for previewing while designing but don't forget to turn it off when done.";

        GUILayout.TextArea(note, wrapLabel);

        ShapeRenderer shapeRenderer = target as ShapeRenderer;

        string onOff = shapeRenderer.ShouldUpdateMaterialPropertiesInEditor ? "ON" : "OFF";

        if (GUILayout.Button(onOff, EditorStyles.miniButton))
        {
            if (shapeRenderer.ShouldUpdateMaterialPropertiesInEditor)
                propShouldUpdateMaterialPropertiesInEditor.boolValue = false;
            else
                propShouldUpdateMaterialPropertiesInEditor.boolValue = true;
        }
    }

    //...

}

```

Example in editor:

Image 809

Image 810

Hopefully this helps someone else.

Regards,

Daniel

Avatar
ido
Quote from daniel rinaldi

HelIo, 

I was facing a similar issue where I work. The scene would get dirtied everytime we would run the scene in the editor. I "fixed" it in a way with the following solution:

I added the following to ShapesRenderer.cs:
```csharp
[SerializeField]
bool shouldUpdateMaterialPropertiesInEditor = false;

public bool ShouldUpdateMaterialPropertiesInEditor {
    get => shouldUpdateMaterialPropertiesInEditor;
    set => shouldUpdateMaterialPropertiesInEditor = value;
}


private protected void UpdateMaterial() {
#if UNITY_EDITOR
    if (IsUsingUniqueMaterials && !UnityEditor.EditorApplication.isPlaying && 

        !shouldUpdateMaterialPropertiesInEditor)
        return;
#endif

// ...

}


internal void UpdateAllMaterialProperties()
{
#if UNITY_EDITOR
    if (IsUsingUniqueMaterials && !UnityEditor.EditorApplication.isPlaying && 

        !shouldUpdateMaterialPropertiesInEditor)
        return;
#endif

// ...

}

```

I also modified ShapesRendererEditor.cs with the following:

```csharp
SerializedProperty propShouldUpdateMaterialPropertiesInEditor = null;


protected void BeginProperties( bool showColor = true, bool canEditDetailLevel = true ) 

{

// ...

if( uniqueCount > 0 ) {
    using (ShapesUI.Horizontal)
    {
        GUIContent icon = EditorGUIUtility.IconContent("console.warnicon.sml");

        GUILayout.Label(icon);

        string note = "Note: Current configuration will cause scene to be dirtied when entering and exiting 

    play mode. " +
    "For now, the fix is to toggle off shapes material updates in edit mode. Use the button on the right to " +
"toggle it on for previewing while designing but don't forget to turn it off when done.";

        GUILayout.TextArea(note, wrapLabel);

        ShapeRenderer shapeRenderer = target as ShapeRenderer;

        string onOff = shapeRenderer.ShouldUpdateMaterialPropertiesInEditor ? "ON" : "OFF";

        if (GUILayout.Button(onOff, EditorStyles.miniButton))
        {
            if (shapeRenderer.ShouldUpdateMaterialPropertiesInEditor)
                propShouldUpdateMaterialPropertiesInEditor.boolValue = false;
            else
                propShouldUpdateMaterialPropertiesInEditor.boolValue = true;
        }
    }

    //...

}

```

Example in editor:

Image 809

Image 810

Hopefully this helps someone else.

Regards,

Daniel

Just wanted to +1 this issue. Also wanted to say @ daniel, wow! Your workaround is great, thank you.

In my case, I used your code workaround to set shapes with custom sorting and depth settings (setting stuff to OFF). In case anybody else is still getting dirty scene issues: For whatever reason I also had to go over objects with default settings- set them their sorting & depth to something random, and then reset them back to default. Doing both now gives me a clean scene.