Zh/Shader
着色器是在 图形处理器(Graphics Processing Unit, GPU) 上运行的一套程序,用于确定应如何绘制对象。着色器替代了传统的固定渲染管线,可以实现图形计算中的渲染相关计算,由于其可编辑性,可以实现各种各样的图像效果而不用受显卡的固定渲染管线限制。着色器曾只存在于离线渲染(如 电影工业)领域,而实时渲染领域的着色器则是在 Microsoft 推出 Shader Model(着色器模型) 后才被首次引入。
- Source 3D渲染中的所有内容都使用基于着色器绘制的方法
- 着色器根据存储在 材质 文件中的参数进行进一步工作,虽然看上去很简单,但里面存有非常复杂的来处理 实时阴影 、 照明 和 折射 等效果的配置信息。
类型
着色器(Shader)主要有顶点着色器(Vertex Shader,以下简称 VS)和像素着色器(Pixel Shader,以下简称 PS)两种(注:两种着色器在实现上略有不同)。
着色语言
目前有三种主要的着色器语言:高阶着色器语言(HLSL),C for Graphics (Cg)和 OpenGL着色语言(GLSL)。Source 使用基于 HLSL 的着色器。而且 Cg 与其也非常相似,故大多数 Cg 着色器都可以快速轻松地移植到 HLSL。
着色模型
(以下简称 SM) SM 直接定义如何使 GPU 使用高阶着色技术,可以防止太老旧 GPU 运行基于新着色技术的程序。
Source 支持 SM 2.0(包括 PS 2.0b)和 SM 3.0。其中 SM 3.0 是一次巨大飞跃,支持浮点精度运算,是现代高画质游戏的基石。因此 Source 的 shader 本身具有极强的拓展性。
注:为 SM 3.0 编写的着色器可能无法在 Mac 和 Linux 系统上正常工作,因为 Valve 的图形Wrapper运行这个时缺乏某些支持。
- 为较新的GPU创建着色器时,请务必记住去支持那些较旧GPU用的着色器,否则这样会产生大量限制。
- 旧的GPU可能要“着色器回退 (shader fallbacks)”,如果新SM用不了,那么游戏会使用旧SM。
像素着色器
每个被渲染的像素都与像素着色器有关。PS需要来自顶点属性插值的输入,然后再用它来栅格化图像。PS可以产生涉及单个像素颜色的大量效果,例如 折射 、逐像素照明 和 反射 等等。
像素着色器 示例
这里我们为你提供一个像素着色器示例,可以在 Source 中使用。此着色器旨在用作 Post-processing (即 后处理) ,并创建灰度效果。
// 指定一个纹理采样器,其实际来源在是 vmt 中确定的 sampler2D Texture0 : register( s0 ); // PS返回像素的颜色值(所以这里是float4) float4 main( float2 texCoord : TEXCOORD0 ) : COLOR { // 在指定的纹理坐标处对纹理进行采样 float4 tex = tex2D( Texture0, texCoord ); // 用灰度去显示像素颜色值 // - 在像素颜色与指定矢量之间执行点积 // - 在整个图像处理过程中,对于灰度级效果,可寻到 0.222、0.707、0.071 float4 grey = dot(float3(0.222, 0.707, 0.071), tex); // 以float4的形式返回像素颜色 return grey; }
顶点着色器
顶点着色器应用于 可编程管线(Programmable Pipeline) 上运作的每个 顶点(Vertex)。其最基本的功能是将几何体转换为 屏幕空间(Screen-Space) 坐标,以便 像素着色器 去栅格化图像。顶点着色器可以修改这些位置坐标以执行网格变形。它们还可以从 网格(Mesh) 接收其他信息,包括 法线、切线和纹理坐标 , 然后顶点着色器就执行写入 (输出寄存器) 操作,再然后,在像素着色器中的顶点之间对写入的值进行插值。注意!顶点着色器 无法创建或销毁顶点;它一次对单个顶点进行操作,将一个未处理的顶点作为输入并输出单个处理的顶点。
顶点着色器 示例
这是个 传递着色器, 它不会对顶点数据进行大改,只会把数据传递到PS的阶段罢了。
// 这个头文件提供 common vs 的定义 #include "common_vs_fxc.h" // 定义输出结构 struct VS_OUTPUT { // 位置矢量 (float4) float4 pos : POSITION0; // 纹理坐标(uv - float2) float2 texCoord : TEXCOORD0; }; // 获取 位置矢量(float4) // 返回 VS_OUTPUT 结构 VS_OUTPUT main( float4 inPos: POSITION ) { // 声明一下要补充的空的 VS_OUTPUT VS_OUTPUT o = (VS_OUTPUT) 0; // 计算 输入位置 的符号 inPos.xy = sign( inPos.xy); // 用 输入的 xy 来设定输出位置 o.pos = float4( inPos.xy, 0.0f, 1.0f); // 进入到范围 [0,1] o.texCoord = (float2(o.pos.x, -o.pos.y) + 1.0f)/2.0f; return o; }
着色器在起源引擎中的应用
Source 提供两种不同形式的着色器,分别是 后处理型 和 逐对象型 ,Source 中的大多数特效和材质都非常非常非常依赖其PS组件。
后处理
后处理着色器通常是在屏幕内已已经渲染好的四边形的内容上工作的像素着色器。这些四边形会进一步被 Framebuffer 上的数据来被进行纹理处理,然后像素着色器可以改变渲染输出来创建各种效果,比如把一些基础的颜色经过后处理管道来达到最佳效果,例如动态模糊(motion blur)和泛光(bloom)。
注:某些文件已不再包含在 SDK 中。
高级后期处理着色器[如动态模糊(motion blur)和泛光(bloom)的着色器]可能还需要使用自定义 Rendertarget。有关将后处理着色器与模组集成的更多信息,请参阅 Custom_Postprocessing_Effects
逐对象
Source 中的逐对象着色器适用于具有 Valve材质 (.vmt) 中引用的着色器的任何对象,例如 model 等。逐对象着色器可用于创建折射材质、动态地修改模型顶点或其他高级渲染效果。
Source SDK 同时也提供逐对象着色器的示例[在光照贴图(lightmap)里] (sdk_lightmap.cppsdk_lightmap_vs20.fxcsdk_lightmap_ps20.fxc)