shader入门精要读书笔记16 基础纹理-渐变纹理、遮罩纹理

一、渐变纹理

也是由Value公司在制作<军团要塞2>提出,
可以保证物体的轮廓线相比之前使用的传统漫反射光照更加明显,能够提供多种色调变化,常用于卡通渲染中。

基本思想:
在顶点着色器中将法线、顶点转换到世界空间,计算平铺、偏移后的纹理坐标,传递到片元着色器中;
在片元着色器中,环境光如果没有使用单张纹理那么不必计算材质反射率,直接采用系统环境光。计算漫反射时采用半兰伯特模型,使用halfLambert构建纹理坐标对渐变纹理采样。高光反射使用Blinn-Phong模型h来计算。

代码:

Shader “Untiy Shaders Book/Chapter 7/Ramp Texture”
{
	Properties
	{
		_Color{"Color TInt",Color}=(1,1,1,1)
		_RampTex("Ramp Tex",2D)="white"{}  //渐变纹理
		_Specular("Specular",Color)=(1,1,1,1)
		_Gloss("Gloss",Range(8.0,256))=20
	}
	Subshader
	{		
		Pass
		{
			Tags{"LightMode"="ForwardBase"}
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#include "Lighting.cginc"
			fixed4 _Color;
			sampler2D _RampTex;
			float4 _RampTex_ST;
			fixed4 _Specular;
			float4 _Gloss;
			struct a2v
			{
				float4 vertex : POSITION;
				float3 normal ; NORMAL;
				float4 texcoord : TEXCOORD0;
			}
			struct v2f
			{
				float4 pos : SV_POSITION;
				float3 worldNormal : TEXCOORD0;
				float3 worldPos : TEXCOORD1;
				float2 uv : TEXCOORD2;
			}
			v2f vert(a2v v)
			{
				v2f o;
				o.pos = mul(UNITY_MATRIX_MVP,v.vertex);
				o.worldNormal = UntiyObjectToWorldNormal(v.normal);
				o.worldPos = mul(_Object2World,v.vertex).xyz;
				o.uv = TANSFORM_TEX(v.texcoord,_RampTex); //计算平铺、偏移后的纹理坐标
				return o;
			}
			fixed4 frag(v2f i) : SV_Target
			{
				fixed3 worldNormal = normalize(i.worldNormal);
				fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
				fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz; //没有单张纹理,所以没有albedo
				fixed halfLambert = 0.5*dot(worldNormal,worldLightDir)+0.5; //使用半兰伯特模型
				fixed3 diffuseColor = tex2D(_RampTex,fixed2(halfLambert,halfLambert)).rgb*_Color.rgb; //使用halfLambert构造纹理坐标,对RampLambert进行采样。
				fixed3 diffuse = _LightColor.rgb*diffuseColor; //计算半兰伯特的光照漫反射
				fixed3 viewDir = normalize(UnityWorldSpaceViewDir(i.worldPos)); 
				fixed3 halfDir = normalize(worldLightDir+viewDir);
				fixed3 specular = _LightColor0.rgb*_Specular.rgb*pow(max(0,dot(worldNormal,halfDir)),_Gloss);
				return fixed4(ambient+diffuse+specular,1.0);
			}
		}
	}
}

需要注意的是:Wrap Mode需要设置成Clamp,Repeat可能会有取小数部分,从而有小黑点的情况。具体见158页。

二、遮罩纹理

遮罩纹理非常有用,它可以保护某个区域,免于某些修改。
可以使用一张遮罩纹理控制整体光照,某些区域的强或者弱,
还可以制作地形时,混合多种不同纹理。
总之,可以更加精准的(像素级别)控制模型表面的各种性质。

基本思想:
主要是在片元着色器中采样的到遮罩纹理的纹素值,然后使用某个通道的值,与表面属性相乘,通道为0时,就保护表面不受该属性的影响。

代码:

