unity之shader学习笔记(五)--纹理

来源:互联网 发布:数据库视频教程 编辑:程序博客网 时间:2024/05/31 18:31

纹理映射

纹理坐标(也称为u/v坐标,横坐标是u,纵坐标是v,长宽是1)
一般将纹理的颜色代替漫反射的颜色,这样就会看到图像,一般是片元函数处理

纹理的类型有

Normalmap            法线贴图EditorGUI andLegacy  菜单栏图标Sprite               2D图片和UI界面Cubemap              立方体纹理,做环境盒子cookie               制作阴影,使手电筒的光从圆形变成另一种形状,类似蝙蝠灯的中间阴影,lightmap             光照贴图,使用避免实时计算Advanced             自定义

如何使用纹理呢,代码如下

Shader "Custom/10-FirstShader" {      Properties{        //_Diffuse("Diffuse Color",Color) = (1,1,1,1)        _MainTex("Main Tex",2D) = "white"{}             _Color("Color",Color) = (1,1,1,1)        _Specular("Specular Color",Color) = (1,1,1,1)        _Gloss("Gloss",Range(10,200)) = 20    }        SubShader{        Pass{        Tags{ "LightMode" = "ForwardBase" }            CGPROGRAM    #include "Lighting.cginc"    #pragma vertex vert    #pragma fragment frag            //fixed4 _Diffuse;        fixed4 _Specular;        half _Gloss;        sampler2D _MainTex;        fixed4 _Color;        struct a2v {            float4 vertex:POSITION;            float3 normal:NORMAL;            float4 texcoord:TEXCOORD0;//获取纹理坐标点        };        struct v2f {            float4 svPos:SV_POSITION;            float3 worldNormal:TEXCOORD0;//世界空间下法线向量            float4 worldVertex:TEXCOORD1;//用于传递世界空间下顶点坐标            float4 uv:TEXCOORD2;//用于传递uv坐标        };        v2f vert(a2v v) {            v2f f;            f.svPos = mul(UNITY_MATRIX_MVP, v.vertex);            f.worldNormal = UnityObjectToWorldNormal(v.normal);            f.worldVertex = mul(v.vertex, unity_WorldToObject);            f.uv = v.texcoord;//将纹理坐标传递到片元函数            return f;        }        fixed4 frag(v2f f) :SV_Target{        //法线向量        fixed3 normalDir = normalize(f.worldNormal);        //灯光向量        fixed3 lightDir = normalize(WorldSpaceLightDir(f.worldVertex));        //内置函数,可以获取到纹理上某个纹理坐标点的颜色值        //这里只用到了u,v两个值        fixed3 texColor = tex2D(_MainTex,f.uv.xy)*_Color.rgb;        //使用获取到的颜色值替换掉原先漫反射光产生的颜色值        fixed3 diffuse = _LightColor0.rgb * texColor * max(dot(normalDir, lightDir), 0);        //相机视野向量        fixed3 viewDir = normalize(UnityWorldSpaceViewDir(f.worldVertex));        //获取半分线        fixed3 halfDir = normalize(lightDir + viewDir);        //获取高光        fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(dot(normalDir, halfDir), 0), _Gloss);        //最后环境光和纹理做了一个融合   这样修改环境光纹理也不会受到太大影响,不会使得纹理模糊        fixed3 tempColor = diffuse + specular + UNITY_LIGHTMODEL_AMBIENT.rgb*texColor;        return fixed4(tempColor, 1);        }            ENDCG        }        }        Fallback "Specular"}

这里写图片描述
上述代码中,定义了一个纹理参数_MainTex,还有一个_Color用来与纹理叠加,能够控制纹理的颜色。

再看Inspector面板,可以看到纹理属性不仅可以选择纹理图案,还有Tiling属性和Offset属性。
Tilling 是控制纹理进行压缩,Tilling值越大,那么模型上显示的纹理数量也就越多,x控制纹理的宽度,y控制纹理的高度
Offset属性是控制材质的偏移,通过修改Offset下的x的值来使纹理进行左右移动,通过修改Offset下的y的值来使纹理进行上下的移动

那么如何使用这两个值呢,Tilling和Offset是纹理自带的属性,可以直接使用:
定义变量
fixed4 _MainTex_ST;
变量名称是固定的,后面加_ST,其中前两个属性代表S 理解为Scale,后两个属性代表T 理解为Transform

使用缩放变量的话,将

f.uv = v.texcoord;

替换为

f.uv = v.texcoord*_MainTex_ST.xy

使用平移变量的话,将

f.uv = v.texcoord;

f.uv = v.texcoord+_MainTex_ST.zw;映射
可以使得物体有凹凸效果。
法线贴图
使用法线贴图的颜色值修改某一点的法线,以此来实现更真实的效果。ps:法线贴图应该和贴图大小相同,一一配套对应

需要注意的是:法线每个轴取值范围是-1到1,而颜色的值范围是0到1,因此会进行变换运算
像素值 = (法线某轴的值+1)/2
这样像素值就能存下法线的值,需要使用时只需要还原一下就行
法线某轴的值 = 像素值*2-1

法线贴图一般都是采用模型顶点的切线空间的坐标来存储法线,,这种纹理被称为切线空间的法线纹理,而有些贴图是将模型空间中的表面进行直接修改,然后将法线存储在一张纹理中,这种纹理被称之为模型空间的法线纹理,不过该纹理只能应用于一种模型,不如切线空间的法线纹理应用范围广。

那么如何在shader中使用法线贴图呢
代码如下

Shader "Custom/11-FirstShader"{    Properties{        //_Diffuse("Diffuse Color",Color) = (1,1,1,1)        _Color("Color",Color) = (1,1,1,1)        _MainTex("Main Tex",2D) = "white"{}//定义一个法线贴图变量//bump是一个内置模型,意思是当没有指定法线贴图时,使用bump的法线贴图//一般指定的纹理是切线空间下的法线纹理,也可以使用模型空间下的法线纹理,只要注意坐标所在空间相同即可    _NormalMap("Normal Map",2D) = "bump"{}    _BumpScale("Bump Scale",Float)=1    }        SubShader{        Pass{        Tags{ "LightMode" = "ForwardBase" }        CGPROGRAM#include "Lighting.cginc"#pragma vertex vert#pragma fragment frag        //fixed4 _Diffuse;        fixed4 _Color;        sampler2D _MainTex;        float4 _MainTex_ST;//引用法线贴图变量        sampler2D _NormalMap;        float4 _NormalMap_ST;        float _BumpScale;        struct a2v {            float4 vertex:POSITION;//切线空间的确定是通过存储到模型里面的法线和切线确定的            float3 normal:NORMAL;            float4 tangent:TANGENT;//tangent.w是用来确定切线空间中坐标轴的方向的             float4 texcoord:TEXCOORD0;        };        struct v2f {            float4 svPos:SV_POSITION;            //float3 worldNormal:TEXCOORD0;            //float4 worldVertex:TEXCOORD1;            float3 lightDir : TEXCOORD0;            float4 uv:TEXCOORD1;//xy用来存储纹理的uv坐标,zw用来存储法线贴图的纹理坐标        };        //切线空间根据顶点一直在变化,因此只能在顶点函数中获取        //因此该顶点光照的方向向量也在顶点函数中获取        v2f vert(a2v v) {            v2f f;            f.svPos = mul(UNITY_MATRIX_MVP, v.vertex);        //  f.worldNormal = UnityObjectToWorldNormal(v.normal);        //  f.worldVertex = mul(v.vertex, _World2Object);            f.uv.xy = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw;            f.uv.zw = v.texcoord.xy * _NormalMap_ST.xy + _NormalMap_ST.zw;            TANGENT_SPACE_ROTATION;//调用这个后之后,会得到一个矩阵 rotation 这个矩阵用来把模型空间下的方向转换成切线空间下            //ObjSpaceLightDir(v.vertex)//得到模型空间下的平行光方向             f.lightDir = mul(rotation, ObjSpaceLightDir(v.vertex));             return f;         }        //把所有跟法线方向相关的运算都放在切线空间下        //从法线贴图里取到的法线方向都是切线空间下的        fixed4 frag(v2f f) :SV_Target{            //fixed3 normalDir = normalize(f.worldNormal);            //获取纹理坐标该点的颜色值              fixed4 normalColor = tex2D(_NormalMap,f.uv.zw);            //将颜色值转换为法线的值            //  fixed3 tangentNormal = normalize(  normalColor.xyz * 2 - 1 ) ; //切线空间下的法线//UnpackNormal 是系统自带的转换方法           fixed3 tangentNormal = UnpackNormal(normalColor);            tangentNormal.xy = tangentNormal.xy*_BumpScale;            tangentNormal = normalize(tangentNormal);            fixed3 lightDir = normalize(f.lightDir);            fixed3 texColor = tex2D(_MainTex, f.uv.xy)*_Color.rgb;            fixed3 diffuse = _LightColor0.rgb * texColor * max(dot(tangentNormal, lightDir), 0);            fixed3 tempColor = diffuse + UNITY_LIGHTMODEL_AMBIENT.rgb*texColor;            return fixed4(tempColor, 1);        }        ENDCG    }    }        Fallback "Specular"}

有无法线贴图对比
这里写图片描述

0 0