Unity Shader片段着色器使用基础详解
Unity中的Shader(着色器)用于控制游戏对象的渲染方式,让它们变得更加美观、细致。Shader分为顶点着色器和片段着色器,这篇攻略主要介绍Unity中片段着色器的使用基础,可以帮助开发者更加细致地控制对象的渲染方式。
Shader基础知识
在进入片段着色器的详细使用说明前,我们先来了解一些Shader的基础知识:
-
Shader程序:Shader程序是一个小型程序,它可以用来控制材质表面的渲染效果。在Unity中,Shader是由着色器语言编写的,可以用许多内置的和自定义的函数来描述。
-
ShaderLab语言:这是Unity的一种语言,它用于描述材质、纹理、渲染队列、某个材质的Shader和其它属性。它是一种易于阅读和编写的语言,并且易于维护。
-
Uniform变量:这种变量是可编程的,它的值可以被修改,而且在绘制物体时,它是不一样的,又称之为上传的变量。比如说,全局变量或者纹理。
有了以上的基础知识,我们就可以更好地理解Unity中片段着色器的使用方法。
片段着色器
片段着色器是一种Shader编程技巧,它用于描述一个像素的颜色和属性。它们的作用体现在单个像素上,包括光照模型、着色、透明度、阴影、反射和折射等效果。
片段着色器样例1
下面是一个Unity中片段着色器的基础代码:
Shader "Custom/MyFragmentShader" {
Properties {
_MainTex ("Texture", 2D) = "white" {}
_Color ("Color", Color) = (1,1,1,1)
}
SubShader {
Tags {"Queue"="Transparent" "RenderType"="Opaque"}
LOD 100
Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
struct appdata {
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f {
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
sampler2D _MainTex;
float4 _MainTex_ST;
fixed4 _Color;
v2f vert (appdata v) {
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
return o;
}
fixed4 frag (v2f i) : SV_Target {
fixed4 col = tex2D(_MainTex, i.uv) * _Color;
col.a = _Color.a * col.a;
return col;
}
ENDCG
}
}
在这个例子中,我们定义了一个名为“ Custom/MyFragmentShader”的着色器。在Properties区块中,我们定义了_MainTex(主纹理)和_Color(颜色)两个Uniform属性,同时它们的默认值分别为白色和纯白色。
在SubShader区块中,我们通过Tags指令定义了它们的渲染顺序和类型,并且设置了LOD(LOD表示level of details)
在内部的Pass语句中,我们定义了一个传递着色器的CGPROGRAM块,在这里我们定义了一个输入参数appdata和一个输出参数v2f。
vert
函数定义了输入参数v并输出了v的顶点着色阶段的处理结果,同时重映射了_MainTex的uv坐标到图像的正确位置。固定函数TEXCOORD0
包含了uv坐标, float4
类型包含64位浮点数,表示精度很高的浮点坐标。
frag`函数定义了输入参数i并输出了颜色。在这个函数中,我们首先获取_MainTex的颜色,然后将它与颜色变量_Color进行乘法运算,最后将颜色的Alpha通道值设置为变量_Color的Alpha值,最终返回这个颜色值。
这么一看,Unity中的片段着色器相比OpenGL,其着色代码相对比较简单易用。
片段着色器样例2
现在,我们来看一个更复杂一点的例子。这个例子中,我们要使用屏幕空间反射技术让我们的地面反射画面中的物体。
Shader "Custom/ShaderExample" {
Properties {
[HDR] _ReflColor ("Reflection Color", Color) = (1, 1, 1, 1)
_DiffuseColor ("Diffuse Color", Color) = (1, 1, 1, 1)
_MainTex ("Base (RGB)", 2D) = "white" {}
}
SubShader {
Tags { "RenderType"="Opaque" }
CGPROGRAM
#pragma surface surf Standard
struct Input {
float2 uv_MainTex;
};
half4 _ReflColor;
half4 _DiffuseColor;
sampler2D _MainTex;
float4 _MainTex_ST;
void surf (Input IN, inout SurfaceOutputStandard o)
{
o.Albedo = tex2D(_MainTex, IN.uv_MainTex).rgb * _DiffuseColor.rgb;
o.Metallic = 0.5;
o.Smoothness = 0.5;
o.Normal = float3(0,0,1);
o.Emission = _ReflColor.rgb * tex2D(_MainTex, reflect(IN.uv_MainTex, o.Normal)).rgb;
o.Alpha = 1;
}
ENDCG
}
FallBack "Diffuse"
在这个例子中,我们定义了一个名为“ Custom/ShaderExample”的着色器。在Properties区块中,我们定义了三个Uniform属性:_ReflColor
和_DiffuseColor
的颜色属性以及_MainTex
的主纹理属性。
在SubShader区块中,我们通过Tags指令定义这个着色器的渲染类型为不透明的。在此后的CGPROGRAM块中,我们使用了 #pragma surface surf Standard 指令来使用Standard Shader Surface Functions。
这里的函数 surf(Input IN, inout SurfaceOutputStandard o)用于将输入的Mesh顶点所对应的表面输出为SurfaceOutputStandard的实例化对象,后续的混合、渲染、反射和折射拆分都是在o的实例上操作。
在这个例子中,我们使用了反射矩阵传入INPUT并用其获取屏幕空间反射的纹理坐标来改变当前表面的反射色。我们通过纹理采样方式tex2D把纹理坐标的颜色值结合DiffusColor和Diffuse纹理纹理颜色进行混合。
Shader的局限性
使用Unity内置的Shader是可以在游戏中实现很多复杂效果的。但是,由于Shader编程需要对OpenGL或Metal等底层渲染API有一定的了解,所以它对于新手来说可能有些陌生。同时,由于Shader的执行是在GPU上完成的,所以在某些情况下,Shader的执行会占用大量的系统资源,从而降低游戏的帧率。
另外,对于非高端设备的手机来说,也可能会出现一些兼容性问题,特别是一些老旧的手机。因此,在制作游戏时,我们需要对不同的设备进行适当的优化。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Unity Shader片段着色器使用基础详解 - Python技术站