Shader "Untiy Shaders Book/Chapte3r 7/Normal Map In Tangent Space"
{
	 Properties
	 {
		  _Color("Color Tint",Color)=(1,1,1,1)  //整体模型色调
		  _MainTex("Main Tex",2D)="white"{} //纹理的声明,初始值全白色。(大概是有了纹理之后,使用纹理来充当漫反射的颜色	_Diffuse)
		  _BumpMap("Normal Map",2D)="bump"{} //法线纹理,使用bump作为默认值,bump是模型自带的法线信息
		  _BumpScale("Bump Scale",Float)=1.0 //控制法线纹理作用下的凹凸程度
		  SpecularMask("Specular Mask",2D) = "white"{}  //高光反射遮罩纹理
		  SpecularScale("Specular Scale",Float) = 1.0  //用来控制遮罩影响度的系数
		  _Specular("Specular",Color)=(1,1,1,1) //控制高光反射颜色
		  _Gloss("Gloss",Range(8.0,256))=20 //控制高光反射范围
	 }
	 SubShader
	 {
		  Pass
		  {
			   Tags{"LightMode"="ForwardBase"} //光照模式定义
			   CGPROGRAM
			   #pragma vertex vert
			   #pragma fragment frag
			   #include "Lighting.cginc"
			   fixed4 _Color;
			   sample2D _MainTex;
			   float4 _MainTex_ST; //得到纹理平铺偏移属性,主纹理、法线纹理、遮罩纹理 共用,可以节省空间。
			   sample2D _BumpMap;
			   float _BumpScale;
			   sampler2D _SpecularMask; //遮罩纹理
			   float _SpecularScale; //遮罩影响系数
			   fixed4 _Specular;
			   float _Gloss;
			   struct a2v
			   {
				    float4 vertex : POSITION;
				    float3 normal : NORMAL;
				    float4 tangent : TANGENT; //获取切线,4个分量是因为需要w分量来确定切线空间第三个坐标轴副切线的方向性。
				    float4 texcoord : TEXCOORD0; //存储纹理坐标
			   }
			   struct v2f
			   {
			           float4 pos : SV_POSITION; //描述输出的顶点位置
			           float2 uv : TEXCOORD0; //纹理坐标变量uv
			           float3 lightDir : TEXCOORD1; //传递顶点着色器中计算出的光源方向
			           float3 viewDir : TEXCOORD2;  //传递顶点着色器中计算出的视角方向
			   }
			   v2f vert(a2v v)
			   {
				    v2f o;
				    o.pos=mul(UNTIY_MATRIX_MVP,v.vertex); //转换到裁剪空间中
				    o.uv.xy = v.texcoord.xy*_MainTex_ST.xy+_MainTex_ST.zw;  //纹理的缩放平移计算
				    TANGENT_SPACE_ROTATION; //计算模型空间转换到切线空间的变换矩阵rotation(3×3),具体实现代码在150页。
				    o.lightDir=mul(rotation,ObjSpaceLightDir(v.vertex)).xyz; //将光照方向转到切线空间内
				    o.viewDir=mul(rotation,ObjSpaceViewDir(v.vertex)).xyz; //将观察方向转到切线空间内
				    return o;
			   }
			   fixed4 frag(v2f i) : SV_Target
			   {
				    fixed3 tangentLightDir = normalize(i.lightDir);//将切向空间内的矢量单位矢量化,下同
				    fixed3 tangentViewDir = normalize(i.viewDir);
				    fixed4 packedNormal = tex2D(_BumpMap,i.uv); //先对法线纹理进行采样
				    fixed3 tangentNormal; //创建变量从像素反映射回法线方向。
				    tangentNormal=UnpackNormal(packedNormal); //反映射
				    tangentNormal.xy* = _BumpScale; //乘以凹凸程度
				    tangentNormal.z = sqrt(1.0-saturate(dot(tangentNormal.xy,tangentNormal.xy)));
				    //运用直角三角形三边关系使用xy求得z
				    fixed3 albedo = tex2D(_MainTex,i.uv).rgb*_Color.rgb; //对纹理采样,乘颜色得到材质的反射率
				    fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz*albedo; //环境光部分
				    fixed3 diffuse = _LightColor0.rbg*albedo*max(0,dot(tangentNormal,tangentLightDir)); //漫反射
				    fixed3 halfDir = normalize(tangentLightDir+tangentViewDir); //计算BP模型中的h
		 		    fixed specularMask = tex2D(_SpecularMask,i.uv).r*_SpecularScale;   
		 		    //对遮罩纹理采样后,rgb各个分量都一样,都是该点的高光反射强度,所以任选R分量进行计算掩码值。
		 		    //乘以系数_SpecularScale后,控制高光反射强度。
				    fixed3 specular=_LightColor0.rgb*_Specular.rgb*pow(max(0,dot(tangentNormal,halfDir)),Gloss)*specularMask; 
				    //计算附带遮罩的高光反射
				    return fixed4 (ambient+diffuse+specular,1.0); //相加
			    }   
		  }
	 }
	Fallback "Specular”
}

以上 这张遮罩纹理浪费了一些空间,因为rgb分量存储的是同一个值,
在实际的游戏制作中,我们会充分使用遮罩纹理的每一个颜色来存储表面属性。
比如r控制高光反射,g控制边缘光照强度,高光反射指数部分存储在b,自发光存储在a。

《Dota2》开发中,每个模型就是使用4张纹理:
一张控制定义颜色,一张控制定义表面法线,另外两张都是遮罩纹理。
这样两张遮罩纹理就会提供8种额外的表面属性,这使得人物材质自由度很强,可以支持很多的高级模型属性。

总结下前面不懂的:

tex2D采样怎么采,i.uv纹理坐标到底是什么,怎么用在这个函数的,可以查查tex2D函数。
Wrap Mode,Repeat和Clamp,为什么repeat纹理坐标超过1,舍弃整数部分然后会出现重复样子。然后为什么这样渐变纹理会有黑点。
遮罩纹理中,为什么_MainTex_ST会定义三个纹理的共同的偏移平铺系数,是如果不定义另外两个就会默认使用这个么。
就想起这些。。记下

这节看完突然就理解了,有时候为什么会看见那么乱七八糟,五颜六色,花了呼哨的没有意义的图片,原来都是控制信息,吊,谁研究的呢你说。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值