【Unity】Shader代码的小结构
有机紫菜
编辑于 2025年04月03日 21:29

Shader代码的大结构​---紧接之前的部分.

小结构指的是Shader中从CGPROGRAM--ENDCG---之间代码的常用结构和常用命令的写法.

在Unity的Shader代码中,块内部使用的是HLSL(High-Level Shading Language)或GLSL(OpenGL Shading Language),这是一种用于编写着色器程序的语言。在这个块内部,指令是预处理器指令,用于指导编译器如何处理代码。以下是块内的一些常用结构和它们的含义:

  1. #pragma vertex vert:

    • #pragma 是预处理器指令,用于向编译器提供额外的信息。

    • vertex 是固定的关键字,表示后面跟随的是顶点着色器的函数名。

    • vert 是自定义的函数名,它是顶点着色器的入口点。你可以将其命名为任何有效的C语言标识符,但通常使用简洁且具有描述性的名称。

  1. #pragma fragment frag:

    • 同样,#pragma 是预处理器指令。

    • fragment 是固定的关键字,表示后面跟随的是片元着色器的函数名。

    • frag 是自定义的函数名,它是片元着色器的入口点。

代码块
C#
自动换行
复制代码
CGPROGRAM
#pragma vertex vert
#pragma fragment frag

// 顶点着色器
float4 vert (appdata v) : SV_POSITION
{
    // 顶点着色器代码
}

// 片元着色器
fixed4 frag (v2f i) : SV_Target
{
    // 片元着色器代码
}
ENDCG
复制成功

fixed4 frag (v2f i) : SV_Target

  1. fixed4: 是HLSL中的一个数据类型,表示一个四维向量,其元素是固定精度浮点数(16位)。通常用于颜色和纹理坐标等不需要高精度的值。fixed4 包含四个分量:x, y, z, 和 w。

  2. frag:是自定义的函数名,代表片元着色器的入口点。你可以将frag替换为任何有效的C语言标识符。这个名称是约定俗成的,用于表示这是片元着色器。

  3. v2f: 是一个结构体类型,通常在Shader中用于从顶点着色器传递数据到片元着色器。v2f是自定义的,表示“vertex to fragment”的缩写,但你可以根据需要给它起任何名字。

  4. i: 是函数参数的名称,代表传递给片元着色器的v2f结构体实例。你可以将i替换为任何有效的变量名。

  5. SV_Target: 是一个系统值语义,用于指示这个函数返回的值将被写入渲染目标(通常是颜色缓冲区)。SV代表“system value”,是HLSL中用于特定用途的预定义语义

float4 vert (appdata v) : SV_POSITION

  1. float4: 是HLSL中的一个数据类型,表示一个四维向量,其元素是单精度浮点数(32位)。通常用于顶点位置、变换矩阵等需要高精度的值。float4 也包含四个分量:x, y, z, 和 w。

  2. vert: 是自定义的函数名,代表顶点着色器的入口点。和frag一样,你可以将vert替换为任何有效的C语言标识符。这个名称同样是约定俗成的,用于表示这是顶点着色器。

  3. appdata: 是一个结构体类型,通常用于定义顶点着色器的输入数据。它包含了顶点位置、纹理坐标、法线等信息。appdata是自定义的,可以根据需要更改其名称。

  4. v: 是函数参数的名称,代表传递给顶点着色器的appdata结构体实例。你可以将v替换为任何有效的变量名。

  5. SV_POSITION: 是一个系统值语义,用于指示这个函数返回的值是裁剪空间中的顶点位置。SV代表“system value”,POSITION是HLSL中预定义的语义之一,用于特定的用途。

总结来说,这些关键字和数据类型定义了着色器函数的输入、输出以及它们在渲染管线中的角色。在编写Shader时,你需要遵循这些约定来确保着色器能够正确地与Unity的渲染管线集成。

其他的预处理器指令

在HLSL(High-Level Shading Language)中,预处理器指令用于在编译阶段控制代码的编译过程。以下是一些常用的预处理器指令:

  1. #define:

    • 用于定义一个宏,可以在代码中使用这个宏来代替一个值或表达式。#define MY_VALUE 1.0

  1. #undef:

    • 用于取消之前定义的宏。

    • #undef MY_VALUE

  1. #if:

    • 根据条件编译代码块。如果条件为真,则编译该代码块。

    • #if defined(MY_VALUE) // 编译这里的代码 #endif

  1. #ifdef:

    • 如果指定的宏已定义,则编译代码块。

    • #ifdef MY_VALUE // 编译这里的代码 #endif

  1. #ifndef:

    • 如果指定的宏未定义,则编译代码块。

    • #ifndef MY_VALUE // 编译这里的代码 #endif

  1. #else:

  1. #elif:

    • 类似于#else,但是可以提供一个新的条件测试。

    • #if defined(MY_VALUE) // 编译这里的代码

    • #elif defined(ANOTHER_VALUE)// 如果ANOTHER_VALUE定义了,则编译这里的代码

    • #endif

  1. #endif:

    • 结束#if#ifdef#ifndef#elif#else代码块。

    • #if def MY_VALUE

    • // 编译这里的代码

    • #endif

  1. #pragma:

    • 用于向编译器提供额外的信息,比如指定着色器函数名。

    • #pragma vertex vert

    • #pragma fragment frag

  1. #error:#error "This is a custom error message"

    • 用于生成一个编译错误消息。

  1. #line:#line 100 "newfilename.hlsl"

    • 用于改变预处理器报告的行号和文件名。

  1. #region#endregion:#region MyShaderCode // 代码块 #endregion这些指令在编写Shader时非常有用,可以帮助你根据不同的条件编译不同的代码路径,定义宏,以及控制编译过程的其他方面。

    • 用于在代码编辑器中折叠代码块,不是编译指令,但有助于组织代码。

  1. #include:#include "MyCommonCode.hlsl"

    • 用于将另一个文件的内容包含到当前文件中,通常用于包含头文件或常用的代码段。

