一、着色器核心概念
1.着色器简介
着色器程序,通常称为着色器,是在 GPU 上运行的程序。
在 Unity 中,着色器分为三大类。每个类别的用途不同,使用方式也不同。 1. 作为图形管线一部分的着色器是最常见的着色器类型。它们执行一些计算来确定屏幕上像素的颜色。在 Unity 中,通常是通过 Shader 对象使用这种类型的着色器。 2. 计算着色器在常规图形管线之外,在 GPU 上执行计算。 3. 光线追踪着色器执行与光线追踪相关的计算。
术语 着色器的相关术语可能令人困惑;人们通常使用“着色器”表示不同的内容。
在本文档中,该术语的用法如下:
- 着色器或者着色器程序 - 在 GPU 上运行的程序。除非另有说明,否则这意味着着色器程序是图形管线的一部分。
- Shader 对象 - Shader 类的一个实例。Shader 对象是着色器程序和其他信息的封装器。
- ShaderLab - 一种用于编写着色器的 Unity 特定语言。
- Shader Graph - 一种无需编写代码即可创建着色器的工具。
- 着色器资源 - Unity 项目中扩展名为 .shader 的文件。它定义一个 Shader 对象。
- Shader Graph 资源 - Unity 项目中的文件。它定义一个 Shader 对象。
2.Shader 类
在 Unity 中,当您使用的着色器属于图形管线 的一部分,通常用到 Shader 类的实例。我们将一个 Shader 类的实例称为 Shader 对象。
Shader 对象是 Unity 使用着色器程序的特定方式;它是着色器程序和其他信息的封装器。它允许您在同一个文件中定义多个着色器程序,并告诉 Unity 如何使用它们。
- Shader 对象基础 Shader 对象包含着色器程序、更改 GPU 上设置的指令(统称为渲染状态)以及告诉 Unity 如何使用它们的信息。
将 Shader 对象与材质共同使用来确定场景的外观。
- 资源,
您可以通过两种方式创建 Shader 对象。分别具有各自类型的资源: * 您可以编写代码来创建一个着色器资源,这是一个带有 .shader 扩展名的文本文件。 * 您可以使用 Shader Graph,创建一个 Shader Graph 资源。
无论您以何种方式创建 Shader 对象,Unity 在内部都以相同的方式表示结果
在 Shader 对象内部 Shader 对象具有嵌套结构。它将信息按照名为子着色器和通道的结构进行组织。它将着色器程序组织成着色器变体。
Shader对象 shader对象包含:
- 关于自身的信息,例如其名称fallback 一个可选的fallback Shader 对象,如果 Unity 不能使用这个对象,则会使用fallback 对象
- 一个或多个子着色器。
- 子着色器 子着色器用于将 Shader 对象分成多个部分,分别兼容不同的硬件、渲染管线和运行时设置。
一个子着色器包含:
- 有关此子着色器与哪些硬件、渲染管线和运行时设置兼容的信息
- 子着色器标签,这是提供有关子着色器的信息的键值对
- 一个或多个通道
- pass通道 通道包含:
- 通道标签,这是提供有关通道的信息的键值对
- 在运行着色器程序之前更新渲染状态的说明
- 着色器程序,组织成一个或多个着色器变体
- 着色器变体
通道包含的着色器程序被组织成着色器变体。着色器变体共享通用代码,通过启用或禁用给定Keyword,使其具有不同功能。
通道中的着色器变体的数量取决于您在着色器代码中定义的Keyword数量以及目标平台。每个通道包含至少一个变体。
- 渲染期间的操作顺序
这是 Unity 如何在所有渲染管线中使用 Shader 对象渲染几何体的高级描述。
在 Unity 使用 Shader 对象之前:
1.Unity 为 Shader 对象创建一个子着色器列表。它添加 Shader 对象中定义的所有子着色器,然后按顺序添加任何回退 Shader 对象中的所有子着色器。
当 Unity 首次使用 Shader 对象渲染几何体时,或者当着色器 LOD 值或活动渲染管道更改时: 1.Unity 遍历所有子着色器的列表并检查它们以确定它们是否:与设备硬件兼容;等于或低于当前着色器 LOD 值;并与活动渲染管道兼容。 2.如果列表包含一个或多个满足这些要求的子着色器,它会选择第一个子着色器。这是活动的子着色器。 3.如果列表不包含任何满足所有要求的子着色器: 1.如果列表包含一个或多个满足硬件要求(但不满足 LOD 或渲染管线要求)的子着色器,则 Unity 选择第一个子着色器。这是活动的子着色器。 2. If the list does not contain any SubShaders that meet the hardware requirements, Unity displays the error shader.
Unity 可以识别使用相同着色器变体的几何体并将其组织成批次实现更高效的渲染。每帧一次,对于每批几何体:
1.Unity 确定它应该渲染活动子着色器中的哪些通道,以及帧中的哪个点。此行为因渲染管道而异。 2.对于它渲染的每个通道: 1.如果当前渲染状态与通道中定义的渲染状态不匹配,Unity 会根据通道中的定义设置渲染状态。 2.GPU 使用相关的着色器变体渲染几何体。
3.着色器编译
- 概述 每次构建项目时,Unity 编辑器都会编译构建所需的所有着色器:针对每个所需的图形 API 编译每个所需的着色器变体。
当您在 Unity 编辑器中工作时,编辑器不会提前编译所有内容。这是因为为每个图形 API 编译每个变体可能需要很长时间。
相反,Unity 编辑器会这样做:
- 当导入一个着色器资源时,会执行一些最小的处理(例如表面着色器生成)。
- 当需要显示着色器变体时,它会检查 Library/ShaderCache 文件夹。
- 如果找到使用相同源代码的先前编译的着色器变体,则会使用该着色器变体。
- 如果没有找到匹配项,则编译所需的着色器变体并将结果保存到缓存中。
- 注意:如果您启用异步着色器编译,它在后台执行此操作并同时显示占位着色器。
着色器编译使用名为 UnityShaderCompiler 的进程。可启动多个 UnityShaderCompiler 编译器进程(通常在机器中每个 CPU 核心对应一个),这样在Player构建时就可以并行完成着色器编译。当编辑器不编译着色器时,编译器进程不执行任何操作,也不消耗计算机资源。
如果有许多经常更改的着色器,着色器缓存文件夹可能会变得非常大。删除此文件夹是安全的;只会导致 Unity 重新编译着色器变体。
在Player构建时,所有“尚未编译”的着色器变体都将被编译,因此即使编辑器不会使用这些着色器变体,它们也会存在于游戏数据中
- 不同的着色器编译器 不同平台使用不同的着色器编译器来编译着色器程序,如下所述:
- 使用 DirectX 的平台会使用 Microsoft 的 FXC HLSL 编译器。
- 使用 OpenGL (Core & ES) 的平台会使用 Microsoft 的 FXC HLSL 编译器,然后使用 HLSLcc 将字节代码转换为 GLSL。
- 使用 Metal 的平台会使用 Microsoft 的 FXC HLSL 编译器,然后使用 HLSLcc 将字节代码转换为 Metal。
- 使用 Vulkan 的平台会使用 Microsoft 的 FXC HLSL 编译器,然后使用 HLSLcc 将字节代码转换为 SPIR-V。
- 其他平台(如游戏主机平台)使用其各自的编译器。
- 表面着色器使用 HLSL 和 MojoShader 来完成代码生成分析步骤。 使用
pragma 指令可以配置各种着色器编译器设置。
FXC HLSL、 HLSLcc
- 缓存着色器预处理器
- 构建时剥离
在构建游戏时,Unity可以检测到一些内部着色器变体未被游戏使用,并从构建数据中排除(“剥离”)它们。
4.异步着色器编译
异步着色器编译是一项仅限于编辑器的功能,当您的 Shader 对象比较复杂,包含大量着色器变体时,此功能可以改进您的工作流程。
5.Branching, variants, and keywords
- 着色器中的条件
有时,您希望同一个着色器在不同的情况下做不同的事情。例如,您可能希望为不同的材质配置不同的设置,为不同的硬件定义功能,或者在运行时动态更改着色器的行为。您可能还希望避免在不需要时执行计算量大的代码,例如纹理读取、顶点输入、插值器或循环。
可以使用条件来定义 GPU 仅在特定条件下执行的行为。
- 不同类型的条件句, 要在着色器中使用条件,可以使用一下方法:
- 静态分支,着色器编译器再编译时评估条件代码。
- 动态分支,GPU再运行时平柜条件代码。
- 着色器变体,Unity使用静态分支将着色器源代码变异成多个着色器程序。然后Unity在运行时使用匹配条件的着色器程序。
- 不同类型的条件句, 要在着色器中使用条件,可以使用一下方法:
- 合适使用哪些条件 着色器中的条件没有“一刀切”的方法,在给定项目中,您应该考虑每种方法对于给定着色器的优缺点。
请记住以下信息:
- 如果您知道编译时的条件(例如,如果您知道您正在为给定的硬件构建),那么静态分支可能是最佳选择。静态分支代码易于编写和维护,不会对构建时间、文件大小或运行时性能产生负面影响。但是,您不能使用它在运行时针对不同条件执行代码。
- 如果您需要在运行时针对不同的条件执行代码,您应该考虑以下选项:
- 着色器变体不会导致任何 GPU 性能损失。但是,项目中的大量着色器变体可能会导致严重的问题:增加构建时间、文件大小、运行时内存使用和加载时间。手动预加载(“预热”)着色器时,着色器变体还会引入额外的代码复杂性。
- 动态分支会导致 GPU 性能损失,根据着色器代码和硬件的不同,这种损失可能很小也可能很大。但是,它允许您在运行时使用条件而不增加项目中着色器变体的数量。
- 可以编写着色器代码以避免分支或变体,而是使用返回 0 或 1 的数学运算来执行条件代码。这可能导致难以维护的复杂代码。根据具体情况,与动态分支相比,它可能只会带来非常小的性能改进,或者根本没有优势。
一般来说,最好的方法是分析应用程序的性能并仔细考虑您的决定。例如,如果您能承受稍微增加的 GPU 成本,最好使用动态分支来实现“足够好”的 GPU 性能并降低引入更多变体的风险。但是,如果 GPU 性能是此着色器的主要关注点,并且您已经考虑了额外变体的成本,则可以选择使用变体。
- Shader分支 Shader条件行为,有两种分支:
- 静态分支
- 使用#if、#elif、#else和#endif预处理器指令,或#ifdef和#ifndef预处理器指令来创建静态分支。
- 使用计算编译时常量值的if 语句。尽管if语句也可用于动态分支,但编译器会检测编译时常量值并改为创建静态分支。 Unity为一些可用于静态分支的编译时常量提供内置宏。
- 动态分支
- 在手动编码的着色器中,使用评估运行时状态的if 语句。您可以使用属性来强制 GPU 执行两个分支,或者只执行一个分支。
- 在 Shader Graph 中,使用Branch Node。这总是执行两个分支。
- 着色器变体 着色器变体,有时也称为着色器排列,是将条件行为引入着色器代码的一种方式。 具有大量变体的着色器被称为“大型着色器”或“超级着色器”。Unity 的标准着色器就是此类着色器的一个示例。
变体数量:
例如,考虑一个相当典型的用例,其中一个着色器有一组着色器变体Keyword,每个Keyword包含两个Keyword
(feature name_ON和feature name_OFF)。如果着色器有两组这样的Keyword,则会产生四个变体。如果着色器有十组这样的Keyword,这将产生
1024 个变体。
- 重复变体数据
着色器变体的重复数据删除 编译后,Unity 会自动识别同一个 Pass 中的相同变体,并确保这些相同的变体指向相同的字节码。这称为重复数据删除。
重复数据删除可防止同一 Pass 中的相同变体增加文件大小;但是,相同的变体仍然会导致编译期间的工作浪费,并在运行时增加内存使用和着色器加载时间。考虑到这一点,最好去掉不需要的变体。
着色器keyword
Unity 的预定义着色器Keyword Unity 使用预定义的着色器Keyword集来生成启用通用功能的着色器变体。
Unity 在编译时添加了以下着色器变体Keyword集:
- 默认情况下,Unity 将这组Keyword添加到所有图形着色器程序中:STEREO_INSTANCING_ON、STEREO_MULTIVIEW_ON、STEREO_CUBEMAP_RENDER_ON、UNITY_SINGLE_PASS_STEREO。您可以使用编辑器脚本去除这些Keyword。有关详细信息,请参阅着色器变体剥离。
- 默认情况下,Unity 将这组Keyword添加到标准着色器中:LIGHTMAP_ON、DIRLIGHTMAP_COMBINED、DYNAMICLIGHTMAP_ON、LIGHTMAP_SHADOW_MIXING、SHADOWS_SHADOWMASK。您可以使用图形设置窗口去除这些Keyword。
- 在 Built-in Render Pipeline 中,如果您的项目使用彼此不同的层设置,Unity 会将这组Keyword添加到所有图形着色器中:UNITY_HARDWARE_TIER1、UNITY_HARDWARE_TIER2、UNITY_HARDWARE_TIER3。有关详细信息,请参阅图形层:图形层和着色器变体。
- 着色器Keyword限制
着色器keyword限制 Unity 最多可以使用 4,294,967,294 个全局着色器keyword。单个着色器和计算着色器最多可以使用 65,534 个本地着色器keyword。
着色器源文件中声明的每个keyword及其依赖项都计入此限制。依赖项包括着色器使用UsePass和fallbacks包含的Pass。
如果 Unity 多次遇到同名的着色器keyword,则仅计入限制一次。
如果着色器总共使用超过 128 个keyword,则会导致运行时性能下降;因此,最好将keyword的数量保持在较低水平。Unity 总是为每个着色器保留 4 个keyword。
- 开启关闭、检查状态着色器Keyword
要检查是否为图形着色器启用了本地keyword,请使用Material.IsKeywordEnabled或Material.EnableKeyword。对于计算着色器,请使用ComputeShader.IsKeywordEnabled或ComputeShader.EnableKeyword。
要检查是否启用了全局keyword,请使用Shader.IsKeywordEnabled或Shader.EnableKeyword或ComputeShader.enabledKeywords。
要为图形着色器启用或禁用本地着色器keyword,请使用Material.SetKeyword、Material.EnableKeyword或Material.DisableKeyword。对于计算着色器,请使用ComputeShader.SetKeyword、ComputeShader.EnableKeyword或ComputeShader.DisableKeyword。
要启用或禁用全局着色器keyword,请使用Shader.SetKeyword、ComputeShader.EnableKeyword或ComputeShader.DisableKeyword。
要使用命令缓冲区启用或禁用本地或全局keyword,请使用CommandBuffer.EnableKeyword或CommandBuffer.DisableKeyword。
- 运行时管理keyword
在运行时管理keyword集 当您创作着色器时,您在集合中声明keyword。一个集合包含互斥keyword。 在运行时,Unity 没有这些集合的概念。它允许您独立启用或禁用任何keyword,启用或禁用keyword不会影响任何其他keyword的状态。这意味着可以启用同一组中的多个keyword,或禁用一组中的所有keyword。 当一组中的多个keyword被启用或一组中没有keyword被启用时,Unity 会选择一个它认为“足够好”匹配的变体。无法保证到底会发生什么,并且可能导致意想不到的结果。最好通过仔细管理keyword状态来避免这种情况。
- 变体剥离
- 在可能的情况下使用shader_feature而不是multi_compile。
- 确保您不使用 定义未使用的关键字multi_compile。
- 指示着色器关键字何时仅影响给定的着色器阶段
使用编辑器配置剥离
- 在Graphics Settings 窗口中,配置Shader stripping部分中的设置:
- 确保始终包含的着色器设置中不包含不需要的着色器。
- 与 GPU 实例化、光照贴图和雾相关的条带变体。
- 在内置渲染管道中,如果您的层设置不同并不重要,请确保它们彼此相同。有关详细信息,请参阅图形层。
- 在通用渲染管道 (URP) 中,禁用 URP 资源中未使用的功能。有关详细信息,请参阅着色器剥离。
使用构建回调剥离 ``` c# using System.Collections.Generic; using UnityEditor; using UnityEditor.Build; using UnityEditor.Rendering; using UnityEngine; using UnityEngine.Rendering;
// Simple example of stripping of a debug build configuration class ShaderDebugBuildProcessor : IPreprocessShaders { ShaderKeyword m_KeywordDebug; public ShaderDebugBuildProcessor() { m_KeywordDebug = new ShaderKeyword("DEBUG"); } // Multiple callback may be implemented. // The first one executed is the one where callbackOrder is returning the smallest number. public int callbackOrder { get { return 0; } } public void OnProcessShader( Shader shader, ShaderSnippetData snippet, IList<ShaderCompilerData> shaderCompilerData) { // In development, don't strip debug variants if (EditorUserBuildSettings.development) return; for (int i = 0; i < shaderCompilerData.Count; ++i) { if (shaderCompilerData[i].shaderKeywordSet.IsEnabled(m_KeywordDebug)) { shaderCompilerData.RemoveAt(i); --i; } } } }```
6.着色器加载
自己管理着色器编译,并预加载
ShaderVariantCollection.WarmUp()7.在运行时替换着色器
应通过脚本使用函数 Camera.RenderWithShader 或 Camera.SetReplacementShader 来实现着色器替换。这两个函数均采用 shader 和 replacementTag。
工作方式如下:摄像机按正常方式渲染场景,对象仍使用自己的材质,但要更改最终使用的实际着色器:
- 如果 replacementTag 为空,则使用指定的替换着色器来渲染场景中的所有对象。
- 如果 replacementTag 不为空,则对于将要渲染的每个对象:
- 查询真实对象的着色器以获取标签值。
- 如果没有该标签,则不渲染对象。
- 在替换着色器中找到一个子着色器,并且该子着色器的一个给定标签具有找到的值。如果找不到此类子着色器,则不渲染对象。
- 现在,使用该子着色器来渲染对象。
内置着色器中的着色器替换标签 所有内置着色器都设置了一个“RenderType”标签,可以在使用替换着色器进行渲染时使用此标签。标签值如下: * Opaque:大部分着色器(法线、自发光、反射和地形着色器)。 * Transparent:大部分半透明着色器(透明、粒子、字体和地形附加通道着色器)。 * TransparentCutout:遮罩透明度着色器(透明镂空、两个通道植被着色器)。 * Background:天空盒着色器。 * Overlay:光环、光晕着色器。 * TreeOpaque:地形引擎树皮。 * TreeTransparentCutout:地形引擎树叶。 * TreeBillboard:地形引擎公告牌树。 * Grass:地形引擎草。 * GrassBillboard:地形引擎公告牌草。
因此,比如说,如果所有着色器都要有一个值为“Opaque”、“Transparent”、“Background”或“Overlay”的“RenderType”标签,则可编写一个替换着色器,该着色器只使用一个具有 RenderType = Solid 标签的子着色器来渲染实体对象。在替换着色器中找不到其他标签类型,因此不会渲染对象。或者您也可以为不同“RenderType”标签值编写若干子着色器。顺便提一下,所有内置 Shader 对象都设置了一个“RenderType”标签。
eg:
//Start() 函数指定替换着色器:
void Start() {
camera.SetReplacementShader (EffectShader, "RenderType");
}
//此函数请求 EffectShader 使用 RenderType 键。对于所需的每个 RenderType,EffectShader 都有一个键/值标签。Shader 应如下所示:
Shader "EffectShader" {
SubShader {
Tags { "RenderType"="Opaque" }
Pass {
...
}
}
SubShader {
Tags { "RenderType"="SomethingElse" }
Pass {
...
}
}
...
}8.计算着色器
9.Error and loading shaders
二、内置着色器
1. Standard Shader
Unity 标准着色器是一个包含一整套功能的内置着色器。标准着色器还包含一种称为__基于物理着色 (Physically Based Shading)__ 的高级光照模型。基于物理着色 (PBS) 以一种模仿现实的方式模拟材质和光照之间的相互作用。PBS 最近才在实时图形中成为可能。在光照和材质需要以直观而逼真的状态共存的情况下,这种光照模型的效果最佳。
- 术语 基于物理的着色时:
能量守恒(Energy conservation)。这是一种物理学概念,可确保对象反射的光绝不会对于接受的光。材质的镜面反射越强, 其漫反射就应该越弱;表面越光滑, 高光越强且高光面积越小。
高动态范围 (High Dynamic Range, HDR)。这是指超出常规 0-1 范围的颜色。例如,太阳很容易比蓝天亮十倍。
- Content and Context
在思考Unity的光照时,将概念划分为所谓的Content(光照和渲染的对象)
和Context(即场景中会影响光照对象的光照) 会很方便。
- Context
对象发生光照时,了解哪些光源会影响对象非常重要。场景中通常有直接光源:可能是放置在场景中的游戏对象光源。此外还有间接光源,例如反射和反射光。这些光源都会对对象的材质产生影响,从而产生摄像机在对象表面上看到的最终结果。
这种划分并非硬性和绝对的,通常可能被认为的“内容”也可能是另一个对象的光照上下文的一部分。
在这方面,一个很好的例子就是位于沙漠景观中的建筑物。该建筑物将从天空盒获取光照信息,也可能会从周围地面的反射光获取这些信息。
但是,可能有一个角色站在建筑物的外墙附近。对于该角色,建筑物是光照上下文的一部分:建筑物可能投射阴影,建筑物可能将反射光从墙壁投射到角色身上,或者角色可能有直接反射建筑物本身的反射部分。
- Metallic 与 Specular 工作流程的比较
使用标准着色器创建材质时,可选择以下两个着色器之一:Standard 或 Standard (Specular setup)。两者接受的数据不同,如下所述:
Standard:着色器显示“Metallic”值,表示材质是不为金属性。在使用金属性材质的情况下,反照率颜色 (Albedo) 控制镜面反射的颜色,且大多数光线以镜面反射形式反射。非金属性材质具有与入射光颜色相同的镜面反射,并且在正面观察表面时几乎不会反射。
Standard (Specular setup):选择此着色器意味着使用传统方法。使用镜面反射颜色来控制材质中镜面反射的颜色和强度。此设置可使镜面反射具有与漫射不同的颜色。
使用上述任一种方法都能很好地表示最常见的材质类型,因此在大多数情况下,具体选择哪种方法是基于美术工作流程的个人喜好问题。
2.标准粒子着色器
三、使用 Shader Graph
https://docs.unity3d.com/Packages/com.unity.shadergraph@12.1/manual/index.html
四、编写着色器
1. 概述
为 Unity 编写着色器时,使用以下语言:
- 一种称为 HLSL 的编程语言。使用它可编写着色器程序本身。有关 HLSL 的更多信息,请参阅 Unity 中的 HLSL。
- 一种称为 ShaderLab 的 Unity 特定语言。使用它可定义 Shader 对象,它充当着色器程序的容器。有关 ShaderLab 的更多信息,请参阅 ShaderLab。 不需要为不同的平台使用不同的语言;Unity 针对不同的图形 API 将 HLSL 和 ShaderLab 代码编译为不同语言。有关更多信息,请参阅着色器编译。
注意:如果需要,还可以直接用 GLSL 和 Metal 编写着色器程序。在常规工作流程中,不建议或不需要这样做。有关如何使用 GLSL 的更多信息,请参阅 Unity 中的 GLSL。
2. ShaderLab
定义Shader对象
Shader "<name>"
{
<optional: Material properties>
<One or more SubShader definitions>
<optional: custom editor>
<optional: fallback>
}
Shader "Examples/ShaderSyntax"
{
CustomEditor = "ExampleCustomEditor"
Properties
{
// 此处是材质属性声明
}
SubShader
{
// 此处是定义子着色器的其余代码
Pass
{
// 此处是定义通道的代码
}
}
Fallback "ExampleFallbackShader"
}
1. 定义材质属性
Properties
{
<Material property declaration>
<Material property declaration>
}
材质属性声明格式
[optional: attribute] name("display text in Inspector", type name) = default value
- Integer(旧版 Int)。
_ExampleName ("Integer display name", Integer) = 1 - Float。
_ExampleName ("Float display name", Float) = 0.5 - Texture2D。
_ExampleName ("Texture2D display name", 2D) = "" {}or_ExampleName ("Texture2D display name", 2D) = "red" {}, 默认值字符串中可使用 Unity 的内置纹理之一:- “white”(RGBA:1,1,1,1)、
- “black”(RGBA:0,0,0,1)、
- “gray”(RGBA:0.5,0.5,0.5,1)、
- “bump”(RGBA:0.5,0.5,1,0.5)
- “red”(RGBA:1,0,0,1)
- Texture2DArray。
_ExampleName ("Texture2DArray display name", 2DArray) = "" {} - Texture3D。
_ExampleName ("Texture3D", 3D) = "" {}。默认值为 “gray”(RGBA:0.5,0.5,0.5,1)纹理。 - Cubemap。
_ExampleName ("Cubemap", Cube) = "" {}。默认值为 “gray”(RGBA:0.5,0.5,0.5,1)纹理。 - CubemapArray。
_ExampleName ("CubemapArray", CubeArray) = "" {}。 - Color。
_ExampleName("Example color", Color) = (.25, .5, .5, 1)。这会在着色器代码中映射到 float4。颜色拾取器。 - Vector。
_ExampleName ("Example vector", Vector) = (.25, .5, .5, 1)。这会在着色器代码中映射到 float4。
材质属性特性 1. [Gamma] 指示浮点数或者矢量属性使用 sRGB值。这意味着如果项目中的颜色空间需要,则它必须与其他sRGB值一起转换。 2. [HDR] 指示颜色使用的高动态范围值。 3. [HideInInspector], 编辑器隐藏属性。 4. [MainTexture] 设置为主纹理, 可以使用Material.mainTexture进行访问。默认情况下,Unity 将具有属性名称 _MainTex 的纹理视为主纹理。如果纹理具有不同的属性名称,但希望 Unity 将它视为主纹理,请使用此特性。 5. [MainColor] 设置为材质设置主色,可以使用 Material.color 进行访问。 6. [NoScaleOffset] 告知 Unity 编辑器隐藏此纹理属性的平铺和偏移字段。 7. [Normal]指示纹理属性需要法线贴图。 8. [PerRendererData] 指示纹理属性将来自每渲染器数据,形式为 MaterialPropertyBlock。 材质 Inspector 会将这些属性显示为只读。
Shader "Examples/ExampleShader"
{
SubShader
{
HLSLINCLUDE
// 在此编写要共享的 HLSL 代码
ENDHLSL
Pass
{
Name "ExampleFirstPassName"
Tags { "LightMode" = "ExampleLightModeTagValue" }
// 在此编写设置渲染状态的 ShaderLab 命令
HLSLPROGRAM
// 此 HLSL 着色器程序自动包含上面的 HLSLINCLUDE 块的内容
// 在此编写 HLSL 着色器代码
ENDHLSL
}
Pass
{
Name "ExampleSecondPassName"
Tags { "LightMode" = "ExampleLightModeTagValue" }
// 在此编写设置渲染状态的 ShaderLab 命令
HLSLPROGRAM
// 此 HLSL 着色器程序自动包含上面的 HLSLINCLUDE 块的内容
// 在此编写 HLSL 着色器代码
ENDHLSL
}
}
}
3. HLSL
1. 预处理语法
- pragma
#pragma target 3.0
#pragma exclude_renderers vulkan
#pragma vertex vert
#pragma fragment frag
2. 着色器语义
- #pragma vertex vert 主顶点着色器函数。
- #pragma fragment frag,
输入数据语义:
| 输入 | 说明 | 类型 |
|---|---|---|
| BINORMAL[n] | 二进制 | float4 |
| BLENDINDICES[n] | 混合索引 | uint |
| BLENDWEIGHT[n] | 混合权重 | FLOAT |
| COLOR[n] | 漫射和反射颜色 | float4 |
| NORMAL[n] | 普通向量 | float4 |
| POSITION[n] | 对象空间中的顶点位置。 | float4 |
| POSITIONT | 转换的顶点位置。 | float4 |
| PSIZE[n] | 点大小 | FLOAT |
| TANGENT[n] | 正切 | float4 |
| TEXCOORD[n] | 纹理坐标 | float4 |
顶点输出数据语义:
| 输出 | 说明 | 类型 |
|---|---|---|
| COLOR[n] | 漫射或反射颜色 | float4 |
| FOG | 顶点雾 | FLOAT |
| POSITION[n] | 顶点在齐次空间中的位置。 通过将 (x,y,z) 除以 w,在屏幕空间中计算位置。 每个顶点着色器都必须写出具有此语义的参数。 | float4 |
| PSIZE | 点大小 | FLOAT |
| TESSFACTOR[n] | 分割因子 | FLOAT |
像素着色器输入语义 |输入 |说明 |类型 | |---- | :-- |----| |COLOR[n] |漫射或反射颜色 |float4| |TEXCOORD[n] |纹理坐标 |float4| |VFACE |点指示面向背的基元的浮点标量。 负值向后面,而正值则面对相机。!注意Direct3D 9 着色器模型 3.0 中提供了此语义。 对于 Direct3D 10 及更高版本,请改用 SV_IsFrontFace 。 |FLOAT| |VPOS |屏幕空间中的像素位置 (x,y) 。 若要将此语义 () 的 Direct3D 9 着色器转换为 Direct3D 10 及更高版本的着色器,请参阅 Direct3D 9 VPOS 和 Direct3D 10 SV_Position) |float2|
像素着色器输出语义 |输入 |说明 |类型 | |---- | :-- |----| |COLOR[n] |输出颜色 |float4| |DEPTH[n] |输出深度 |FLOAT|