原文地址
在本文中,我将对shader是啥做个基本介绍,讨论Unity渲染管道的基础并给读者介绍如何使用unity游戏引擎中的shader.
shader广泛用于视频游戏中,用于产生很多变化效果,如光照模型,扭曲,(运动)模糊,发光(bloom)和边缘检测效果.着色语言(shading language)用于图形处理单元(GPU)编程并允许用户设置图形硬件来渲染而不是固定功能管道渲染.常用的shader类型有3种:顶点着色器(Vertex Shader),片段着色器(Fragment Shader)和几何着色器(Geometry Shader).
在Unity中用户能够编写自定义shader,然而全屏效果需要的渲染材质只在Unity Pro中才提供,本文中不会涉及它.这些全屏图形处理效果本身就是很高深的话题.由于要涉及到很多材料,我不会在编写自定义shader效果上讨论太深而主要着重于shader是什么以及如何在unity中使用它们.
在Unity中所有的渲染都是通过shader进行的.Unity中的shader是些短小的脚本,它们允许用户配置显卡如何为渲染而设置.Unity本身带有超过60种的内置shader,通过使用材质来使用这些shader.在Unity中材质和shader间的关系很密切.shader包含代码,这些代码定义了使用哪种资源(asset)与属性.同时材质允许用户调整属性并赋予资源(assets).例如,如果我们创建一个新的GameObject并给其赋予一个材质,我们可以从检视器(Inspector)中选择一个shader,这个shader指定了在游戏运行时材质的外观.材质的属性根据用于渲染GameObeject的shader而不同.
在Unity中书写shader有3种方式:固定功能着色器(Fixed Function Shaders),顶点和片段着色器(Vertex and Fragment Shaders)和表面着色器(Surface Shaders).这些着色器的代码使用Unity里被称作"ShaderLab"的着色和材质语言封装起来.shader本身通常使用CG或者HLSL着色器语言.
表面着色器很常用于shader需要同时被灯光和阴影影响的情况下.既然着色器需要受灯光影响,你不想每次都为处理默认BlinnPhong光照模型写出完整的着色器代码.这允许用户用一种更简洁的方式编写复杂的着色器.如果着色器不与光照相互影响(interact)那么最好使用顶点和片段寄存器来替代.否则Unity在我们不需要它们的时候还会进行光照计算.<todo>
如果着色器无需与灯光互相影响或者你想弄一个表面着色器不能处理的效果此时顶点和片段着色器就派上用场了.它们是用于创建着色器效果最灵活的着色器,不过它使得与光照交互变得有点难.
固定功能着色器用于不支持可编程着色器的硬件.固定功能着色器常作为最后的备用方案来确保当图形处理单元(gpu)不支持特定着色器效果时游戏仍然在渲染一些有意义的东西.固定功能着色器完全使用Unity里的"ShaderJob"编写.我们稍后会更加详细的探讨它.
使用着色器我们可以定义我们的工程在我们的游戏世界里如何呈现以及它如何影响光照(react to lighting).这些灯光如何影响物体取决于着色器的管道与它使用的渲染路径(rendering path).渲染路径可以通过Unity的播放器设置改变.或者在检视器(inspector)中camera的'Rendering Path'设置中被覆盖.在Unity中有3中渲染路径:Vertex Lit,Forward Rendering和Deferred Rendering.如果显卡不能处理当前所选的渲染路径则会返回(fallback)使用另一种.所以如果显卡不支持延迟渲染(deferred rendering),Unity会自动使用前置渲染(Forward Rendering).如果不支持你前置渲染则将会切换到Vertex Lit.由于所有的着色器都受所设置渲染路径的影响,我简单的描述一下每个渲染路径都是做啥的.
Vertex Lit是可用的最简单的光照模型.它不支持实时阴影.它常用于硬件受限的老电脑上.在内部(internally)它将从一个管道中物体顶点的所有灯光值来计算光照值(这句很拗口,原文是Internally it will calculate lighting from all lights at the object vertices in one pass).因为光照是在逐顶点级别上处理的,逐像素效果是不支持的.
前置渲染根据影响物体的灯光在一个或多个管道中渲染每个物体.根据灯光设置与用户光照强度设置所有的灯光差别对待(treated differently)