【《Unity Shader入门精要》 提炼总结】(十一)第十一章·渐变纹理的应用&遮罩纹理的应用

 

 

 

本文由@唐三十胖子出品,转载请注明出处。  
文章链接:https://blog.csdn.net/iceSony/article/details/84634170

 

 

 

这篇文章将总结和提炼《Unity Shader入门精要》的第七章“基础纹理”的内容。

通过这篇文章,你可以知道

1)渐变纹理的应用

2)遮罩纹理的应用

一.渐变纹理的应用

纹理的最初使用,是为了给一个模型表面上色。实际上,纹理可以用来存储表面属性,如之前的法线纹理将法线信息存储在一张纹理中。通过纹理也可以控制漫反射光照结果。而渐变纹理,实现的是在材质纹理上再对光照信息进行处理。

分别使用

具体代码如下

Shader "sony/Shader174"
{
	Properties
	{
		_Diffuse("漫反射系数",Color) = (1.0,1.0,1.0,1.0)
		_MainTex("主纹理",2D) = "white"{}
	}
		SubShader
	{
		Pass
	{
		Tags{ "LightMode" = "ForwardBase" }
		CGPROGRAM
#include "lighting.cginc"
#pragma vertex vert
#pragma fragment frag
		float4 _Diffuse;
	sampler2D _MainTex;
	float4 _MainTex_ST;
	struct a2v
	{
		float4 pos : POSITION;
		float3 normal : NORMAL;
		float4 texcoord:TEXCOORD0;
	};
	struct v2f
	{
		float4 pos : SV_POSITION;
		float3 worldNormal : TEXCOORD0;
	};
	v2f vert(a2v v)
	{
		v2f o;
		o.pos = UnityObjectToClipPos(v.pos);
		o.worldNormal = UnityObjectToWorldNormal(v.normal);
		return o;
	}
	fixed4 frag(v2f i) : SV_Target
	{
		float3 worldNormal = i.worldNormal;
		float3 worldLightDir = UnityWorldSpaceLightDir(worldNormal);

		float3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;

		fixed halfLambert = 0.5*dot(worldNormal, worldLightDir) + 0.5;
		float3 diffuse = _LightColor0.rgb * _Diffuse.rgb * tex2D(_MainTex,float2(halfLambert, halfLambert));

		return fixed4(ambient + diffuse,1.0);
	}
		ENDCG
	}
	}
}

代码很短看看就好,其中让人不解的是tex2D内容的uv坐标

为什么是halfLambert呢?

原因是纹理本身就是一个一维纹理,因此纹理的uv我们都可以通过半兰伯特来代替

  • 这里进行纹理采样的uv坐标为半兰伯特值,将法线与光照方向的点积映射到[0,1]也就是说原本光照不到的地方会取到渐变纹理中靠左下部分的颜色。
  • 由于采样时uv坐标都是相等的,因此取到的颜色应该是对应纹理坐标[0,1]内的对角线上的颜色。
  • 还有一点值得注意的是,当采用突变性的渐变纹理时(如第一张渐变纹理),漫反射的结果是阴影之间更加分明,类似于卡通效果。

二.遮罩纹理的应用

遮罩纹理应用于很多商业游戏中,用来保护某些区域,免于某些修改。两个常见的应用:

  • 使模型某些区域的高光强烈,某些区域较弱。而不是将高光反射应用到模型的所有地方,使用遮罩纹理可以更加细腻的控制高光的光照效果。
  • 制作地形材质时需要混合多张图片,例如表现草地,石子,裸露土地的纹理。使用遮罩纹理可以控制如何混合这些纹理。

使用者遮罩纹理的流程:通过采样得到遮罩纹理的纹素值,然后使用其中某个通道的值与某种表面属性进行相乘,当该通道值为0时,可以保护表面不受属性影响。

其实就用了一步

fixed mask = tex2D(_MaskTex, i.uv).r * _MaskScale;

在最后的高光反射的时候进行混合即可

fixed3 specular = _LightColor0.rgb * _Specular * pow(max(0, dot(tangentNormal, halfDir)), _Gloss) * mask;

实现代码

