着色器

From Valve Developer Community
< Zh
Jump to: navigation, search
English (en)Español (es)Русский (ru)Українська (uk)中文 (zh)Translate (Translate)
参见:  Category:Shaders


着色器是在 图形处理器(Graphics Processing Unit, GPU) 上运行的一套程序,用于确定应如何绘制对象。着色器替代了传统的固定渲染管线,可以实现图形计算中的渲染相关计算,由于其可编程性,可以实现各种各样的图像效果而不用受显卡的固定渲染管线限制。

笼统地说,在 起源 起源 之前的 金源 金源 使用简单的纹理映射 (Texture Mapping) 来展示材质,而 起源 起源 优秀的着色器系统在此基础上加入了新的数学模型(例如 Phong Specular(en) 着色),使得材质表现更贴近真实。

Note.png注意: 现代计算机图形学领域将渲染管线内的所有组件都定义为着色器,不一定具备图形渲染功能。例如计算着色器 (Compute Shader )。我们日常所讨论的着色器大多都是使纹理材质有独特表现的一种固定程序,广义地来看,金源 金源 也具备着色器和着色模型 (Lambertian Diffuse)。
Note.png注意: 起源 起源 一般使用 Forward 模式的渲染管线,在编写某些着色器时可能需要考虑到这个因素。
  • Source 的 3D 渲染中的所有内容都使用基于着色器绘制的方法,因为它运行着一个完整的渲染管线。
  • 着色器根据存储在 材质(en) 文件中的参数进行进一步工作,看似简单,但里面存有非常复杂的来处理 实时阴影照明折射 等特效的配置信息,它们一般由复杂的着色方程实现。
  • 着色频率和着色模型不应混为一谈。不同着色频率通过调整采样率来改变原有着色模型下的着色质量。
不同的着色频率:Flat Shading 和 Phong Shading

类型

整个光栅化渲染管线内最重要的着色器是顶点着色器(Vertex Shader)和像素着色器(Pixel Shader)。Source(en) SDK 提供了大量现成的着色器(en)

着色语言

目前有三种主要的着色器语言:高阶着色语言(HLSL(en)),C for Graphics (Cg(en)) 和 OpenGL 着色语言(GLSL)。Source 使用基于 HLSL 的着色器。HLSL 和 Cg 语言的语法基本相同,大多数 Cg 着色器都可以快速轻松地移植到 HLSL。

着色模型

Shader Model (以下简称 SM)是一种编程模型,直接地定义了如何使 GPU 运行高阶着色技术,同时可以防止太老的 GPU 运行新着色技术的程序。(防止显卡爆炸) Source(en) 支持 SM 2.0(包括 PS 2.0b)和 SM 3.0. 其中 SM 3.0 是一次巨大飞跃,支持浮点精度运算,是现代高画质游戏的基石。因此 Source 的 shader 本身具有极强的拓展性。

Note.png注意: SM 3.0 的着色器可能无法在 macOS 和 Linux 系统上正常工作,因为 Valve 的转接层 (DirectX To OpenGL) togl只支持 SM 3.0 的部分特性,如果想要着色器正常工作,你应该考虑做一个 SM 2.0b 标准的着色器。
证实: 对于 vulkan_wrapper 的情况未知 ( Source(en) 并不原生支持 Vulkan API, 只能通过 dxvk 进行转译。)
  • 为较新的 GPU 创建着色器时,请务必记住去支持那些较旧 GPU 用的着色器,否则这样会对老玩家产生很多限制。
  • 旧的 GPU 可能要“着色器回退 (shader fallbacks)”,如果新版SM用不了,那么游戏会使用旧版 SM。

像素着色器

每个被渲染的像素都与像素着色器有关。像素着色器需要来自顶点的插值输入,然后再用它来栅格化图像。像素着色器可以产生涉及单个像素颜色的大量效果,例如 折射逐像素照明反射 等等。

像素着色器 示例

