0
\$\begingroup\$

Usually in Unity, when your scripts make changes to something at runtime, those changes are not persisted back to design-time. This is generally considered a good thing. But for whatever bizarre technical reason, this does not apply to shader properties on materials. If you change something while the game is running, it stays changed!

Generally the way to get around this is with a MaterialPropertyBlock, which also helps avoid generating a lot of garbage. But MaterialPropertyBlocks work with Renderers, which leaves out one rather important material: the skybox.

Right now, I have code that says RenderSettings.skybox.SetFloat("_PropName", value);, and it's incredibly aggravating because it always needs to be reset afterwards. RenderSettings doesn't have a SkyboxRenderer property that I can use in conjunction with a MaterialPropertyBlock, so how can I change shader settings on my skybox and make them not persist after I exit play mode?

\$\endgroup\$
  • \$\begingroup\$ The "bizarre technical reason" being the same reason that applies to every asset in your project folder but not in your scene: if you don't instantiate a copy (like the copy of a game object spawned when loading a scene), then you're modifying the original. \$\endgroup\$ – DMGregory Jun 23 at 17:20
  • \$\begingroup\$ @DMGregory I don't instantiate copies of the game objects when I'm loading the scenes. Unity's perfectly capable of taking care of that for me in order to protect the originals. But for some bizarre technical reason, it doesn't do the same for the skybox. \$\endgroup\$ – Mason Wheeler Jun 23 at 17:22
  • \$\begingroup\$ Loading a scene is instantiating a copy. Once you enter play mode you're no longer manipulating the saved scene file on your hard disc, you've spawned newly-created instances of all its contents. \$\endgroup\$ – DMGregory Jun 23 at 17:22
0
\$\begingroup\$

Presumably you considered doing something like...

Material originalSkybox = RenderSettings.skybox;
Material runtimeSkybox = Instantiate(originalSkybox);
RenderSettings.skybox = runtimeSkybox;

runtimeSkybox.SetFloat(...

...and destroying runtimeSkybox when your game ends?

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ No, actually the thought never crossed my mind to Instantiate something that's not a GameObject. Does that even work? Only time I've ever seen Instantiate used is with prefabs. \$\endgroup\$ – Mason Wheeler Jun 23 at 17:25
  • \$\begingroup\$ @MasonWheeler Instantiate really mostly just makes a copy of something. It works with... nearly anything. \$\endgroup\$ – Weckar E. Jul 23 at 18:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.