Pass内指令概览

用于设置渲染状态的命令

在 Pass 代码块中使用这些命令可为该 Pass 设置渲染状态,或者在 SubShader 代码块中使用这些命令可为该 SubShader 以及其中的所有 Pass 设置渲染状态。

  • AlphaToMask:设置 alpha-to-coverage 模式。

  • Blend:启用和配置 alpha 混合。

  • BlendOp:设置 Blend 命令使用的操作。

  • ColorMask:设置颜色通道写入掩码。

  • Conservative:启用和禁用保守光栅化。

  • Cull:设置多边形剔除模式。

  • Offset:设置多边形深度偏移。

  • Stencil:配置模板测试,以及向模板缓冲区写入的内容。

  • ZClip:设置深度剪辑模式。

  • ZTest:设置深度测试模式。

  • ZWrite:设置深度缓冲区写入模式。

Pass名称命名规则

在Unity的Shader代码中, 指令用于为Pass块指定一个名称。这个名称在Unity编辑器中显示,并且对于理解Shader的各个部分很有帮助。然而, 指令的名称并不是固定的,你可以根据你的Shader的需要和理解来命名Pass块。

命名Pass块有以下几个好处:

  1. 代码可读性:

    • 清晰的命名有助于其他开发者或你自己理解Shader的各个部分。

  1. Unity编辑器:

    • 在Unity编辑器中,每个Pass都会在材质窗口中显示其名称,这有助于快速识别和选择特定的Pass。

  1. 调试和优化:

    • 如果你在调试Shader时遇到了问题,清晰的命名可以帮助你快速定位到问题所在的Pass。

  1. 自动化:

    • 一些Shader编写工具和框架可能依赖于Pass的名称来执行特定的操作,如生成渲染路径或优化。###

Pass内的指令.

在Unity的Shader代码中,Pass块内部可以包含多种指令,用于设置渲染状态、控制渲染过程和优化性能。以下是一些常用的Pass块指令及其说明:

  1. Stencil:

    • 用于设置与模板测试(Stencil Test)相关的状态,如模板测试函数、操作、对比等。Stencil { CompareEqual 0, 0, 0 WriteZero FailKeep ZFailKeep ZPassKeep }

  1. ZTest:

    • 用于设置深度测试(Depth Test)的函数,如小于、等于、不等于等。ZTest Greater

  1. ZWrite:

    • 用于设置是否写入深度缓冲区(Depth Buffer)。ZWrite On

  1. Cull:

    • 用于设置是否进行背面剪裁(Backface Culling)。Cull Back

  1. Blend:

    • 用于设置混合(Blending)模式,如Alpha Blending、Additive等。Blend SrcAlpha OneMinusSrcAlpha

  1. Name:

    • 用于为Pass块指定一个名称,这个名称在Unity编辑器中显示。Name "MyPass"

  1. Tag:

    • 用于为Pass块指定标签,如RenderType、Queue等,这些标签用于Unity渲染器的设置。Tags { "RenderType"="Opaque" "Queue"="Geometry" }

  1. LOD:

    • 用于设置细节级别(Level of Detail),影响渲染的复杂度。LOD 200

  1. Fog:

    • 用于设置雾效(Fog)相关的状态,如雾效类型、颜色等。Fog { Mode Linear }

  1. Lighting:Lighting On

    • 用于启用或禁用光照(Lighting)计算。

  1. AlphaTest:AlphaTest Greater 0.5

    • 用于设置是否进行Alpha测试,以及测试的函数和值。

  1. AlphaToMask:AlphaToMask Off

    • 用于设置是否将Alpha值用作Mask。

  1. ColorMaterial:ColorMaterial Diffuse

    • 用于设置材质的颜色如何与光照混合。

  1. CullMode:CullMode Back

    • 用于设置背面剪裁(Culling)的模式,如Back、Front、Off等。

  1. ZTestMode:ZTestMode Greater

    • 用于设置深度测试(Z Test)的模式,如Less、Greater、Equal等。

  1. ZWriteMode:ZWriteMode Always

    • 用于设置是否写入深度缓冲区(Z Write),以及写入的模式。

  1. BlendSrc:BlendSrc SrcAlpha

    • 用于设置混合(Blending)的源因子。

  1. BlendDst:BlendDst OneMinusSrcAlpha这些指令可以在Pass块内部使用,以控制渲染过程中的各个方面。根据你的Shader需求,你可以选择使用其中的一些或全部指令来定制渲染行为。

    • 用于设置混合(Blending)的目标因子。

  1. ZClip:

    • 在Unity的Shader代码中,ZClip 指令用于设置深度剪裁(Depth Clipping)的状态。深度剪裁是一种技术,用于隐藏超出屏幕视锥的物体。在Unity的ShaderLab中,ZClip 指令允许你控制是否剪裁超出视锥的深度值。