MirrorCamera.cs 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. [ExecuteInEditMode]
  5. [RequireComponent(typeof(Camera))]
  6. public class MirrorCamera : MonoBehaviour
  7. {
  8. public Camera lookCamera;
  9. public Transform reflectionTransform;
  10. public Vector3 reflectionPosition;
  11. public Quaternion reflectionRotation;
  12. public Vector3 reflectionUp;
  13. public float clipPlaneOffset = 0.07f;
  14. private Camera m_Camera;
  15. private void Awake() {
  16. m_Camera = GetComponent<Camera>();
  17. }
  18. private void OnPreRender() {
  19. GL.invertCulling = true;
  20. if (reflectionTransform)
  21. {
  22. ResetCamera();
  23. }
  24. }
  25. private void OnPostRender() {
  26. GL.invertCulling = false;
  27. }
  28. public void ResetCamera() {
  29. if (!lookCamera) return;
  30. Vector3 pos, normal;
  31. Quaternion rotation;
  32. if (reflectionTransform)
  33. {
  34. pos = reflectionTransform.position;
  35. normal = reflectionTransform.up;
  36. rotation = reflectionTransform.rotation;
  37. }
  38. else
  39. {
  40. pos = reflectionPosition;
  41. normal = reflectionUp;
  42. rotation = reflectionRotation;
  43. }
  44. transform.position = pos;
  45. transform.rotation = rotation;
  46. float d = -Vector3.Dot (normal, pos) - clipPlaneOffset;
  47. Vector4 reflectionPlane = new Vector4 (normal.x, normal.y, normal.z, d);
  48. Matrix4x4 reflection = Matrix4x4.zero;
  49. reflection = CalculateReflectionMatrix (reflection, reflectionPlane);
  50. Vector3 oldpos = lookCamera.transform.position;
  51. Vector3 newpos = reflection.MultiplyPoint( oldpos );
  52. m_Camera.worldToCameraMatrix = lookCamera.worldToCameraMatrix * reflection;
  53. // Setup oblique projection matrix so that near plane is our reflection
  54. // plane. This way we clip everything below/above it for free.
  55. Vector4 clipPlane = CameraSpacePlane( m_Camera, pos, normal, 1.0f );
  56. //Matrix4x4 projection = cam.projectionMatrix;
  57. Matrix4x4 projection = lookCamera.CalculateObliqueMatrix(clipPlane);
  58. m_Camera.projectionMatrix = projection;
  59. m_Camera.transform.position = newpos;
  60. Vector3 euler = lookCamera.transform.eulerAngles;
  61. m_Camera.transform.eulerAngles = new Vector3(0, euler.y, euler.z);
  62. m_Camera.transform.position = oldpos;
  63. }
  64. Vector4 CameraSpacePlane(Camera cam, Vector3 pos, Vector3 normal, float sideSign)
  65. {
  66. Vector3 offsetPos = pos + normal * clipPlaneOffset;
  67. Matrix4x4 m = cam.worldToCameraMatrix;
  68. Vector3 cpos = m.MultiplyPoint(offsetPos);
  69. Vector3 cnormal = m.MultiplyVector(normal).normalized * sideSign;
  70. return new Vector4(cnormal.x, cnormal.y, cnormal.z, -Vector3.Dot(cpos, cnormal));
  71. }
  72. static float Sgn(float a)
  73. {
  74. if (a > 0.0F)
  75. {
  76. return 1.0F;
  77. }
  78. if (a < 0.0F)
  79. {
  80. return -1.0F;
  81. }
  82. return 0.0F;
  83. }
  84. static Matrix4x4 CalculateReflectionMatrix(Matrix4x4 reflectionMat, Vector4 plane)
  85. {
  86. reflectionMat.m00 = (1F - 2F * plane[0] * plane[0]);
  87. reflectionMat.m01 = ( - 2F * plane[0] * plane[1]);
  88. reflectionMat.m02 = ( - 2F * plane[0] * plane[2]);
  89. reflectionMat.m03 = ( - 2F * plane[3] * plane[0]);
  90. reflectionMat.m10 = ( - 2F * plane[1] * plane[0]);
  91. reflectionMat.m11 = (1F - 2F * plane[1] * plane[1]);
  92. reflectionMat.m12 = ( - 2F * plane[1] * plane[2]);
  93. reflectionMat.m13 = ( - 2F * plane[3] * plane[1]);
  94. reflectionMat.m20 = ( - 2F * plane[2] * plane[0]);
  95. reflectionMat.m21 = ( - 2F * plane[2] * plane[1]);
  96. reflectionMat.m22 = (1F - 2F * plane[2] * plane[2]);
  97. reflectionMat.m23 = ( - 2F * plane[3] * plane[2]);
  98. reflectionMat.m30 = 0F;
  99. reflectionMat.m31 = 0F;
  100. reflectionMat.m32 = 0F;
  101. reflectionMat.m33 = 1F;
  102. return reflectionMat;
  103. }
  104. }