154 lines
5.1 KiB
C#

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<Camera>();
}
void OnDisable() {
ReleaseBakerCamera();
}
void OnDestroy() {
ReleaseSkyboxCubemap();
ReleaseBakerCamera();
}
void LateUpdate() {
settings = VolumeManager.instance?.stack?.GetComponent<ShinyScreenSpaceRaytracedReflections>();
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<Camera>();
bakerCam.enabled = false;
var urpData = bakerGO.AddComponent<UniversalAdditionalCameraData>();
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);
}
}
}