图形学中的着色器是运行在GPU端的程序。依靠着色器编程,开发者可以修改GPU对于游戏对象的渲染流程。例如,使用顶点着色器进行顶点变换和传递数据,利用片元着色器可以逐片元地渲染。(注意:这些操作都发生在GPU端,目的是控制屏幕上的渲染效果,通常不会真正影响内存/硬盘中游戏原始物体的几何/颜色数据)
Unity项目中着色器的编译实际上包括两个部分:在打包时分析着色器依赖,清点着色器变体,之后面向打包的目标平台(Win/MacOS/Android/iOS......)进行编译。在运行时被编译后的着色器代码还需要被图形硬件驱动加载入GPU中,并完成机器码转换,才最终可以变成硬件指令。后者是一个高度本地化的过程,硬件的具体型号、驱动的版本不同,此过程的结果也不一样,因此需要在客户端完成。但是好在占用的时间极短,在中小项目中不会在运行时造成可被察觉的影响。在着色器数量极多的3A游戏中,通常会在第一次启动时由程序一次性完成这种二次编译(“正在编译着色器......”),之后缓存在本地以供调用,以彻底避免可能在游戏过程中偶尔可能产生的编译卡顿。
Unity中的着色器可以通过.shader文件手动编写,或是使用shadergraph包进行可视化节点式的编辑。
Unity中一个三维模型存储在Mesh资产中,材质mat是对模型表面视觉效果的配置文件,其中需要指定一个着色器Shader。
存储在模型文件中的数据 (.FBX, .OBJ, .blend 等)
模型文件定义了物体的几何结构和基础数据。当导入 Unity 后,这些数据主要存储在 Mesh 资产中。
顶点位置 (Vertex Positions):定义模型形状的最基本数据,即所有点在三维空间中的坐标。
网格拓扑 (Mesh Topology):定义了哪些顶点连接在一起构成了三角形(或四边形),从而形成了模型的表面。
UV坐标 (UV Coordinates)为模型上每一个顶点指定一个UV坐标,将其映射到纹理贴图的对应位置。模型只包含坐标,不包含纹理图片本身。
法线 (Normals):定义了每个顶点或面的法线朝向。这个数据它决定了在光照计算中表面如何反射光线,当然还有网格的正反面。
顶点色 (Vertex Colors):可以为模型的每个顶点指定一个颜色。这可以用来做一些简单的颜色混合或作为数据传递给着色器。
骨骼和蒙皮权重 (Bones & Skin Weights):对于可动的角色模型,模型文件包含了骨骼(Armature/Rig)结构以及每个顶点受哪些骨骼影响的权重信息,用于实现动画。
子网格 (Sub-meshes):一个模型文件可以包含多个独立的几何部分。例如,一个汽车模型可能将车身、轮子、玻璃分为三个子网格,以便为它们应用不同的材质。
材质文件定义了模型的外观和渲染方式。它本质上是一个“配置”文件。
着色器引用 (Shader Reference):每个材质引用一个着色器文件用于处理渲染过程。
纹理贴图 (Textures):材质包含了对着色器所需纹理文件的引用。这些是普通的图像文件(.PNG, .JPG, .TGA 等)。
反照率/基础色 (Albedo/Base Color):物体的基本颜色贴图。
法线贴图 (Normal Map):用于增加表面细节,模拟凹凸感。
金属度/平滑度 (Metallic/Smoothness/Roughness):定义物体表面的金属性和光滑程度。
自发光贴图 (Emission Map):定义物体哪些部分会自己发光。
环境光遮蔽(AO)、高度图等。
颜色值 (Colors):简单的颜色属性,例如,你可以给材质一个整体的“色调”(Tint Color)。
数值和滑块 (Floats & Sliders):着色器中定义的各种可调参数,例如金属度、平滑度、透明度、发光强度等。
渲染设置 (Rendering Settings):例如渲染队列(Render Queue,决定透明物体的渲染顺序)、是否双面渲染(Double-Sided)等。
属性 (Properties):在着色器的顶部定义,这些是会显示在材质检视面板(Inspector)上的参数。它充当了着色器代码与美术/设计师之间的桥梁,允许用户通过材质去调整颜色、贴图、滑块数值等。
子着色器 (SubShader):一个着色器可以包含一个或多个子着色器。Unity会从上到下检查列表,并使用目标硬件支持的第一个子着色器。这是一种实现多平台和多硬件兼容性的机制(例如,为高端PC写一个复杂的PBR子着色器,为移动设备写一个简化的版本)。
通道 (Pass):每个子着色器由一个或多个通道(Pass)组成。每个Pass代表一次完整的渲染操作。例如,一个物体可能需要一个Pass来渲染它的主要颜色和光照,再用另一个Pass来投射阴影。
渲染状态设置 (Render State Setup):在Pass中,可以设置GPU的渲染状态。例如:
Tags:向渲染管线提供关于着色器意图的元数据(如"RenderType"="Opaque"表示这是一个不透明物体)。
混合模式(Blend Mode):控制透明效果。
深度测试(ZTest):决定物体是否会被其他物体遮挡。
剔除模式(Cull Mode):决定渲染正面、背面还是双面。
着色器代码 (Shader Code):这是着色器的“大脑”,通常用Cg/HLSL语言编写,包含在CGPROGRAM...ENDCG或HLSLPROGRAM...ENDHLSL块中。这些代码定义了顶点着色器(Vertex Shader)和片元/像素着色器(Fragment/Pixel Shader)等函数。
顶点着色器:处理模型传入的顶点数据(位置、UV、法线等),进行坐标变换、顶点动画等操作。
片元着色器:计算每个像素的最终颜色,这是进行光照计算、纹理采样和颜色混合的地方。
回退 (Fallback):一个可选的声明,用于指定当所有子着色器在目标硬件上都无法运行时,应该使用哪个备用着色器。这是一个保证兼容性的“安全网”
需要注意的是shaderlab(.shader的内容)并不是编程语言,可视作一个声明式的配置文件。Cg(C for Graphics)是legacy方案,不推荐使用。正确做法是在shaderlab文件内嵌套HLSL语言的着色器代码,嵌套在HLSLPROGRAM ... ENDHLSL中(一些书中叫做Cg/HLSL语言,因为Unity项目中的两种语言几乎相同。但Unity6的官方文档一律称作HLSL,参见 https://docs.unity3d.com/6000.0/Documentation/Manual/writing-shader-writing-shader-programs-hlsl.html) 。除HLSL之外,GLSL、Metal也可用但不推荐。
官网文档中的描述:
When you write shaders for Unity, you use the following languages:
- A programming language called HLSL. Use this to write the shader programs themselves. For more information on HLSL, see HLSL in Unity.
- A Unity-specific language called ShaderLab. Use this to define a Shader object, which acts as a container for your shader programs. For more information on ShaderLab, see ShaderLab.
因此可将ShaderLab视作容器,着色器的核心逻辑基于HLSL。
该示例中的代码来自 https://docs.unity3d.com/6000.0/Documentation/Manual/urp/writing-shaders-urp-basic-unlit-structure.html ,注释是我补充的。

但凡b站支持一下代码块......也不至于......
也许能日更?明天大概是对代码上的细节继续写一点,以及会包含一些内置着色器讲解。