標籤:
轉載自風宇沖Unity3D教程學院
簡介Reflection Mapping,又叫Environment Mapping。對應TexGen的SphereMap和CubeReflect。是最快的reflect周圍環境的演算法最早出現的是Sphere Mapping,之後被Cube Mapping取代。Reflection Mapping比射線追蹤(Ray Tracing)高效得多Reflection Mapping的前提是2個假設(1)入射線來自無限距離(2)物體是凸的,沒有自身的相互反射
Sphere Mapping已經過時的技術,優點:1效率高2也可以用普通貼圖缺點:1.只有用魚眼貼圖,並處於正視觀景窗的視點時才是最佳效果。其他情況如使用普通貼圖,處於其他位置時效果一般。2 浪費貼圖的4個邊角,圓形地區之外的紋理值不會對結果產生影響。原理:在一幅平面紋理映像中對各個方向的顏色進行編碼就相當於把一個擦得鋥亮的完美球體放在環境的中央,然後在極遠處用長焦鏡頭對它進行拍照。需要編碼的地區就是覆蓋整個紋理映像的一個圓形地區,它與紋理映像的頂、底、左、右邊緣相切。這個圓形地區之外的紋理值不會對結果產生影響,因為它們不會在環境紋理中使用。貼圖:把一個擦得鋥亮的完美球體放在環境的中央,用魚眼鏡頭的相機拍照,將球體沿著頂、底、左、右邊緣切出來一張照片,那麼就是貼圖了。有了貼圖後,在攝像機座標系下,根據I,N得出R. 再由R得出UV.即使沒有魚眼貼圖,用普通貼圖也有一定的類似效果。 貼圖魚眼貼圖 普通貼圖
效果
計算方法:1 在攝像機座標系中根據I:入射向量 和 N:法線向量 計算出 R:反射向量R = I - 2 * N * dot(N,I)2 再根據固定演算法 由R計算出 uv
float2 R_To_UV(float3 r){ float interim = 2.0 * sqrt(r.x * r.x + r.y * r.y + (r.z + 1.0) * (r.z + 1.0)); return float2(r.x/interim+0.5,r.y/interim+0.5); }
Fixed and Fragment Shader代碼
Shader "Custom/Texgen_SphereMap_FragMine" { Properties { _Reflectivity ("Reflectivity", Range (0,1)) = 0.5 _MainTex("Base", 2D) = "white" _Environment ("Environment", 2D) = "white" } SubShader { Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" sampler2D _MainTex; sampler2D _Environment; float4 _MainTex_ST; float _Reflectivity; struct v2f { float4 pos : SV_POSITION; float2 uv : TEXCOORD0; float2 uv2:TEXCOORD1; } ; //I:入射向量 N:法線向量 R:反射向量 float3 reflect(float3 I,float3 N) { return I - 2.0*N *dot(N,I); } // float2 R_To_UV(float3 r) { float interim = 2.0 * sqrt(r.x * r.x + r.y * r.y + (r.z + 1.0) * (r.z + 1.0)); return float2(r.x/interim+0.5,r.y/interim+0.5); } v2f vert (appdata_base v) { v2f o; o.pos = mul(UNITY_MATRIX_MVP,v.vertex); o.uv = TRANSFORM_TEX(v.texcoord,_MainTex); float3 posEyeSpace = mul(UNITY_MATRIX_MV,v.vertex).xyz; float3 I = posEyeSpace - float3(0,0,0); float3 N = mul((float3x3)UNITY_MATRIX_MV,v.normal); N = normalize(N); float3 R = reflect(I,N); o.uv2 = R_To_UV(R); return o; } float4 frag (v2f i) : COLOR { float4 reflectiveColor = tex2D(_Environment,i.uv2); float4 decalColor = tex2D(_MainTex,i.uv); float4 outp = lerp(decalColor,reflectiveColor,_Reflectivity); return outp; } ENDCG } }}
Cube Mapping主流技術優點:真正的反映環境,不受位置角度限制。缺點:效率比起Sphere Mapping低不少原理及計算方法:1 在全局座標系中根據I:入射向量 和 N:法線向量 計算出 R:反射向量R = I - 2 * N * dot(N,I)2 再由R 使用texCUBE進行紋理映射得到顏色texCUBE(_Environment,i.R); Fixed and Fragment Shader代碼
Shader "Custom/Texgen_CubeR_FragMine" { Properties { _Reflectivity ("Reflectivity", Range (0,1)) = 0.5 _MainTex("Base", 2D) = "white" _Environment ("Environment", Cube) = "white" } SubShader { Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" sampler2D _MainTex; samplerCUBE _Environment; float4 _MainTex_ST; float _Reflectivity; struct v2f { float4 pos : SV_POSITION; float2 uv : TEXCOORD0; float3 R:TEXCOORD1; } ; float3 reflect(float3 I,float3 N) { return I - 2.0*N *dot(N,I); } v2f vert (appdata_base v) { v2f o; o.pos = mul(UNITY_MATRIX_MVP,v.vertex); o.uv = TRANSFORM_TEX(v.texcoord,_MainTex); float3 posW = mul(_Object2World,v.vertex).xyz; float3 I = posW -_WorldSpaceCameraPos.xyz; float3 N = mul((float3x3)_Object2World,v.normal); N = normalize(N); o.R = reflect(I,N); return o; } float4 frag (v2f i) : COLOR { float4 reflectiveColor = texCUBE(_Environment,i.R); float4 decalColor = tex2D(_MainTex,i.uv); float4 outp = lerp(decalColor,reflectiveColor,_Reflectivity); return outp; } ENDCG } }}
Unity3D教程寶典之Shader篇:第二十四講Reflection Mapping