MirrorReflection.cs 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  1. using System;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. namespace CalmWater
  5. {
  6. [ExecuteInEditMode]
  7. [RequireComponent(typeof(MeshRenderer))]
  8. public class MirrorReflection : MonoBehaviour
  9. {
  10. //private RenderTexture rt;
  11. public LayerMask reflectionMask = -1;
  12. private enum QualityLevels
  13. {
  14. High = 1,
  15. Medium = 2,
  16. Low = 4,
  17. VeryLow = 8
  18. };
  19. [SerializeField]
  20. private QualityLevels Quality = QualityLevels.Medium;
  21. [Tooltip("Color used instead of skybox if you choose to not render it.")]
  22. public Color clearColor = Color.grey;
  23. public bool reflectSkybox = true;
  24. public bool m_DisablePixelLights = false;
  25. [Tooltip("You won't be able to select objects in the scene when thi is active.")]
  26. public bool UpdateSceneView = true;
  27. public float clipPlaneOffset = 0.07F;
  28. private String reflectionSampler = "_ReflectionTex";
  29. Vector3 m_Oldpos;
  30. Camera m_ReflectionCamera;
  31. Material m_SharedMaterial;
  32. Dictionary<Camera, bool> m_HelperCameras;
  33. void OnEnable(){
  34. gameObject.layer = LayerMask.NameToLayer ("Water");
  35. setMaterial();
  36. }
  37. void OnDisable()
  38. {
  39. if(m_ReflectionCamera != null)
  40. {
  41. DestroyImmediate (m_ReflectionCamera);
  42. }
  43. }
  44. void Start()
  45. {
  46. gameObject.layer = LayerMask.NameToLayer ("Water");
  47. setMaterial ();
  48. }
  49. public void setMaterial()
  50. {
  51. m_SharedMaterial = GetComponent<Renderer>().sharedMaterial;
  52. }
  53. Camera CreateReflectionCameraFor(Camera cam)
  54. {
  55. String reflName = gameObject.name + "Reflection" + cam.name;
  56. GameObject go = GameObject.Find(reflName);
  57. if (!go)
  58. {
  59. go = new GameObject(reflName, typeof(Camera));
  60. go.hideFlags = HideFlags.HideAndDontSave;
  61. }
  62. if (!go.GetComponent(typeof(Camera)))
  63. {
  64. go.AddComponent(typeof(Camera));
  65. }
  66. Camera reflectCamera = go.GetComponent<Camera>();
  67. reflectCamera.backgroundColor = clearColor;
  68. reflectCamera.clearFlags = reflectSkybox ? CameraClearFlags.Skybox : CameraClearFlags.SolidColor;
  69. SetStandardCameraParameter(reflectCamera, reflectionMask);
  70. if (!reflectCamera.targetTexture)
  71. {
  72. reflectCamera.targetTexture = CreateTextureFor(cam);
  73. }
  74. return reflectCamera;
  75. }
  76. void SetStandardCameraParameter(Camera cam, LayerMask mask)
  77. {
  78. cam.cullingMask = mask & ~(1 << LayerMask.NameToLayer("Water"));
  79. cam.backgroundColor = Color.black;
  80. cam.enabled = false;
  81. }
  82. RenderTexture CreateTextureFor(Camera cam)
  83. {
  84. int rtW = Mathf.FloorToInt(cam.pixelWidth / (int)Quality);
  85. int rtH = Mathf.FloorToInt(cam.pixelHeight / (int)Quality);
  86. RenderTexture rt = new RenderTexture(rtW,rtH, 24);
  87. rt.hideFlags = HideFlags.DontSave;
  88. return rt;
  89. }
  90. public void RenderHelpCameras(Camera currentCam)
  91. {
  92. if (null == m_HelperCameras)
  93. {
  94. m_HelperCameras = new Dictionary<Camera, bool>();
  95. }
  96. if (!m_HelperCameras.ContainsKey(currentCam))
  97. {
  98. m_HelperCameras.Add(currentCam, false);
  99. }
  100. if (m_HelperCameras[currentCam] && !UpdateSceneView)
  101. {
  102. return;
  103. }
  104. if (!m_ReflectionCamera)
  105. {
  106. m_ReflectionCamera = CreateReflectionCameraFor(currentCam);
  107. }
  108. RenderReflectionFor(currentCam, m_ReflectionCamera);
  109. m_HelperCameras[currentCam] = true;
  110. }
  111. public void LateUpdate()
  112. {
  113. if (null != m_HelperCameras)
  114. {
  115. m_HelperCameras.Clear();
  116. }
  117. }
  118. public void WaterTileBeingRendered(Transform tr, Camera currentCam)
  119. {
  120. RenderHelpCameras(currentCam);
  121. if (m_ReflectionCamera && m_SharedMaterial)
  122. {
  123. m_SharedMaterial.SetTexture(reflectionSampler, m_ReflectionCamera.targetTexture);
  124. }
  125. }
  126. public void OnWillRenderObject()
  127. {
  128. WaterTileBeingRendered(transform, Camera.current);
  129. }
  130. void RenderReflectionFor(Camera cam, Camera reflectCamera)
  131. {
  132. if (!reflectCamera)
  133. {
  134. return;
  135. }
  136. if (m_SharedMaterial && !m_SharedMaterial.HasProperty(reflectionSampler))
  137. {
  138. return;
  139. }
  140. #if UNITY_EDITOR
  141. int rtW = Mathf.FloorToInt(cam.pixelWidth / (int)Quality);
  142. int rtH = Mathf.FloorToInt(cam.pixelHeight / (int)Quality);
  143. if (reflectCamera.targetTexture.width != rtW || reflectCamera.targetTexture.width != rtH)
  144. {
  145. DestroyImmediate (reflectCamera.targetTexture);
  146. reflectCamera.targetTexture = CreateTextureFor (cam);
  147. }
  148. #endif
  149. // Optionally disable pixel lights for reflection
  150. int oldPixelLightCount = QualitySettings.pixelLightCount;
  151. if (m_DisablePixelLights)
  152. {
  153. QualitySettings.pixelLightCount = 0;
  154. }
  155. reflectCamera.cullingMask = reflectionMask & ~(1 << LayerMask.NameToLayer("Water"));
  156. //reflectCamera.cullingMask = ~(1<<4) & reflectionMask.value; // never render water layer
  157. SaneCameraSettings(reflectCamera);
  158. reflectCamera.backgroundColor = clearColor;
  159. reflectCamera.clearFlags = reflectSkybox ? CameraClearFlags.Skybox : CameraClearFlags.SolidColor;
  160. if (reflectSkybox)
  161. {
  162. if (cam.gameObject.GetComponent(typeof(Skybox)))
  163. {
  164. Skybox sb = (Skybox)reflectCamera.gameObject.GetComponent(typeof(Skybox));
  165. if (!sb)
  166. {
  167. sb = (Skybox)reflectCamera.gameObject.AddComponent(typeof(Skybox));
  168. }
  169. sb.material = ((Skybox)cam.GetComponent(typeof(Skybox))).material;
  170. }
  171. }
  172. GL.invertCulling = true;
  173. Transform reflectiveSurface = transform; //waterHeight;
  174. Vector3 eulerA = cam.transform.eulerAngles;
  175. reflectCamera.transform.eulerAngles = new Vector3(-eulerA.x, eulerA.y, eulerA.z);
  176. reflectCamera.transform.position = cam.transform.position;
  177. Vector3 pos = reflectiveSurface.transform.position;
  178. pos.y = reflectiveSurface.position.y;
  179. Vector3 normal = reflectiveSurface.transform.up;
  180. float d = -Vector3.Dot(normal, pos) - clipPlaneOffset;
  181. Vector4 reflectionPlane = new Vector4(normal.x, normal.y, normal.z, d);
  182. Matrix4x4 reflection = Matrix4x4.zero;
  183. reflection = CalculateReflectionMatrix(reflection, reflectionPlane);
  184. m_Oldpos = cam.transform.position;
  185. Vector3 newpos = reflection.MultiplyPoint(m_Oldpos);
  186. reflectCamera.worldToCameraMatrix = cam.worldToCameraMatrix * reflection;
  187. Vector4 clipPlane = CameraSpacePlane(reflectCamera, pos, normal, 1.0f);
  188. Matrix4x4 projection = cam.projectionMatrix;
  189. projection = CalculateObliqueMatrix(projection, clipPlane);
  190. reflectCamera.projectionMatrix = projection;
  191. reflectCamera.transform.position = newpos;
  192. Vector3 euler = cam.transform.eulerAngles;
  193. reflectCamera.transform.eulerAngles = new Vector3(-euler.x, euler.y, euler.z);
  194. reflectCamera.Render();
  195. GL.invertCulling = false;
  196. // Restore pixel light count
  197. if (m_DisablePixelLights)
  198. {
  199. QualitySettings.pixelLightCount = oldPixelLightCount;
  200. }
  201. }
  202. void SaneCameraSettings(Camera helperCam)
  203. {
  204. helperCam.depthTextureMode = DepthTextureMode.None;
  205. helperCam.backgroundColor = Color.black;
  206. helperCam.clearFlags = CameraClearFlags.SolidColor;
  207. helperCam.renderingPath = RenderingPath.Forward;
  208. }
  209. static Matrix4x4 CalculateObliqueMatrix(Matrix4x4 projection, Vector4 clipPlane)
  210. {
  211. Vector4 q = projection.inverse * new Vector4(
  212. Sgn(clipPlane.x),
  213. Sgn(clipPlane.y),
  214. 1.0F,
  215. 1.0F
  216. );
  217. Vector4 c = clipPlane * (2.0F / (Vector4.Dot(clipPlane, q)));
  218. // third row = clip plane - fourth row
  219. projection[2] = c.x - projection[3];
  220. projection[6] = c.y - projection[7];
  221. projection[10] = c.z - projection[11];
  222. projection[14] = c.w - projection[15];
  223. return projection;
  224. }
  225. static Matrix4x4 CalculateReflectionMatrix(Matrix4x4 reflectionMat, Vector4 plane)
  226. {
  227. reflectionMat.m00 = (1.0F - 2.0F * plane[0] * plane[0]);
  228. reflectionMat.m01 = (- 2.0F * plane[0] * plane[1]);
  229. reflectionMat.m02 = (- 2.0F * plane[0] * plane[2]);
  230. reflectionMat.m03 = (- 2.0F * plane[3] * plane[0]);
  231. reflectionMat.m10 = (- 2.0F * plane[1] * plane[0]);
  232. reflectionMat.m11 = (1.0F - 2.0F * plane[1] * plane[1]);
  233. reflectionMat.m12 = (- 2.0F * plane[1] * plane[2]);
  234. reflectionMat.m13 = (- 2.0F * plane[3] * plane[1]);
  235. reflectionMat.m20 = (- 2.0F * plane[2] * plane[0]);
  236. reflectionMat.m21 = (- 2.0F * plane[2] * plane[1]);
  237. reflectionMat.m22 = (1.0F - 2.0F * plane[2] * plane[2]);
  238. reflectionMat.m23 = (- 2.0F * plane[3] * plane[2]);
  239. reflectionMat.m30 = 0.0F;
  240. reflectionMat.m31 = 0.0F;
  241. reflectionMat.m32 = 0.0F;
  242. reflectionMat.m33 = 1.0F;
  243. return reflectionMat;
  244. }
  245. static float Sgn(float a)
  246. {
  247. if (a > 0.0F)
  248. {
  249. return 1.0F;
  250. }
  251. if (a < 0.0F)
  252. {
  253. return -1.0F;
  254. }
  255. return 0.0F;
  256. }
  257. Vector4 CameraSpacePlane(Camera cam, Vector3 pos, Vector3 normal, float sideSign)
  258. {
  259. Vector3 offsetPos = pos + normal * clipPlaneOffset;
  260. Matrix4x4 m = cam.worldToCameraMatrix;
  261. Vector3 cpos = m.MultiplyPoint(offsetPos);
  262. Vector3 cnormal = m.MultiplyVector(normal).normalized * sideSign;
  263. return new Vector4(cnormal.x, cnormal.y, cnormal.z, -Vector3.Dot(cpos, cnormal));
  264. }
  265. }
  266. }