这里我们提供一个像素着色器示例,可以在 Source 中使用。此着色器旨在用作 Post-processing (即 后处理) ,并创建 Grayscale。

  1.  
  2.  
  3.  
  4.  
  5.  
  6.  
  7.  
  8.  
  9.  
  10.  
  11.  
  12.  
  13.  
  14.  
// 纹理采样器 sampler2D Texture0 : register( s0 ); // 像素着色器返回像素的颜色值(所以这里是float4) float4 main( float2 texCoord : TEXCOORD0 ) : COLOR { // 在指定的纹理坐标处对纹理进行采样 float4 tex = tex2D( Texture0, texCoord ); // 利用灰度信息得到像素的颜色值 // - 在像素颜色与指定矢量做点乘 // - 处理过程中对于 Grayscale 有如下数值 ''0.222、0.707、0.071'' float4 grey = dot(float3(0.222, 0.707, 0.071), tex); // 以float4浮点数的形式返回像素颜色 return grey; }

顶点着色器

顶点着色器应用于 可编程管线(Programmable Pipeline) 上运作的每个 顶点(Vertex)。其最基本的功能是将几何体的顶点通过矩阵变换 (Transform) (具体包括世界空间 (Model Transform) 变换,视角变换 (View Transform) 和屏幕空间投影变换 (Projection Transform),三者合一即为图形学上大名鼎鼎的 "MVP 变换" )转为屏幕空间坐标等等,以便下一流程(例如三角形装配,遍历,像素着色器等)操作,顶点着色器负责处理模型数据并对这些数据执行输出操作,然后系统对顶点着色器输出的数据进行插值,再把插值结果送到像素着色器。顶点着色器也从网格(Mesh)接收其他信息,包括法线、切线和纹理 UV 坐标 等。

Note.png注意: 顶点着色器无法创建或销毁顶点。它处理的各顶点之间是无法相互访问的。

顶点着色器 示例

顶点着色器多数情况下只是扮演搬运工的角色, 它不会对顶点数据进行大改。

  1.  
  2.  
  3.  
  4.  
  5.  
  6.  
  7.  
  8.  
  9.  
  10.  
  11.  
  12.  
  13.  
  14.  
  15.  
  16.  
  17.  
  18.  
  19.  
  20.  
  21.  
  22.  
  23.  
  24.  
// 头文件 #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 中的大多数特效和材质都非常非常依赖其像素着色器组件。

后处理

后处理着色器通常是在屏幕内已经渲染好的四边形的内容上工作的像素着色器。这些四边形(2x2 像素块,一般像素着色器执行着色的最小粒度)会进一步被各 Buffer 上的数据来进行纹理处理,然后再送到像素着色器来进一步渲染,输出图元后再创建各种效果,比如把一些基础的颜色经过后处理管道来达到最佳效果,例如动态模糊(motion blur)和泛光(bloom)。

高级的后期处理着色器[如动态模糊(motion blur)和泛光(bloom)的着色器]可能还需要使用自定义 RenderTarget(en)。有关将后处理着色器与模组集成的更多信息,请参阅 Custom_Postprocessing_Effects(en)

逐对象 / 逐物体

Source 中的逐对象着色器适用于具有由 Valve 材质 (.vmt)(en) 援引的着色器的任何对象,比如 模型,笔刷 等。逐对象着色器可用于创建折射材质、动态地修改模型顶点或实现其他高级渲染效果。例如我们可以使用 Shadow Volume 采样数据写回 Stencil Buffer 来逐对象地投射高效率的动态阴影,但是请注意,目前没人在 Source 里实践过 Shadow Volume,我们一般使用 Shadowmap 或逐对象的阴影纹理。

Source SDK 同时也提供逐对象着色器的示例[在光照贴图(lightmap)里] (sdk_lightmap.cppsdk_lightmap_vs20.fxcsdk_lightmap_ps20.fxc)

扩展链接