为什么在播放模式结束时不会重置对天空盒 Material 的脚本更改?

Why do scripting changes to the Skybox Material not reset when play mode over?

My Unity app animates the scene's Skybox Material Exposure 属性 over time (based on audio). The Material asset in my project file has Exposure=1 (initial value).这很好用。

When I play the app inside Unity:

  1. Before play, I select the Material in Project (to see what's happening),
  2. Play the app in Unity,
  3. As soon as app starts, the Material's Exposure is set to a very low value (as expected),
  4. The Skybox Exposure animates as expected (i.e., Skybox is changing to the music),
  5. The Exposure value (in Inspector) does not change after the first change at start (#3), during the play (seems odd),
  6. When I exit play mode, the Exposure (in Inspector) is set to the last value during play (which is not displayed in the Inspector while 运行).

==> I expected the Material to return to its pre-play values after exiting.

IMPORTANT: If I try this same experiment with say a Sphere radius (no scripting though), and I manually change the sphere's radius while playing, when I exit play mode it resets (as expected) to its original pre-play value.

Clearly, I am missing something very core to Unity. I've read everything I can find & still lost. (Wondering if the issue is default Hideflags on the scene's skybox or something similar.)

Scene controller script that changes skybox.material.exposure each frame:

public class AnimateSkyboxFromAudio : BaseAnimateFromAudio {
    protected override void Start() {
         base.Start ();
    }

    protected override void MyUpdate () {
        float rms = GetAttrByName (AudioAnalyzer.RMS);
        RenderSettings.skybox.SetFloat ("_Exposure", rms * 5);
    }
}

I expected the Material to return to its pre-play values after exiting.

RenderSettings.skybox 与其他具有 material 的游戏对象的工作方式不同。它 returns 共享 material 引用 不同于 Renderer.material 在其 material 属性 时返回的唯一 material已访问。

因此,您必须在修改 material 之前对其进行备份。单击停止时,将备份 material 分配回 RenderSettings.skybox。这些都可以在 Start()OnDisable() 函数中完成。您通过使用 Material 参数调用 Material class 构造函数来备份 material。(Material newMat = new Material(RenderSettings.skybox)).

如果您 正在更改 _Exposure 属性 那么您甚至不需要进行 material 备份。只需用 RenderSettings.skybox.GetFloat("_Exposure"); 备份 _Exposure 属性 然后在单击停止时重新分配它。

The Exposure value (in Inspector) does not change after the first change at start (#3), during the play (seems odd),

更改 material 值后调用 DynamicGI.UpdateEnvironment();

用 UI Slider 更改天空盒 _Exposure 属性 的示例:

public Slider slider;
Material backUpMaterial;

void Start()
{
    slider.minValue = 0f;
    slider.maxValue = 3f;
    slider.value = 1.3f;


    //Get Material Backup
    backUpMaterial = makeSkyboxBackUp();

    slider.onValueChanged.AddListener(delegate { sliderCallBack(slider.value); });
}

void sliderCallBack(float value)
{
    RenderSettings.skybox.SetFloat("_Exposure", value);
    DynamicGI.UpdateEnvironment();
}

Material makeSkyboxBackUp()
{
    return new Material(RenderSettings.skybox);
}


//Restore skybox material back to the Default values
void OnDisable()
{
    RenderSettings.skybox = backUpMaterial;
    DynamicGI.UpdateEnvironment();
    slider.onValueChanged.RemoveListener(delegate { sliderCallBack(slider.value); });
}

由于您已经修改了 skybox 设置的原始副本,我建议您通过将 _Exposure 属性 设置为默认设置 1.3 来重置它值,然后尝试上面的解决方案。