Shader语法基础
Shader结构
Shader 后跟随的是该Shader的名称
Shader "Custom/DiffuseShader"{
}
Properties 块
定义了可以在 Unity 编辑器中调整的变量,如颜色、纹理、浮点数等
这些变量可以在材质面板中被修改,从而影响最终的渲染效果
[KeywordEnum(X, Y, Z)] _Faces ("Faces", Float) = 0
定义一个下拉列表,其中包含多个选项。
X
、Y
和Z
是下拉列表中的选项名称当用户在材质编辑器中选择一个选项时,相应的关键字会被定义,可以在着色器代码中使用这些关键字来控制不同的代码路径
可以在 Unity 的材质编辑器中,你会看到一个名为 "Faces" 的下拉列表,其中包含三个选项:
X
、Y
和Z
。用户可以选择其中一个选项,选择的选项会定义相应的关键字(_FACES_X
、_FACES_Y
或_FACES_Z
),从而影响着色器代码的编译和运行。
Properties
{
_Color ("Main Color", Color) = (1,1,1,1)
_MainTex ("Base (RGB)", 2D) = "white" {}
[KeywordEnum(X, Y, Z)] _Faces ("Faces", Float) = 0
}
SubShader 块
每个 Shader 至少需要一个 SubShader
SubShader 中包含了实际执行的着色器代码,包括顶点着色器(Vertex Shader)、片段着色器(Fragment Shader)、表面着色器(Surface Shader)等
如果一个 Shader 在某些硬件上无法运行,Unity 会尝试使用下一个 SubShader
Tags标签
Tags
标签用于指定 Shader 的一些重要属性,这些属性可以帮助 Unity 更好地管理和优化渲染流程。Tags
标签通常放在 SubShader
块中,用于提供关于如何处理该 SubShader 的附加信息
RenderType:指定渲染类型,会影响渲顺序和混合模式
"Opaque": 当 RenderType 设置为 "Opaque" 时,Unity 会将使用该 Shader 的对象放入不透明渲染队列。不透明对象的渲染顺序通常是按对象的深度进行排序,从近到远(即从摄像机最近的对象开始渲染)
"Transparent":当 RenderType 设置为 "Transparent" 时,Unity 会将使用该 Shader 的对象放入透明渲染队列
Tags { "RenderType"="Opaque" }
LOD
LOD(Level of Detail,细节等级)用于控制 Shader 的复杂度和渲染性能。LOD 值可以用来决定在不同情况下使用哪些 SubShader 或 Pass。通过设置 LOD,你可以在性能和视觉效果之间找到一个平衡点。
控制 Shader 的复杂度:LOD 值用于指定 Shader 的复杂度。较低的 LOD 值表示较低的复杂度,较高的 LOD 值表示较高的复杂度。
优化性能
当LOD设置为200时,表示中等复杂度的 Shader,一般是漫反射。
LOD 200
CGPROGRAM和ENDCG
用于包围用 HLSL(High-Level Shading Language)编写的着色器代码块。这两个关键字告诉 Unity 编译器,这部分代码是用 HLSL 编写的,需要特殊处理。
#pragma 编译指令
它用于控制编译器的行为,它可以用于多种目的,包括指定着色器类型、优化编译选项、启用或禁用特定功能等
#pragma shader_feature:用于在编译时有条件地包含或排除代码块,你可以在 Unity 编辑器中通过材质属性或脚本来启用或禁用这些关键字
#pragma shader_feature _FACES_X _FACES_Y _FACES_Z
#if defined(_FACES_X)
// 处理 X 面的逻辑
o.cubeUV = v.color.yz * 255;
#elif defined(_FACES_Y)
// 处理 Y 面的逻辑
o.cubeUV = v.color.xz * 255;
#elif defined(_FACES_Z)
// 处理 Z 面的逻辑
o.cubeUV = v.color.xy * 255;
#pragma surface:定义一个表面着色器
语法:#pragma surface surf [lightModel] [additionalOptions] [vertex:vertexFunction]
surf:表面着色器的主函数名
lightModel:光照模型,例如
Standard
、Lambert
、BlinnPhong
等additionalOptions:额外的选项,例如
fullforwardshadows
、addshadow
等
fullforwardshadows
启用前向渲染中的完整阴影,适用于需要高质量阴影的场景vertex:vertexFunction:可选的顶点着色器函数名
#pragma surface surf Standard fullforwardshadows vertex:vert
// 顶点作色器函数名
void vert ()
{
}
// 表面着色器函数名
void surf ()
{
}
#pragma target:指定目标 HLSL 版本或特定的 GPU 特性
语法:#pragma target [version]
version:版本
3.0
:支持更多的高级特性,如几何着色器和双线性插值。
CG语法
变量类型
定义一个变量并使用,需要
1. 在 Shader 的 Properties
块中定义纹理属性
2. 在CG代码块中声明 sampler2D
变量。
sampler2D:二维纹理的采样器类型,它允许你在着色器中读取和采样纹理数据,使用tex2D进行采集纹理
顶点着色器函数
顶点着色器函数 vert
的参数用于传递和处理顶点数据
void vert (inout appdata_full v, out Input o)
参数说明
inout appdata_full v
inout
关键字表示这个参数既可以作为输入,也可以作为输出。也就是说,你可以在函数内部修改这个参数的值,这些修改会反映到调用者appdata_full 是一个结构体,包含了顶点的所有属性,如位置、法线、切线、颜色、纹理坐标等
float4 vertex : POSITION
:顶点的位置
float3 normal : NORMAL
:顶点的法线
float4 tangent : TANGENT
:顶点的切线
float4 color : COLOR
:顶点的颜色
v.color.yz * 255 某个顶点的颜色的分离乘以255,这么做的目的是将顶点颜色的分量从【0,0】变为【0,255】将颜色值转换为更适合用作 UV 坐标的值
out Input o
out
关键字表示这个参数只能作为输出
Input
是一个用户定义的结构体,用于存储从顶点着色器传递到片段着色器的数据
表面着色器函数
void surf (Input IN, inout SurfaceOutputStandard o) {
// 采集_MainTex对于uv的颜色,并进行混色
fixed4 c = tex2D (_MainTex, IN.cubeUV) * _Color;
// 采集的颜色应用到表面漫反射上
o.Albedo = c.rgb;
// 设置金属感,0为非金属,1为金属
o.Metallic = _Metallic;
// 设置光滑感,0为粗糙,1为光滑
o.Smoothness = _Glossiness;
// 设置透明度,0完全透明~1完全不透明
o.Alpha = c.a;
}
Input IN
IN
是一个输入结构体,包含从顶点着色器传递过来的数据
inout SurfaceOutputStandard o
SurfaceOutputStandard
是 Unity 内置的结构体,包含多个表面属性
常用的宏
UNITY_INITIALIZE_OUTPUT(Input, o):这是一个宏,用于初始化 Input
结构体。确保所有字段都被正确初始化,避免未定义行为。让Input结构体里面的变量都初始化,并给o
评论区