加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

shader实例(二十二)TexGen-球面贴图SphereMap

(2015-01-19 20:32:13)
标签:

spheremap

球面贴图

分类: Shader

球面贴图一般用于环境反射,如下图(左边为球面贴图,右边为正常贴图),一个镜面水晶球在这只猫的前方,而这只猫也正看着这个水晶球,效果是这只大头猫的头变的更大了。http://www/uc/myshow/blog/misc/gif/E___6724EN00SIGG.gif

http://s7/mw690/002wvREMgy6Pj9DuQHI06&690

原理:

1.将顶点转换到摄像机空间

2.根据该顶点的摄像机【入射向量 I 】和【法线向量N】计算【反射向量R】

3.将【反射向量R】与【摄像机向量(0,0,1)】相加,计算出【过渡向量m】

4.求【过渡向量m】单位向量,再将值映射为uv的值域上,求得纹理坐标

如图:

http://s1/mw690/002wvREMgy6Pjgfikk8d0&690
基础知识:

求反射向量 http://www.cnblogs.com/graphics/archive/2013/02/21/2920627.html

 

代码和详细分析如下:

Shader "Custom/球面贴图" {

   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; // 输出的球面纹理信息

            ;

            

            // 求反射向量。这个底层有封装,拆开就是这样的

            float3 reflect(float3 I,float3 N)

            {

                return 2.0*N *dot(N,I);

            }

            

            float2 GetUV(float3 r)

            {

                // 开根号对过渡向量m求模(反射向量r+摄像机向量(0,0,1)为过渡向量m)

                float sqrt(r.x r.x r.y r.y (r.z 1.0(r.z 1.0)); 

                // 求过渡向量m的单位向量

                float3 float3(r.x m, r.y m, r.z m);

                // 顶点值域为[-1,1],转为UV的值域[0,1]

                // 在边缘处UV信息也是更靠近图片里面,才形成镜面水晶球的效果吧

                return float2(0.5 n.x 0.5,0.5 n.y 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 posEyeSpace float3(0,0,0);

                // 将顶点的法线向量转换到摄像机坐标

                float3 mul((float3x3)UNITY_MATRIX_MV,v.normal);

                // 求法线单位向量

                normalize(N);

                // 根据入射向量和法线向量求反射向量

                float3 reflect(I,N);

                // 根据反射向量获取最终的UV信息

                o.uv2 GetUV(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

        }

    }

}

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有