Files
UltimateFishing/Assets/Scripts/Assembly-CSharp/ReflectionCamera.cs
2026-02-21 16:45:37 +08:00

256 lines
6.4 KiB
C#

using System.Collections;
using UnityEngine;
public class ReflectionCamera : MonoBehaviour
{
public float m_ClipPlaneOffset = 0.07f;
public LayerMask CullingMask = -17;
public bool HDR;
public bool OcclusionCulling = true;
public float TextureScale = 1f;
public RenderTextureFormat RenderTextureFormat;
public FilterMode FilterMode;
public RenderingPath RenderingPath;
public bool UseRealtimeUpdate;
public int FPSWhenMoveCamera = 40;
public int FPSWhenStaticCamera = 20;
private RenderTexture renderTexture;
private GameObject go;
private Camera reflectionCamera;
private Vector3 oldPosition;
private Quaternion oldRotation;
private Transform instanceCameraTransform;
private int frameCountWhenCameraIsStatic;
private bool canUpdateCamera;
private bool isStaticUpdate;
private WaitForSeconds fpsMove;
private WaitForSeconds fpsStatic;
private const int DropedFrames = 50;
private Camera currentCamera;
private void OnEnable()
{
Shader.EnableKeyword("editor_off");
Shader.EnableKeyword("cubeMap_off");
currentCamera = Camera.main;
fpsMove = new WaitForSeconds(1f / (float)FPSWhenMoveCamera);
fpsStatic = new WaitForSeconds(1f / (float)FPSWhenStaticCamera);
if (!UseRealtimeUpdate)
{
StartCoroutine(RepeatCameraMove());
StartCoroutine(RepeatCameraStatic());
}
else
{
canUpdateCamera = true;
}
}
private IEnumerator RepeatCameraMove()
{
while (true)
{
if (!isStaticUpdate)
{
canUpdateCamera = true;
}
yield return fpsMove;
}
}
private IEnumerator RepeatCameraStatic()
{
while (true)
{
if (isStaticUpdate)
{
canUpdateCamera = true;
}
yield return fpsStatic;
}
}
private void OnBecameVisible()
{
if (go != null)
{
go.SetActive(true);
}
}
private void OnBecameInvisible()
{
}
private void Update()
{
Vector3 position = base.transform.position;
Vector3 up = base.transform.up;
float w = 0f - Vector3.Dot(up, position) - m_ClipPlaneOffset;
Vector4 plane = new Vector4(up.x, up.y, up.z, w);
Matrix4x4 reflectionMat = Matrix4x4.zero;
CalculateReflectionMatrix(ref reflectionMat, plane);
Vector3 position2 = currentCamera.transform.position;
Vector3 position3 = reflectionMat.MultiplyPoint(position2);
if (go == null)
{
renderTexture = new RenderTexture((int)((float)Screen.width * TextureScale), (int)((float)Screen.height * TextureScale), 16, RenderTextureFormat);
renderTexture.DiscardContents();
go = new GameObject("Water Refl Camera");
reflectionCamera = go.AddComponent<Camera>();
reflectionCamera.depth = currentCamera.depth - 1f;
reflectionCamera.renderingPath = RenderingPath;
reflectionCamera.depthTextureMode = DepthTextureMode.None;
go.transform.position = base.transform.position;
go.transform.rotation = base.transform.rotation;
reflectionCamera.cullingMask = CullingMask;
reflectionCamera.targetTexture = renderTexture;
reflectionCamera.hdr = HDR;
reflectionCamera.useOcclusionCulling = OcclusionCulling;
Shader.SetGlobalTexture("_ReflectionTex", renderTexture);
instanceCameraTransform = reflectionCamera.transform;
}
reflectionCamera.worldToCameraMatrix = currentCamera.worldToCameraMatrix * reflectionMat;
Vector4 clipPlane = CameraSpacePlane(reflectionCamera, position, up, 1f);
reflectionCamera.projectionMatrix = currentCamera.CalculateObliqueMatrix(clipPlane);
GL.invertCulling = true;
go.transform.position = position3;
Vector3 eulerAngles = currentCamera.transform.eulerAngles;
go.transform.eulerAngles = new Vector3(0f - eulerAngles.x, eulerAngles.y, eulerAngles.z);
UpdateCameraPosition();
GL.invertCulling = false;
}
private void UpdateCameraPosition()
{
if (reflectionCamera == null)
{
return;
}
if (Vector3.SqrMagnitude(instanceCameraTransform.position - oldPosition) <= 1E-05f && instanceCameraTransform.rotation == oldRotation)
{
frameCountWhenCameraIsStatic++;
if (frameCountWhenCameraIsStatic >= 50)
{
isStaticUpdate = true;
}
}
else
{
frameCountWhenCameraIsStatic = 0;
isStaticUpdate = false;
}
oldPosition = instanceCameraTransform.position;
oldRotation = instanceCameraTransform.rotation;
if (canUpdateCamera)
{
reflectionCamera.enabled = true;
if (!UseRealtimeUpdate)
{
canUpdateCamera = false;
}
}
else if (reflectionCamera.enabled)
{
reflectionCamera.enabled = false;
}
}
private static float sgn(float a)
{
if (a > 0f)
{
return 1f;
}
if (a < 0f)
{
return -1f;
}
return 0f;
}
private Matrix4x4 CalculateObliqueMatrix(Matrix4x4 projection, Vector4 clipPlane)
{
Vector4 b = projection.inverse * new Vector4(sgn(clipPlane.x), sgn(clipPlane.y), 1f, 1f);
Vector4 vector = clipPlane * (2f / Vector4.Dot(clipPlane, b));
projection[2] = vector.x - projection[3];
projection[6] = vector.y - projection[7];
projection[10] = vector.z - projection[11];
projection[14] = vector.w - projection[15];
return projection;
}
private static void CalculateReflectionMatrix(ref Matrix4x4 reflectionMat, Vector4 plane)
{
reflectionMat.m00 = 1f - 2f * plane[0] * plane[0];
reflectionMat.m01 = -2f * plane[0] * plane[1];
reflectionMat.m02 = -2f * plane[0] * plane[2];
reflectionMat.m03 = -2f * plane[3] * plane[0];
reflectionMat.m10 = -2f * plane[1] * plane[0];
reflectionMat.m11 = 1f - 2f * plane[1] * plane[1];
reflectionMat.m12 = -2f * plane[1] * plane[2];
reflectionMat.m13 = -2f * plane[3] * plane[1];
reflectionMat.m20 = -2f * plane[2] * plane[0];
reflectionMat.m21 = -2f * plane[2] * plane[1];
reflectionMat.m22 = 1f - 2f * plane[2] * plane[2];
reflectionMat.m23 = -2f * plane[3] * plane[2];
reflectionMat.m30 = 0f;
reflectionMat.m31 = 0f;
reflectionMat.m32 = 0f;
reflectionMat.m33 = 1f;
}
private Vector4 CameraSpacePlane(Camera cam, Vector3 pos, Vector3 normal, float sideSign)
{
Vector3 point = pos + normal * m_ClipPlaneOffset;
Matrix4x4 worldToCameraMatrix = cam.worldToCameraMatrix;
Vector3 lhs = worldToCameraMatrix.MultiplyPoint(point);
Vector3 rhs = worldToCameraMatrix.MultiplyVector(normal).normalized * sideSign;
return new Vector4(rhs.x, rhs.y, rhs.z, 0f - Vector3.Dot(lhs, rhs));
}
private void OnDisable()
{
ClearCamera();
Shader.DisableKeyword("editor_off");
Shader.DisableKeyword("cubeMap_off");
}
private void ClearCamera()
{
if ((bool)go)
{
Object.DestroyImmediate(go);
go = null;
}
if ((bool)renderTexture)
{
Object.DestroyImmediate(renderTexture);
renderTexture = null;
}
}
}