Files
2026-03-04 10:03:45 +08:00

595 lines
22 KiB
C#

using System;
using System.Collections.Generic;
using System.Reflection;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.PostProcessing;
namespace PlanarReflections3
{
[ExecuteAlways]
public class PlanarReflectionsRenderer : MonoBehaviour
{
private string version = "3.4";
private float frameTime;
protected static ReflectionSettings globalReflectionSettings = new ReflectionSettings();
[SerializeField]
protected ReflectionSettings settings = new ReflectionSettings();
[SerializeField]
protected RenderTexture externalReflectionTex;
[SerializeField]
protected RenderTexture externalReflectionDepth;
protected RenderTexture reflectionTex;
protected RenderTexture reflectionDepth;
[SerializeField]
protected bool SRPMode;
public Shader internalDepthShader;
public bool castersActive;
private Dictionary<Camera, InternalReflectionRenderer> gameReflectors = new Dictionary<Camera, InternalReflectionRenderer>();
private InternalReflectionRenderer sceneViewReflector = new InternalReflectionRenderer();
[SerializeField]
protected List<RenderTexture> releasables = new List<RenderTexture>();
private List<RenderTexture> rTex = new List<RenderTexture>();
public string Version => version;
public ReflectionSettings GlobalSettings => globalReflectionSettings;
public ReflectionSettings Settings => settings;
public RenderTexture ReflectionTex
{
get
{
if (!externalReflectionTex)
{
return reflectionTex;
}
return externalReflectionTex;
}
}
public RenderTexture ReflectionDepth
{
get
{
if (!externalReflectionDepth)
{
return reflectionDepth;
}
return externalReflectionDepth;
}
}
public bool isSRP => SRPMode;
public void OnEnable()
{
Camera[] array = Resources.FindObjectsOfTypeAll<Camera>();
Camera[] array2 = array;
foreach (Camera camera in array2)
{
if (camera.name.Contains("PLANAR3_") && !SRPMode)
{
if (camera.targetTexture != externalReflectionTex)
{
RenderTexture.ReleaseTemporary(camera.targetTexture);
}
camera.targetTexture = null;
}
}
if (GraphicsSettings.renderPipelineAsset != null)
{
SRPMode = true;
}
else
{
SRPMode = false;
}
if (SRPMode)
{
array2 = array;
foreach (Camera camera2 in array2)
{
if (camera2.name.Contains("PLANAR3_"))
{
camera2.targetTexture = null;
UnityEngine.Object.Destroy(camera2.gameObject);
}
}
RenderPipelineManager.beginFrameRendering -= SRPRenderReflection;
RenderPipelineManager.beginFrameRendering += SRPRenderReflection;
RenderPipelineManager.beginFrameRendering -= CleanupTextures;
RenderPipelineManager.beginFrameRendering += CleanupTextures;
base.gameObject.layer = 4;
}
else
{
Camera.onPreCull = (Camera.CameraCallback)Delegate.Remove(Camera.onPreCull, new Camera.CameraCallback(RenderReflection));
Camera.onPreCull = (Camera.CameraCallback)Delegate.Combine(Camera.onPreCull, new Camera.CameraCallback(RenderReflection));
base.gameObject.layer = 4;
}
}
private void Start()
{
Camera[] array = Resources.FindObjectsOfTypeAll<Camera>();
Camera[] array2 = array;
foreach (Camera camera in array2)
{
if (camera.name.Contains("PLANAR3_") && !SRPMode)
{
RenderTexture.ReleaseTemporary(camera.targetTexture);
camera.targetTexture = null;
UnityEngine.Object.DestroyImmediate(camera.gameObject);
}
}
if (GraphicsSettings.renderPipelineAsset != null)
{
SRPMode = true;
}
else
{
SRPMode = false;
}
if (SRPMode)
{
array2 = array;
foreach (Camera camera2 in array2)
{
if (camera2.name.Contains("PLANAR3_"))
{
camera2.targetTexture = null;
UnityEngine.Object.DestroyImmediate(camera2.gameObject);
}
}
RenderPipelineManager.beginFrameRendering -= SRPRenderReflection;
RenderPipelineManager.beginFrameRendering += SRPRenderReflection;
RenderPipelineManager.beginFrameRendering -= CleanupTextures;
RenderPipelineManager.beginFrameRendering += CleanupTextures;
base.gameObject.layer = 4;
}
else
{
Camera.onPreCull = (Camera.CameraCallback)Delegate.Remove(Camera.onPreCull, new Camera.CameraCallback(RenderReflection));
Camera.onPreCull = (Camera.CameraCallback)Delegate.Combine(Camera.onPreCull, new Camera.CameraCallback(RenderReflection));
base.gameObject.layer = 4;
}
}
public void SRPRenderReflection(ScriptableRenderContext context, Camera[] srcCamera)
{
for (int i = 0; i < srcCamera.Length; i++)
{
if (!srcCamera[i].name.Contains("PLANAR3_"))
{
RenderReflection(srcCamera[i]);
}
}
}
public void CleanupTextures(ScriptableRenderContext context, Camera[] srcCamera)
{
for (int i = 0; i < releasables.Count; i++)
{
if (releasables[i] != null)
{
RenderTexture.ReleaseTemporary(releasables[i]);
releasables.RemoveAt(i);
if (i > 0)
{
i--;
}
}
}
}
public void RenderReflection(Camera srcCamera)
{
if ((Settings.updateOnCastOnly && !castersActive && Application.isPlaying) || (Settings.trackCamerasWithTag && srcCamera.tag != Settings.CamerasTag && srcCamera.cameraType != CameraType.SceneView) || srcCamera.cameraType == CameraType.Reflection || srcCamera.cameraType == CameraType.Preview)
{
return;
}
InternalReflectionRenderer internalReflectionRenderer = null;
if (srcCamera.depthTextureMode == DepthTextureMode.None)
{
srcCamera.depthTextureMode = DepthTextureMode.Depth;
}
if (srcCamera.cameraType == CameraType.SceneView)
{
if (Application.isPlaying && SRPMode)
{
if ((bool)sceneViewReflector.refCamera)
{
sceneViewReflector.refCamera.enabled = false;
}
return;
}
if (!sceneViewReflector.refCamera)
{
sceneViewReflector.refCamera = new GameObject("PLANAR3_SCENEVIEW", typeof(Camera)).GetComponent<Camera>();
GameObject obj = sceneViewReflector.refCamera.gameObject;
HideFlags hideFlags = (sceneViewReflector.refCamera.hideFlags = HideFlags.HideAndDontSave);
obj.hideFlags = hideFlags;
}
internalReflectionRenderer = sceneViewReflector;
}
else if (srcCamera.cameraType == CameraType.Game)
{
if (!gameReflectors.ContainsKey(srcCamera) || gameReflectors[srcCamera] == null)
{
gameReflectors.Add(srcCamera, new InternalReflectionRenderer());
}
if (!gameReflectors[srcCamera].refCamera)
{
gameReflectors[srcCamera].refCamera = new GameObject("PLANAR3_GAMECAM_" + srcCamera.GetInstanceID(), typeof(Camera)).GetComponent<Camera>();
GameObject obj2 = gameReflectors[srcCamera].refCamera.gameObject;
HideFlags hideFlags = (gameReflectors[srcCamera].refCamera.hideFlags = HideFlags.HideAndDontSave);
obj2.hideFlags = hideFlags;
}
else
{
GameObject obj3 = gameReflectors[srcCamera].refCamera.gameObject;
HideFlags hideFlags = (gameReflectors[srcCamera].refCamera.hideFlags = HideFlags.HideAndDontSave);
obj3.hideFlags = hideFlags;
}
internalReflectionRenderer = gameReflectors[srcCamera];
}
if (internalReflectionRenderer == null)
{
return;
}
internalReflectionRenderer.refCamera.CopyFrom(srcCamera);
if (!SRPMode)
{
internalReflectionRenderer.refCamera.cameraType = CameraType.Reflection;
}
if (internalReflectionRenderer.refCamera.clearFlags == CameraClearFlags.Nothing || internalReflectionRenderer.refCamera.clearFlags == CameraClearFlags.Depth)
{
internalReflectionRenderer.refCamera.clearFlags = CameraClearFlags.Color;
}
internalReflectionRenderer.refCamera.enabled = SRPMode;
if (!externalReflectionTex)
{
if (!SRPMode)
{
if (!Application.isPlaying || Settings.targetFramerate == 0 || Time.realtimeSinceStartup > frameTime)
{
if ((bool)reflectionTex)
{
internalReflectionRenderer.assignedTexture = null;
RenderTexture.ReleaseTemporary(reflectionTex);
}
int width = (int)(((Settings.resolutionMode == ResolutionMode.ExplicitValue) ? Settings.explicitResolution.x : ((float)srcCamera.pixelWidth)) * Settings.resolutionDownscale);
int height = (int)(((Settings.resolutionMode == ResolutionMode.ExplicitValue) ? Settings.explicitResolution.y : ((float)srcCamera.pixelHeight)) * Settings.resolutionDownscale);
if (settings.forceFloatOutput && settings.usePostFX)
{
reflectionTex = RenderTexture.GetTemporary(new RenderTextureDescriptor(width, height, RenderTextureFormat.ARGBFloat, 24));
}
else
{
reflectionTex = RenderTexture.GetTemporary(new RenderTextureDescriptor(width, height, RenderTextureFormat.Default, 24));
}
reflectionTex.name = "PIDI_REFTEX" + ((srcCamera.cameraType == CameraType.SceneView) ? "SCENE" : "GAME");
if (!rTex.Contains(reflectionTex))
{
rTex.Add(reflectionTex);
}
if (!reflectionTex.IsCreated())
{
reflectionTex.useMipMap = Settings.useMipMaps;
reflectionTex.antiAliasing = ((!Settings.useAntialiasing) ? 1 : 4);
reflectionTex.Create();
}
internalReflectionRenderer.assignedTexture = reflectionTex;
}
}
else if (!internalReflectionRenderer.assignedTexture)
{
int width2 = (int)(((Settings.resolutionMode == ResolutionMode.ExplicitValue) ? Settings.explicitResolution.x : ((float)srcCamera.pixelWidth)) * Settings.resolutionDownscale);
int height2 = (int)(((Settings.resolutionMode == ResolutionMode.ExplicitValue) ? Settings.explicitResolution.y : ((float)srcCamera.pixelHeight)) * Settings.resolutionDownscale);
if (settings.forceFloatOutput && settings.usePostFX)
{
reflectionTex = RenderTexture.GetTemporary(new RenderTextureDescriptor(width2, height2, RenderTextureFormat.ARGBFloat, 24));
}
else
{
reflectionTex = RenderTexture.GetTemporary(new RenderTextureDescriptor(width2, height2, RenderTextureFormat.Default, 24));
}
reflectionTex.name = "PIDI_REFTEX" + ((srcCamera.cameraType == CameraType.SceneView) ? "SCENE" : "GAME");
if (!rTex.Contains(reflectionTex))
{
rTex.Add(reflectionTex);
}
reflectionTex.useMipMap = Settings.useMipMaps;
reflectionTex.antiAliasing = ((!Settings.useAntialiasing) ? 1 : 4);
reflectionTex.Create();
internalReflectionRenderer.assignedTexture = reflectionTex;
}
else
{
int num = (int)(((Settings.resolutionMode == ResolutionMode.ExplicitValue) ? Settings.explicitResolution.x : ((float)srcCamera.pixelWidth)) * Settings.resolutionDownscale);
int num2 = (int)(((Settings.resolutionMode == ResolutionMode.ExplicitValue) ? Settings.explicitResolution.y : ((float)srcCamera.pixelHeight)) * Settings.resolutionDownscale);
if (!internalReflectionRenderer.assignedTexture || internalReflectionRenderer.assignedTexture.width != num || internalReflectionRenderer.assignedTexture.height != num2)
{
if (internalReflectionRenderer.assignedTexture != null && !releasables.Contains(internalReflectionRenderer.assignedTexture))
{
releasables.Add(internalReflectionRenderer.assignedTexture);
}
internalReflectionRenderer.refCamera.targetTexture = null;
if (settings.forceFloatOutput && settings.usePostFX)
{
reflectionTex = RenderTexture.GetTemporary(new RenderTextureDescriptor(num, num2, RenderTextureFormat.ARGBFloat, 24));
reflectionTex.name = "PIDI_REFTEX" + ((srcCamera.cameraType == CameraType.SceneView) ? "SCENE" : "GAME");
if (!rTex.Contains(reflectionTex))
{
rTex.Add(reflectionTex);
}
reflectionTex.useMipMap = Settings.useMipMaps;
reflectionTex.antiAliasing = ((!Settings.useAntialiasing) ? 1 : 4);
reflectionTex.Create();
internalReflectionRenderer.assignedTexture = reflectionTex;
}
else
{
reflectionTex = RenderTexture.GetTemporary(new RenderTextureDescriptor(num, num2, RenderTextureFormat.Default, 24));
reflectionTex.name = "PIDI_REFTEX" + ((srcCamera.cameraType == CameraType.SceneView) ? "SCENE" : "GAME");
if (!rTex.Contains(reflectionTex))
{
rTex.Add(reflectionTex);
}
reflectionTex.useMipMap = Settings.useMipMaps;
reflectionTex.antiAliasing = ((!Settings.useAntialiasing) ? 1 : 4);
reflectionTex.Create();
internalReflectionRenderer.assignedTexture = reflectionTex;
}
}
reflectionTex = internalReflectionRenderer.assignedTexture;
}
reflectionTex.filterMode = FilterMode.Bilinear;
}
float shadowDistance = QualitySettings.shadowDistance;
if (!SRPMode && Settings.customShadowDistance)
{
QualitySettings.shadowDistance = Settings.shadowDistance;
}
internalReflectionRenderer.refCamera.targetTexture = ReflectionTex;
internalReflectionRenderer.refCamera.aspect = srcCamera.aspect;
internalReflectionRenderer.refCamera.rect = new Rect(0f, 0f, 1f, 1f);
Vector3 forward = srcCamera.transform.forward;
Vector3 up = srcCamera.transform.up;
Vector3 position = srcCamera.transform.position;
Vector3 direction = base.transform.InverseTransformDirection(forward);
Vector3 direction2 = base.transform.InverseTransformDirection(up);
Vector3 position2 = base.transform.InverseTransformPoint(position);
direction.y *= -1f;
direction2.y *= -1f;
position2.y *= -1f;
forward = base.transform.TransformDirection(direction);
up = base.transform.TransformDirection(direction2);
position = base.transform.TransformPoint(position2);
internalReflectionRenderer.refCamera.transform.position = position;
internalReflectionRenderer.refCamera.transform.LookAt(position + forward, up);
internalReflectionRenderer.refCamera.nearClipPlane = Settings.nearClipDistance;
internalReflectionRenderer.refCamera.farClipPlane = Settings.farClipDistance;
internalReflectionRenderer.refCamera.renderingPath = Settings.renderingPath;
internalReflectionRenderer.refCamera.cullingMask = Settings.reflectLayers;
if (Settings.usePostFX)
{
PostProcessLayer postProcessLayer = ((Settings.PostFXSettingsMode == PostFXSettingsMode.CustomSettings) ? GetComponent<PostProcessLayer>() : srcCamera.GetComponent<PostProcessLayer>());
if ((bool)postProcessLayer)
{
PostProcessLayer component = internalReflectionRenderer.refCamera.GetComponent<PostProcessLayer>();
if ((bool)component)
{
component.volumeTrigger = internalReflectionRenderer.refCamera.transform;
component.volumeLayer = postProcessLayer.volumeLayer;
component.antialiasingMode = ((postProcessLayer.antialiasingMode != PostProcessLayer.Antialiasing.None) ? PostProcessLayer.Antialiasing.FastApproximateAntialiasing : PostProcessLayer.Antialiasing.None);
component.fastApproximateAntialiasing = postProcessLayer.fastApproximateAntialiasing;
}
else
{
component = internalReflectionRenderer.refCamera.gameObject.AddComponent<PostProcessLayer>();
BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
FieldInfo field = typeof(PostProcessLayer).GetField("m_Resources", bindingAttr);
component.Init((PostProcessResources)field.GetValue(postProcessLayer));
component.volumeTrigger = internalReflectionRenderer.refCamera.transform;
component.volumeLayer = postProcessLayer.volumeLayer;
component.antialiasingMode = ((postProcessLayer.antialiasingMode != PostProcessLayer.Antialiasing.None) ? PostProcessLayer.Antialiasing.FastApproximateAntialiasing : PostProcessLayer.Antialiasing.None);
component.fastApproximateAntialiasing = postProcessLayer.fastApproximateAntialiasing;
}
}
}
else
{
if ((bool)GetComponent<PostProcessLayer>())
{
UnityEngine.Object.DestroyImmediate(GetComponent<PostProcessLayer>());
if ((bool)GetComponent<Camera>())
{
UnityEngine.Object.DestroyImmediate(GetComponent<Camera>());
}
}
if ((bool)internalReflectionRenderer.refCamera.GetComponent<PostProcessLayer>())
{
UnityEngine.Object.DestroyImmediate(internalReflectionRenderer.refCamera.GetComponent<PostProcessLayer>());
}
}
internalReflectionRenderer.refCamera.transform.Rotate(0.01f, 0.01f, 0.01f);
internalReflectionRenderer.refCamera.transform.Translate(0.002f, 0.002f, 0.002f);
if (settings.reflectionClipMode == ReflectionClipMode.AccurateClipping)
{
internalReflectionRenderer.refCamera.projectionMatrix = internalReflectionRenderer.refCamera.CalculateObliqueMatrix(CameraSpacePlane(internalReflectionRenderer.refCamera, base.transform.position, base.transform.up));
}
if (!SRPMode)
{
if (!Application.isPlaying || Settings.targetFramerate == 0)
{
internalReflectionRenderer.refCamera.Render();
}
else if (srcCamera.cameraType != CameraType.SceneView && Application.isPlaying && Time.realtimeSinceStartup > frameTime)
{
frameTime = Time.realtimeSinceStartup + 1f / (float)Settings.targetFramerate;
internalReflectionRenderer.refCamera.Render();
}
}
else
{
if (!Application.isPlaying || Settings.targetFramerate == 0)
{
internalReflectionRenderer.refCamera.enabled = true;
}
else if (Time.realtimeSinceStartup > frameTime)
{
frameTime = Time.realtimeSinceStartup + 1f / (float)Settings.targetFramerate;
internalReflectionRenderer.refCamera.enabled = true;
}
internalReflectionRenderer.refCamera.depth = -999f;
}
if (Settings.useDepth && (bool)internalDepthShader && !SRPMode)
{
if (!externalReflectionDepth)
{
if ((bool)reflectionDepth)
{
RenderTexture.ReleaseTemporary(reflectionDepth);
}
int width3 = (int)(((Settings.resolutionMode == ResolutionMode.ExplicitValue) ? Settings.explicitResolution.x : ((float)srcCamera.pixelWidth)) * Settings.resolutionDownscale);
int height3 = (int)(((Settings.resolutionMode == ResolutionMode.ExplicitValue) ? Settings.explicitResolution.y : ((float)srcCamera.pixelHeight)) * Settings.resolutionDownscale);
reflectionDepth = RenderTexture.GetTemporary(width3, height3, 0, RenderTextureFormat.ARGBFloat, RenderTextureReadWrite.Linear);
reflectionDepth.name = "PIDI_REFDEPTH" + ((srcCamera.cameraType == CameraType.SceneView) ? "SCENE" : "GAME");
if (!rTex.Contains(reflectionDepth))
{
rTex.Add(reflectionDepth);
}
}
internalReflectionRenderer.refCamera.targetTexture = ReflectionDepth;
internalReflectionRenderer.refCamera.backgroundColor = Color.green;
internalReflectionRenderer.refCamera.clearFlags = CameraClearFlags.Color;
Shader.SetGlobalVector("_Planar3DepthPlaneOrigin", new Vector4(base.transform.position.x, base.transform.position.y, base.transform.position.z));
Shader.SetGlobalVector("_Planar3DepthPlaneNormal", -new Vector4(base.transform.up.x, base.transform.up.y, base.transform.up.z));
internalReflectionRenderer.refCamera.renderingPath = RenderingPath.Forward;
internalReflectionRenderer.refCamera.RenderWithShader(internalDepthShader, "");
}
QualitySettings.shadowDistance = shadowDistance;
}
public void LateUpdate()
{
castersActive = false;
Camera[] array = new Camera[gameReflectors.Keys.Count];
gameReflectors.Keys.CopyTo(array, 0);
for (int i = 0; i < array.Length; i++)
{
if (array[i] != null)
{
Vector3 forward = array[i].transform.forward;
Vector3 up = array[i].transform.up;
Vector3 position = array[i].transform.position;
Vector3 direction = base.transform.InverseTransformDirection(forward);
Vector3 direction2 = base.transform.InverseTransformDirection(up);
Vector3 position2 = base.transform.InverseTransformPoint(position);
direction.y *= -1f;
direction2.y *= -1f;
position2.y *= -1f;
forward = base.transform.TransformDirection(direction);
up = base.transform.TransformDirection(direction2);
position = base.transform.TransformPoint(position2);
if (!gameReflectors[array[i]].refCamera)
{
continue;
}
gameReflectors[array[i]].refCamera.transform.position = position;
gameReflectors[array[i]].refCamera.transform.LookAt(position + forward, up);
if (!Settings.useCustomComponents)
{
continue;
}
List<string> list = new List<string>(Settings.customComponentNames);
Component[] components = base.gameObject.GetComponents(typeof(Component));
foreach (Component component in components)
{
if (!list.Contains(component.GetType().Name))
{
continue;
}
if (!gameReflectors[array[i]].refCamera.GetComponent(component.GetType()))
{
Component obj = gameReflectors[array[i]].refCamera.gameObject.AddComponent(component.GetType());
FieldInfo[] fields = component.GetType().GetFields();
foreach (FieldInfo fieldInfo in fields)
{
fieldInfo.SetValue(obj, fieldInfo.GetValue(component));
}
}
else if (Settings.autoSynchComponents)
{
Component obj2 = gameReflectors[array[i]].refCamera.gameObject.AddComponent(component.GetType());
FieldInfo[] fields = component.GetType().GetFields();
foreach (FieldInfo fieldInfo2 in fields)
{
fieldInfo2.SetValue(obj2, fieldInfo2.GetValue(component));
}
}
}
}
else
{
gameReflectors.Remove(array[i]);
}
}
}
public void OnDisable()
{
foreach (RenderTexture item in rTex)
{
RenderTexture.ReleaseTemporary(item);
}
if (SRPMode)
{
RenderPipelineManager.beginFrameRendering -= SRPRenderReflection;
RenderPipelineManager.beginFrameRendering -= CleanupTextures;
}
else
{
Camera.onPreCull = (Camera.CameraCallback)Delegate.Remove(Camera.onPreCull, new Camera.CameraCallback(RenderReflection));
}
Camera[] array = Resources.FindObjectsOfTypeAll<Camera>();
foreach (Camera camera in array)
{
if (camera.name.Contains("PLANAR3_"))
{
if ((bool)camera.targetTexture && rTex.Contains(camera.targetTexture))
{
RenderTexture.ReleaseTemporary(camera.targetTexture);
}
UnityEngine.Object.DestroyImmediate(camera.gameObject);
}
}
}
private Vector4 CameraSpacePlane(Camera forCamera, Vector3 planeCenter, Vector3 planeNormal)
{
Matrix4x4 worldToCameraMatrix = forCamera.worldToCameraMatrix;
Vector3 lhs = worldToCameraMatrix.MultiplyPoint(planeCenter);
Vector3 rhs = worldToCameraMatrix.MultiplyVector(planeNormal).normalized * 1f;
return new Vector4(rhs.x, rhs.y, rhs.z, 0f - Vector3.Dot(lhs, rhs));
}
}
}