找回密码
 立即注册
查看: 6767|回复: 86

[渲染] unity3D中镜面反射

[复制链接]
发表于 2012-12-3 09:57 | 显示全部楼层 |阅读模式
新建一个shader
  1. Shader "FX/Mirror Reflection" {
  2. Properties {
  3. _MainTex ("Base (RGB)", 2D) = "white" {}
  4. _ReflectionTex ("Reflection", 2D) = "white" { TexGen ObjectLinear }
  5. }

  6. // two texture cards: full thing
  7. Subshader {
  8. Pass {
  9. SetTexture[_MainTex] { combine texture }
  10. SetTexture[_ReflectionTex] { matrix [_ProjMatrix] combine texture * previous }
  11. }
  12. }

  13. // fallback: just main texture
  14. Subshader {
  15. Pass {
  16. SetTexture [_MainTex] { combine texture }
  17. }
  18. }

  19. }
复制代码
新建一个脚本
  1. using UnityEngine;
  2. using System.Collections;

  3. // This is in fact just the Water script from Pro Standard Assets,
  4. // just with refraction stuff removed.

  5. [ExecuteInEditMode] // Make mirror live-update even when not in play mode
  6. public class MirrorReflection : MonoBehaviour
  7. {
  8.     public bool m_DisablePixelLights = true;
  9.     public int m_TextureSize = 256;
  10.     public float m_ClipPlaneOffset = 0.07f;

  11.     public LayerMask m_ReflectLayers = -1;

  12.     private Hashtable m_ReflectionCameras = new Hashtable(); // Camera -> Camera table

  13.     private RenderTexture m_ReflectionTexture = null;
  14.     private int m_OldReflectionTextureSize = 0;

  15.     private static bool s_InsideRendering = false;

  16.     // This is called when it's known that the object will be rendered by some
  17.     // camera. We render reflections and do other updates here.
  18.     // Because the script executes in edit mode, reflections for the scene view
  19.     // camera will just work!
  20.     public void OnWillRenderObject()
  21.     {
  22.         if (!enabled || !renderer || !renderer.sharedMaterial || !renderer.enabled)
  23.             return;

  24.         Camera cam = Camera.current;
  25.         if (!cam)
  26.             return;

  27.         // Safeguard from recursive reflections.
  28.         if (s_InsideRendering)
  29.             return;
  30.         s_InsideRendering = true;

  31.         Camera reflectionCamera;
  32.         CreateMirrorObjects(cam, out reflectionCamera);

  33.         // find out the reflection plane: position and normal in world space
  34.         Vector3 pos = transform.position;
  35.         Vector3 normal = transform.up;

  36.         // Optionally disable pixel lights for reflection
  37.         int oldPixelLightCount = QualitySettings.pixelLightCount;
  38.         if (m_DisablePixelLights)
  39.             QualitySettings.pixelLightCount = 0;

  40.         UpdateCameraModes(cam, reflectionCamera);

  41.         // Render reflection
  42.         // Reflect camera around reflection plane
  43.         float d = -Vector3.Dot(normal, pos) - m_ClipPlaneOffset;
  44.         Vector4 reflectionPlane = new Vector4(normal.x, normal.y, normal.z, d);

  45.         Matrix4x4 reflection = Matrix4x4.zero;
  46.         CalculateReflectionMatrix(ref reflection, reflectionPlane);
  47.         Vector3 oldpos = cam.transform.position;
  48.         Vector3 newpos = reflection.MultiplyPoint(oldpos);
  49.         reflectionCamera.worldToCameraMatrix = cam.worldToCameraMatrix * reflection;

  50.         // Setup oblique projection matrix so that near plane is our reflection
  51.         // plane. This way we clip everything below/above it for free.
  52.         Vector4 clipPlane = CameraSpacePlane(reflectionCamera, pos, normal, 1.0f);
  53.         Matrix4x4 projection = cam.projectionMatrix;
  54.         CalculateObliqueMatrix(ref projection, clipPlane);
  55.         reflectionCamera.projectionMatrix = projection;

  56.         reflectionCamera.cullingMask = ~(1 << 4) & m_ReflectLayers.value; // never render water layer
  57.         reflectionCamera.targetTexture = m_ReflectionTexture;
  58.         GL.SetRevertBackfacing(true);
  59.         reflectionCamera.transform.position = newpos;
  60.         Vector3 euler = cam.transform.eulerAngles;
  61.         reflectionCamera.transform.eulerAngles = new Vector3(0, euler.y, euler.z);
  62.         reflectionCamera.Render();
  63.         reflectionCamera.transform.position = oldpos;
  64.         GL.SetRevertBackfacing(false);
  65.         Material[] materials = renderer.sharedMaterials;
  66.         foreach (Material mat in materials)
  67.         {
  68.             if (mat.HasProperty("_ReflectionTex"))
  69.                 mat.SetTexture("_ReflectionTex", m_ReflectionTexture);
  70.         }

  71.         // Set matrix on the shader that transforms UVs from object space into screen
  72.         // space. We want to just project reflection texture on screen.
  73.         Matrix4x4 scaleOffset = Matrix4x4.TRS(
  74.         new Vector3(0.5f, 0.5f, 0.5f), Quaternion.identity, new Vector3(0.5f, 0.5f, 0.5f));
  75.         Vector3 scale = transform.lossyScale;
  76.         Matrix4x4 mtx = transform.localToWorldMatrix * Matrix4x4.Scale(new Vector3(1.0f / scale.x, 1.0f / scale.y, 1.0f / scale.z));
  77.         mtx = scaleOffset * cam.projectionMatrix * cam.worldToCameraMatrix * mtx;
  78.         foreach (Material mat in materials)
  79.         {
  80.             mat.SetMatrix("_ProjMatrix", mtx);
  81.         }

  82.         // Restore pixel light count
  83.         if (m_DisablePixelLights)
  84.             QualitySettings.pixelLightCount = oldPixelLightCount;

  85.         s_InsideRendering = false;
  86.     }


  87.     // Cleanup all the objects we possibly have created
  88.     void OnDisable()
  89.     {
  90.         if (m_ReflectionTexture)
  91.         {
  92.             DestroyImmediate(m_ReflectionTexture);
  93.             m_ReflectionTexture = null;
  94.         }
  95.         foreach (DictionaryEntry kvp in m_ReflectionCameras)
  96.             DestroyImmediate(((Camera)kvp.Value).gameObject);
  97.         m_ReflectionCameras.Clear();
  98.     }


  99.     private void UpdateCameraModes(Camera src, Camera dest)
  100.     {
  101.         if (dest == null)
  102.             return;
  103.         // set camera to clear the same way as current camera
  104.         dest.clearFlags = src.clearFlags;
  105.         dest.backgroundColor = src.backgroundColor;
  106.         if (src.clearFlags == CameraClearFlags.Skybox)
  107.         {
  108.             Skybox sky = src.GetComponent(typeof(Skybox)) as Skybox;
  109.             Skybox mysky = dest.GetComponent(typeof(Skybox)) as Skybox;
  110.             if (!sky || !sky.material)
  111.             {
  112.                 mysky.enabled = false;
  113.             }
  114.             else
  115.             {
  116.                 mysky.enabled = true;
  117.                 mysky.material = sky.material;
  118.             }
  119.         }
  120.         // update other values to match current camera.
  121.         // even if we are supplying custom camera&projection matrices,
  122.         // some of values are used elsewhere (e.g. skybox uses far plane)
  123.         dest.farClipPlane = src.farClipPlane;
  124.         dest.nearClipPlane = src.nearClipPlane;
  125.         dest.orthographic = src.orthographic;
  126.         dest.fieldOfView = src.fieldOfView;
  127.         dest.aspect = src.aspect;
  128.         dest.orthographicSize = src.orthographicSize;
  129.     }

  130.     // On-demand create any objects we need
  131.     private void CreateMirrorObjects(Camera currentCamera, out Camera reflectionCamera)
  132.     {
  133.         reflectionCamera = null;

  134.         // Reflection render texture
  135.         if (!m_ReflectionTexture || m_OldReflectionTextureSize != m_TextureSize)
  136.         {
  137.             if (m_ReflectionTexture)
  138.                 DestroyImmediate(m_ReflectionTexture);
  139.             m_ReflectionTexture = new RenderTexture(m_TextureSize, m_TextureSize, 16);
  140.             m_ReflectionTexture.name = "__MirrorReflection" + GetInstanceID();
  141.             m_ReflectionTexture.isPowerOfTwo = true;
  142.             m_ReflectionTexture.hideFlags = HideFlags.DontSave;
  143.             m_OldReflectionTextureSize = m_TextureSize;
  144.         }

  145.         // Camera for reflection
  146.         reflectionCamera = m_ReflectionCameras[currentCamera] as Camera;
  147.         if (!reflectionCamera) // catch both not-in-dictionary and in-dictionary-but-deleted-GO
  148.         {
  149.             GameObject go = new GameObject("Mirror Refl Camera id" + GetInstanceID() + " for " + currentCamera.GetInstanceID(), typeof(Camera), typeof(Skybox));
  150.             reflectionCamera = go.camera;
  151.             reflectionCamera.enabled = false;
  152.             reflectionCamera.transform.position = transform.position;
  153.             reflectionCamera.transform.rotation = transform.rotation;
  154.             reflectionCamera.gameObject.AddComponent("FlareLayer");
  155.             go.hideFlags = HideFlags.HideAndDontSave;
  156.             m_ReflectionCameras[currentCamera] = reflectionCamera;
  157.         }
  158.     }

  159.     // Extended sign: returns -1, 0 or 1 based on sign of a
  160.     private static float sgn(float a)
  161.     {
  162.         if (a > 0.0f) return 1.0f;
  163.         if (a < 0.0f) return -1.0f;
  164.         return 0.0f;
  165.     }

  166.     // Given position/normal of the plane, calculates plane in camera space.
  167.     private Vector4 CameraSpacePlane(Camera cam, Vector3 pos, Vector3 normal, float sideSign)
  168.     {
  169.         Vector3 offsetPos = pos + normal * m_ClipPlaneOffset;
  170.         Matrix4x4 m = cam.worldToCameraMatrix;
  171.         Vector3 cpos = m.MultiplyPoint(offsetPos);
  172.         Vector3 cnormal = m.MultiplyVector(normal).normalized * sideSign;
  173.         return new Vector4(cnormal.x, cnormal.y, cnormal.z, -Vector3.Dot(cpos, cnormal));
  174.     }

  175.     // Adjusts the given projection matrix so that near plane is the given clipPlane
  176.     // clipPlane is given in camera space. See article in Game Programming Gems 5.
  177.     private static void CalculateObliqueMatrix(ref Matrix4x4 projection, Vector4 clipPlane)
  178.     {
  179.         Vector4 q = projection.inverse * new Vector4(
  180.         sgn(clipPlane.x),
  181.         sgn(clipPlane.y),
  182.         1.0f,
  183.         1.0f
  184.         );
  185.         Vector4 c = clipPlane * (2.0F / (Vector4.Dot(clipPlane, q)));
  186.         // third row = clip plane - fourth row
  187.         projection[2] = c.x - projection[3];
  188.         projection[6] = c.y - projection[7];
  189.         projection[10] = c.z - projection[11];
  190.         projection[14] = c.w - projection[15];
  191.     }

  192.     // Calculates reflection matrix around the given plane
  193.     private static void CalculateReflectionMatrix(ref Matrix4x4 reflectionMat, Vector4 plane)
  194.     {
  195.         reflectionMat.m00 = (1F - 2F * pla


  196. ne[0] * plane[0]);
  197.         reflectionMat.m01 = (-2F * plane[0] * plane[1]);
  198.         reflectionMat.m02 = (-2F * plane[0] * plane[2]);
  199.         reflectionMat.m03 = (-2F * plane[3] * plane[0]);

  200.         reflectionMat.m10 = (-2F * plane[1] * plane[0]);
  201.         reflectionMat.m11 = (1F - 2F * plane[1] * plane[1]);
  202.         reflectionMat.m12 = (-2F * plane[1] * plane[2]);
  203.         reflectionMat.m13 = (-2F * plane[3] * plane[1]);

  204.         reflectionMat.m20 = (-2F * plane[2] * plane[0]);
  205.         reflectionMat.m21 = (-2F * plane[2] * plane[1]);
  206.         reflectionMat.m22 = (1F - 2F * plane[2] * plane[2]);
  207.         reflectionMat.m23 = (-2F * plane[3] * plane[2]);

  208.         reflectionMat.m30 = 0F;
  209.         reflectionMat.m31 = 0F;
  210.         reflectionMat.m32 = 0F;
  211.         reflectionMat.m33 = 1F;
  212.     }
  213. }
复制代码
如图把这两个赋在物体身上  




本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×

评分

参与人数 2 +2 收起 理由
yugo215 + 1 很给力!
graywolfx21 + 1 很给力!

查看全部评分

发表于 2012-12-3 14:10 | 显示全部楼层
好牛逼的脚本  收藏了{:5_412:}
 楼主| 发表于 2012-12-3 15:01 | 显示全部楼层
顶顶顶顶{:5_397:}{:5_397:}{:5_397:}{:5_397:}{:5_397:}{:5_397:}
发表于 2012-12-13 13:07 | 显示全部楼层
谢谢分享  学习学习
发表于 2012-12-13 15:56 | 显示全部楼层
回复看图咯
发表于 2013-7-26 18:45 | 显示全部楼层
谢谢分享  学习学习
发表于 2014-5-26 10:25 | 显示全部楼层

膜拜中。。。。{:soso__7524161091986203637_5:}
发表于 2017-3-1 08:37 | 显示全部楼层
楼主是超人
发表于 2017-3-1 08:55 | 显示全部楼层
顶顶多好
发表于 2017-3-1 08:45 | 显示全部楼层
真心顶
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-11-22 23:01 , Processed in 0.101816 second(s), 29 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表