• Unity3D教程宝典之Shader篇:第二十四讲Reflection Mapping


     
     
    简介
    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
            }
        }
    }
    

      

  • 相关阅读:
    xshell下载官网地址
    logo
    网站案例搜集
    cnblogs修改网站图标icon
    父页面调用子页面方法, 子页面加载父页面传送的数据
    对Java的常用对象(POJO、DTO、PO、BO、VO、DAO)详细解释及应用场景
    关于jsp发起请求加载datagrid数据(草稿)
    接口测试-Http状态码-postman上传文件
    httpclient获取响应实体和信息的封装方法(解耦更新)
    使用httpClient调用接口获取响应数据
  • 原文地址:https://www.cnblogs.com/zdlbbg/p/4329533.html
Copyright © 2020-2023  润新知