using UnityEngine; using UnityEngine.Rendering; using UnityEngine.Rendering.Universal; namespace ShinySSRR { [ExecuteAlways] public class SkyboxBaker : MonoBehaviour { const string BAKER_CAM_NAME = "SSR_SkyboxBaker"; public static bool needSkyboxUpdate = true; RenderTexture skyboxCubemap; float lastSkyboxSnapshotTime; ShinyScreenSpaceRaytracedReflections settings; Camera cam; RenderTextureFormat currentSkyboxFormat; Camera bakerCam; GameObject bakerGO; void OnEnable() { needSkyboxUpdate = true; cam = GetComponent(); } void OnDisable() { ReleaseBakerCamera(); } void OnDestroy() { ReleaseSkyboxCubemap(); ReleaseBakerCamera(); } void LateUpdate() { settings = VolumeManager.instance?.stack?.GetComponent(); if (settings == null || settings.skyboxIntensity.value <= 0 || cam == null) return; if (settings.skyboxUpdateMode.value == SkyboxUpdateMode.Continuous) { needSkyboxUpdate = true; } else if (settings.skyboxUpdateMode.value == SkyboxUpdateMode.Interval && Time.time - lastSkyboxSnapshotTime >= settings.skyboxUpdateInterval.value) { lastSkyboxSnapshotTime = Time.time; needSkyboxUpdate = true; } if (needSkyboxUpdate && cam.cameraType == CameraType.Game) { needSkyboxUpdate = false; UpdateSkyboxCubemap(); } } void ReleaseSkyboxCubemap() { if (skyboxCubemap == null) return; skyboxCubemap.Release(); DestroyImmediate(skyboxCubemap); skyboxCubemap = null; } void ReleaseBakerCamera() { if (bakerGO == null) return; if (Application.isPlaying) { Destroy(bakerGO); } else { DestroyImmediate(bakerGO); } bakerGO = null; bakerCam = null; } void CleanupOrphanedBakerCameras() { if (cam == null) return; Transform camT = cam.transform; for (int i = camT.childCount - 1; i >= 0; i--) { Transform child = camT.GetChild(i); if (child.name == BAKER_CAM_NAME) { if (Application.isPlaying) { Destroy(child.gameObject); } else { DestroyImmediate(child.gameObject); } } } } void EnsureBakerCamera() { if (bakerCam != null) return; ReleaseBakerCamera(); CleanupOrphanedBakerCameras(); bakerGO = new GameObject(BAKER_CAM_NAME); Transform bakerT = bakerGO.transform; bakerT.SetParent(cam.transform, false); bakerT.localPosition = Vector3.zero; bakerT.localRotation = Quaternion.identity; bakerCam = bakerGO.AddComponent(); bakerCam.enabled = false; var urpData = bakerGO.AddComponent(); urpData.renderPostProcessing = false; urpData.renderShadows = false; urpData.requiresColorTexture = false; urpData.requiresDepthTexture = false; urpData.antialiasing = AntialiasingMode.None; } public void UpdateSkyboxCubemap() { if (settings.skyboxReflectionMode.value == SkyboxReflectionMode.CustomCubemap) { Shader.SetGlobalTexture(ShaderParams.SkyboxCubemap, settings.skyboxCustomCubemap.value); return; } if (cam == null) return; EnsureBakerCamera(); bakerCam.fieldOfView = cam.fieldOfView; bakerCam.nearClipPlane = cam.nearClipPlane; bakerCam.orthographic = cam.orthographic; bakerCam.orthographicSize = cam.orthographicSize; bakerCam.clearFlags = cam.clearFlags; bakerCam.backgroundColor = cam.backgroundColor; int desiredCullingMask = settings.skyboxCullingMask.value; bakerCam.cullingMask = desiredCullingMask; bakerCam.farClipPlane = desiredCullingMask == 0 ? cam.nearClipPlane + 0.1f : cam.farClipPlane; int res = 16 << Mathf.Clamp((int)settings.skyboxResolution.value, 0, 9); RenderTextureFormat rtFormat = settings.skyboxHDR.value ? RenderTextureFormat.DefaultHDR : RenderTextureFormat.Default; if (skyboxCubemap == null || skyboxCubemap.width != res || currentSkyboxFormat != rtFormat) { currentSkyboxFormat = rtFormat; ReleaseSkyboxCubemap(); skyboxCubemap = new RenderTexture(res, res, 0, rtFormat) { dimension = TextureDimension.Cube }; } bakerCam.RenderToCubemap(skyboxCubemap); Shader.SetGlobalTexture(ShaderParams.SkyboxCubemap, skyboxCubemap); } } }