Unity3d 镜面折射
网上能找到的基本上是固定管道或表面渲染的shader,
特此翻译为顶点、片段渲染的Shader,
本源码只涉及shader与cs部分,
请自行下载NGUI
unity3d 版本:v4.3.1
RefractionMirror.cs
using UnityEngine; using System.Collections; using System; /// <summary> /// 镜面折射效果 /// </summary> [AddComponentMenu("GameCore/Effect/Refraction/Mirror")] [ExecuteInEditMode] public class RefractionMirror : MonoBehaviour { public bool DisablePixelLights = true; public int TextureSize = 512; public float ClipPlaneOffset = 0; public LayerMask ReflectLayers = -1; private Hashtable _RefractionCameras = new Hashtable(); // Camera -> Camera table private RenderTexture _RefractionTexture = null; private int _OldRefractionTextureSize = 0; private static bool _InsideRendering = false; // This is called when it's known that the object will be rendered by some // camera. We render Refractions and do other updates here. // Because the script executes in edit mode, Refractions for the scene view // camera will just work! void OnWillRenderObject() { if (!enabled || !renderer || !renderer.sharedMaterial || !renderer.enabled) return; Camera cam = Camera.current; if (!cam) return; // Safeguard from recursive Refractions. if (_InsideRendering) return; _InsideRendering = true; Camera RefractionCamera; CreateMirrorObjects(cam, out RefractionCamera); // find out the Refraction plane: position and normal in world space Vector3 pos = transform.position; Vector3 normal = transform.up; // Optionally disable pixel lights for Refraction int oldPixelLightCount = QualitySettings.pixelLightCount; if (DisablePixelLights) QualitySettings.pixelLightCount = 0; CoreTool.CloneCameraModes(cam, RefractionCamera); RefractionCamera.cullingMask = ~(1 << 4) & ReflectLayers.value; // never render water layer RefractionCamera.targetTexture = _RefractionTexture; RefractionCamera.transform.position = cam.transform.position; RefractionCamera.transform.eulerAngles = cam.transform.eulerAngles; RefractionCamera.Render(); Material[] materials = renderer.sharedMaterials; foreach (Material mat in materials) { if (mat.HasProperty("_RefractionTex")) mat.SetTexture("_RefractionTex", _RefractionTexture); } // Set matrix on the shader that transforms UVs from object space into screen // space. We want to just project Refraction texture on screen. Matrix4x4 scaleOffset = Matrix4x4.TRS( new Vector3(0.5f, 0.5f, 0.5f), Quaternion.identity, new Vector3(0.5f, 0.5f, 0.5f)); Vector3 scale = transform.lossyScale; Matrix4x4 mtx = transform.localToWorldMatrix * Matrix4x4.Scale(new Vector3(1.0f / scale.x, 1.0f / scale.y, 1.0f / scale.z)); mtx = scaleOffset * cam.projectionMatrix * cam.worldToCameraMatrix * mtx; foreach (Material mat in materials) { mat.SetMatrix("_ProjMatrix", mtx); } // Restore pixel light count if (DisablePixelLights) QualitySettings.pixelLightCount = oldPixelLightCount; _InsideRendering = false; } // Cleanup all the objects we possibly have created void OnDisable() { if (_RefractionTexture) { DestroyImmediate(_RefractionTexture); _RefractionTexture = null; } foreach (DictionaryEntry kvp in _RefractionCameras) DestroyImmediate(((Camera)kvp.Value).gameObject); _RefractionCameras.Clear(); } // On-demand create any objects we need private void CreateMirrorObjects(Camera currentCamera, out Camera RefractionCamera) { RefractionCamera = null; // Refraction render texture if (!_RefractionTexture || _OldRefractionTextureSize != TextureSize) { if (_RefractionTexture) DestroyImmediate(_RefractionTexture); _RefractionTexture = new RenderTexture(TextureSize, TextureSize, 0); _RefractionTexture.name = "__MirrorRefraction" + GetInstanceID(); _RefractionTexture.isPowerOfTwo = true; _RefractionTexture.hideFlags = HideFlags.DontSave; _RefractionTexture.antiAliasing = 4; _RefractionTexture.anisoLevel = 0; _OldRefractionTextureSize = TextureSize; } // Camera for Refraction RefractionCamera = _RefractionCameras[currentCamera] as Camera; if (!RefractionCamera) // catch both not-in-dictionary and in-dictionary-but-deleted-GO { GameObject go = new GameObject("Mirror Refl Camera id" + GetInstanceID() + " for " + currentCamera.GetInstanceID(), typeof(Camera), typeof(Skybox)); RefractionCamera = go.camera; RefractionCamera.enabled = false; RefractionCamera.transform.position = transform.position; RefractionCamera.transform.rotation = transform.rotation; RefractionCamera.gameObject.AddComponent("FlareLayer"); go.hideFlags = HideFlags.HideAndDontSave; _RefractionCameras[currentCamera] = RefractionCamera; } } }
shader
Shader "GameCore/Mobile/Refraction/Mirror" { Properties { _RefractionTex ("Refraction", 2D) = "white" {TexGen ObjectLinear } _RefractionColor("Color",Color) = (1,1,1,1) } SubShader { Tags { "RenderType"="Opaque"} LOD 100 Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" uniform float4x4 _ProjMatrix; uniform sampler2D _RefractionTex; float4 _RefractionColor; struct outvertex { float4 pos : SV_POSITION; float3 uv : TEXCOORD0; float4 posProj; }; outvertex vert(appdata_tan v) { outvertex o; o.pos = mul (UNITY_MATRIX_MVP,v.vertex); o.posProj = mul(_ProjMatrix, v.vertex); return o; } float4 frag(outvertex i) : COLOR { half4 reflcol = tex2D(_RefractionTex,float2(i.posProj) / i.posProj.w); return reflcol*_RefractionColor; } ENDCG } } }
Shader "GameCore/Refraction/Mirror" { Properties { _RefractionTex ("Refraction ", 2D) = "white" {TexGen ObjectLinear } _RefractionColor("Color",Color) = (1,1,1,1) } SubShader { Tags { "RenderType"="Opaque"} LOD 100 Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" uniform float4x4 _ProjMatrix; uniform sampler2D _RefractionTex; float4 _RefractionColor; struct outvertex { float4 pos : SV_POSITION; float3 uv : TEXCOORD0; }; outvertex vert(appdata_tan v) { outvertex o; o.pos = mul (UNITY_MATRIX_MVP,v.vertex); float3 viewDir = ObjSpaceViewDir(v.vertex); o.uv = mul(_ProjMatrix,float4(viewDir,0)); return o; } float4 frag(outvertex i) : COLOR { half4 reflcol = tex2Dproj(_RefractionTex,i.uv); return reflcol*_RefractionColor; } ENDCG } } }
Unity3d 镜面折射 vertex and frag Shader源码,布布扣,bubuko.com
时间: 2024-10-22 14:35:11