Shader "sony/Shader178"
{
	Properties
	{
		_MainTex("Texture", 2D) = "white" {}
	_BumpTex("BumpTex", 2D) = "white" {}
	_MaskTex("MaskTex", 2D) = "white" {}
	_BumpScale("BumpScale", Float) = 1.0
		_MaskScale("MaskScale", Float) = 1.0
		_Color("Color Tint", Color) = (1, 1, 1, 1)
		_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"

		sampler2D _MainTex;
	float4 _MainTex_ST;
	sampler2D _BumpTex;
	float4 _BumpTex_ST;
	sampler2D _MaskTex;
	float4 _MaskTex_ST;
	float _BumpScale;
	float _MaskScale;
	fixed4 _Color;
	fixed4 _Specular;
	float _Gloss;

	struct appdata
	{
		float4 vertex : POSITION;
		float2 uv : TEXCOORD0;
		float3 normal : NORMAL;
		float4 tangent : TANGENT;
	};

	struct v2f
	{
		float2 uv : TEXCOORD0;
		float4 vertex : SV_POSITION;
		float3 lightDir : TEXCOORD1;
		float3 viewDir : TEXCOORD2;
	};

	v2f vert(appdata v)
	{
		v2f o;
		o.vertex = UnityObjectToClipPos(v.vertex);
		o.uv = TRANSFORM_TEX(v.uv, _MainTex);

		TANGENT_SPACE_ROTATION;
		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 lightDir = normalize(i.lightDir);
	fixed3 viewDir = normalize(i.viewDir);

	fixed4 bumpColor = tex2D(_BumpTex, i.uv);
	fixed3 tangentNormal = UnpackNormal(bumpColor);
	tangentNormal.xy *= _BumpScale;
	tangentNormal.z = sqrt(1 - saturate(dot(tangentNormal.xy, tangentNormal.xy)));

	fixed3 albedo = tex2D(_MainTex, i.uv).rgb * _Color.rgb;

	fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;
	fixed3 diffuse = _LightColor0.rgb * albedo * max(0, dot(tangentNormal, lightDir));

	fixed mask = tex2D(_MaskTex, i.uv).r * _MaskScale;
	fixed3 halfDir = normalize(viewDir + lightDir);
	fixed3 specular = _LightColor0.rgb * _Specular * pow(max(0, dot(tangentNormal, halfDir)), _Gloss) * mask;

	return fixed4(ambient + diffuse + specular, 1.0);
	}
		ENDCG
	}
	}

		FallBack "Specular"
}

这里有两点需要注意的地方:

  • 主纹理,法线纹理和遮罩纹理的纹理坐标都来自主纹理的uv坐标,也就是说当修改材质面板的主纹理的缩放和偏移值时,法线纹理和遮罩纹理都会相应变化,而修改法线纹理和遮罩纹理的缩放偏移值是不会对计算结果产生任何影响的,事实上测试的结果也是这样。
  • 遮罩纹理的计算过程中只用到了纹理的r通道,其他3个通道其实可以用来存储更多的设置值。

 

通过遮罩处理后,高光的效果不是全部反映到整个区域,而是由r通道进行选择,遮罩纹理中全黑色的地方,即r=0处是不会受到高光影响的,这也是为什么高光部分的裂缝处的凹槽更加清晰。

 

下一章我们将介绍Shader开发中神奇的实现:透明效果

下一章见:)

Unity Shader是一种用于渲染图形的程序,它可以控制对象的表面颜色、纹理、透明度、反射等属性,从而实现特殊的视觉效果。对于游戏开发者来说,掌握Shader编写技巧是非常重要的。 以下是关于Unity Shader入门精要: 1. ShaderLab语言 ShaderLab是Unity中用于编写Shader的语言,它是一种基于标记的语言,类似于HTML。ShaderLab可以用于定义Shader的属性、子着色器、渲染状态等信息。 2. CG语言 CG语言是Unity中用于编写Shader的主要语言,它是一种类似于C语言的语言,可以进行数学运算、向量计算、流程控制等操作。CG语言可以在ShaderLab中嵌入,用于实现Shader的具体逻辑。 3. Unity的渲染管线 Unity的渲染管线包括顶点着色器、片元着色器、几何着色器等组件,每个组件都有不同的作用。顶点着色器用于对对象的顶点进行变换,片元着色器用于计算每个像素的颜色,几何着色器用于处理几何图形的变形和细节等。 4. 模板和纹理Shader中,我们可以使用纹理来给对象添加图案或者贴图,也可以使用模板来控制对象的透明度、反射等属性。纹理可以通过内置函数tex2D()来获取,模板可以通过内置函数clip()来实现裁剪。 5. Shader的实现 Shader的实现需要注意以下几点: - 在ShaderLab中定义Shader的属性、子着色器、渲染状态等信息。 - 在CG语言中实现Shader的具体逻辑,包括顶点着色器、片元着色器等内容。 - 使用纹理和模板来实现特定的视觉效果。 - 在对象上应用Shader,通过调整Shader的属性来达到不同的效果。 以上是关于Unity Shader入门精要,希望对你有所帮助。如果你想更深入地了解Shader的编写技巧,可以参考官方文档或者相关教程。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值