Unity Shader - Writing Surface Shaders 编写表面着色器

目录:Unity Shader - 知识点目录(先占位,后续持续更新)
原文:Writing Surface Shaders
版本:2019.1

Writing Surface Shaders

编写表面着色器

编写与光照有交互的shader是复杂的。有许多不同的光源类型,不同的阴影选项,不同的rendering paths(渲染路径)(forward(正向渲染)和deferred rendering(延迟渲染)),以至于这种shader是很复杂的。

Unity中的Surface Shaders(表面着色器)是一种代码生成方法,用此方式编写光照着色器比使用相对低级的vertex/pixel shader programs(顶点/像素着色器程序)容易得多。注意,Surface Shaders并没有自定义语言,魔术或忍术的神奇之术;它仅仅是生成一些你得手写的代码。

一些例子,可看看Surface Shader Examples(表面着色器的例子)和Surface Shader Custom Lighting Examples(表面着色器自定义器光照例子)。

How it works

如何工作的

您定义了一个"surface function"(surface函数),它接受您需要的任何uv或数据作为输入,并填充输出结构SurfaceOutput。SurfaceOutput是surface的基础描述数据(有Albedo颜色,法线,自发光,高光,等等)。你可以使用HLSL编写这些代码。

Surface Shader编译器会根据你哪些所输入的,哪些所填充到输出的,等等来生成精准需要的vertex&pixel shaders,以及生成需要的forward和deferred rendering需要的pass。

Surface shader的标准Output数据结构如下:

struct SurfaceOutput
{
    fixed3 Albedo;  // diffuse color - 漫反射颜色
    fixed3 Normal;  // tangent space normal, if written - 切线空间的法线
    fixed3 Emission; // 自发光颜色
    half Specular;  // specular power in 0..1 range - 高光的强度,数值范围:0~1
    fixed Gloss;    // specular intensity - 也是控制高光的数值
    fixed Alpha;    // alpha for transparencies - 透明度的alpha值
};

在Unity Surface shaders中你可以使用PBR。内置的Standard和StandardSpecular的光照模型(查看下面)分别使用了不一样的输出数据结构:

struct SurfaceOutputStandard
{
    fixed3 Albedo;      // base (diffuse or specular) color - 基础色(漫反射或高光色)
    fixed3 Normal;      // tangent space normal, if written - 切线空间的法线
    half3 Emission;		// 自发光
    half Metallic;      // 0=non-metal, 1=metal - 金属性,0:完全没有,1:高金属性
    half Smoothness;    // 0=rough, 1=smooth - 光滑度,0:粗糙的,1:光滑的
    half Occlusion;     // occlusion (default 1) - AO(Ambient Occlusion) 的基础系数
    fixed Alpha;        // alpha for transparencies - 透明度
};
struct SurfaceOutputStandardSpecular
{
    fixed3 Albedo;      // diffuse color - 漫反射颜色
    fixed3 Specular;    // specular color - 高光色
    fixed3 Normal;      // tangent space normal, if written - 切线空间的法线
    half3 Emission;		// 自发光
    half Smoothness;    // 0=rough, 1=smooth - 光滑度,0:粗糙的,1:光滑的
    half Occlusion;     // occlusion (default 1) - AO(Ambient Occlusion) 的基础系数
    fixed Alpha;        // alpha for transparencies - 透明度
};

Samples

例子

查看Surface Shader Examples, Surface Shader Custom Lighting Examples和Surface Shader Tessellation页面。

Surface Shader compile directives

表面着色器的编译指令

Surface shader代码放在CGPROGRAM…ENDCG块之间,和其他的Shader一样。但不同的有:

  • 必须放在SubShader块中,不是Pass块中。Surface Shader将会被编译成多个pass。
  • 使用**#pragma surface …**指令来指定surface shader的surface function。

#pragma surface指令:

#pragma surface surfaceFunction lightModel [optionalparams]

Required parameters

必要的参数

  • surfaceFunction - 有surface shader代码的cg函数。函数形式:void surf(Input IN, inout SurfaceOutput o),Input structure需要你定义。Input应该宝行一些纹理坐标和其他一些Surface需要的变量。
  • lightModel - 光照模型。内置基于物理的StandardStandardSpecular,以及简单的基于非物理的Lambert(漫反射)和BlinnPhong(高光)。查阅Custom Lighting Models了解如何编写拥有你自己的光照模型。
    • Standard 光照模型使用SurfaceOutputStandard的输出结构体,与Standard(Metallic工作流模型)Shader的一样。
    • StandardSpecular 光照模型使用SurfaceOutputStandardSpecular输出结构体,与Standard (Specular setup工作流模型)Shader的一样。
    • LambertBlinnPhong 光照模型不是基于物理的(这是Unity 4.x版本的模型),但这些shader可以在低端硬件中快速的渲染。

Optional parameters

可选参数

Transparency and alpha testing

Transparency and alpha testing(透明的与alpha测试的) 有alphaalphatest指令控制。透明效果一种两种:传统的alpha混合(用于淡出的对象)或是像物理的"premultiplied blending"(预乘混合)(允许半透明保留适当的高光反射)。启用半透明将会让surface shader生成的代码包含blending指令;但请用alpha cutout(alpha剔除)将会在pixel shader生成处理fragment discard(片段禁用/剔除)的代码。剔除alpha是需要指定数值的:

  • alphaalpha:auto - 将得到简单光照功能的fade-transparency淡化透明(与alpha:fade一样),以及基于物理光照功能的premultiplied transparency预乘透明(与alpha:premul一样)
  • alpha:blend - 启用alpha混合。
  • alpha:fade - 启用传统的 fade-transparency淡化透明。
  • alphatest:VeriableName(alphatest:变量名) - 启用alpha cutout transparency(alpha剔除透明)。剔除变量是用float数值。您可能还想使用addshadow指令来生成正确的阴影投影器的pass。
  • keepalpha - 用于默认不透明的surface shader。 无论输出结构体的alpha值是什么,或者光照函数返回什么,始终写入alpha通道值为1.0(白色)。
  • decal:add - 叠加性的decal(贴花)shader(如:地形shader的AddPass)。意思就一个对象的表面在另一个对象表面上使用了additive混合。查阅Surface Shader Examples
  • decal:blend - 半透明的贴花shader。意思就一个对象的表面在另一个对象表面上使用了alpha混合。查阅Surface Shader Examples

Custom modifier functions

Custom modifier functions(自定义的修改器函数) 可用于修改或计算传入的顶点数据,或修改fragment片段最终计算的颜色。

  • vertex:VertexFunction - 自定义顶点修改函数。该函数在vertex shader生成是就调用,能修改或计算每个顶点的数据。查阅Surface Shader Examples。
  • finalcolor:ColorFunction - 自定义最终颜色修改函数。查阅Surface Shader Examples。
  • finalgbuff:ColorFunction - 自定义延迟渲染路径中修改gbuffer内容。
  • finalprepass:ColorFunction - 自定义prepass基础路径。

Shadows and Tesselation

Shadows and Tessellation(阴影与曲面细化) - 该额外的指令能用于控制阴影也曲面细化如何处理。

  • addshadow - 生成一个shadow caster pass(用于投影或是生成深度图的一个pass)。通常与自定义顶点修改功能一起使用,以便阴影的透射,或是处理一些程序化顶点动画。通常shader不需要指定一个投影用的pass来处理,因为它们通常使用fallback中自带的shadow caster pass来处理。
  • fullforwardshadows - 在正向渲染路径中支持所有的光影类型。正向渲染中shader默认只支持来自一个方向光的阴影。如果你需要在正向渲染中的点光源或是聚灯光源的阴影功能,那么使用这个指令。
  • tessellate:TessFunction - 使用DX11 GPU的曲面细化功能;这个函数计算tesselation因子。查阅Surface Shader Tessellation了解更多详情。

Code generation options

Code generation options(代码生成选项) - 默认的Surface shader生成的代码都尽可能的处理lighting(光照)/shadowing(阴影)/lightmap(光源映射)场景。但某些情况你是不需要部分功能的,这就可以调整生成代码选项来跳过不需要的功能。减少功能还可以让shader变得更小,载入更快。

  • exclude_path:deferredexclude_path:forwardexclude_path:prepass - 不生成对应渲染路径的pass(分别是Deferred Shading-延迟渲染,Forward-正向渲染和Legacy Deferred-旧版的延迟渲染)。
  • noshadow - 禁用掉所有接收阴影的shader代码。
  • noambient - 不应用ambient lighting(环境光)或light probes(光探测器)。
  • nodynlightmap - 禁用实时dynamic global illumination(动态全局光照)的支持。
  • nodirlightmap - 禁用方向光的lightmaps(lightmaps:烘焙出来的静态光源映射)支持。
  • nofog - 禁用内置的雾化处理。
  • nometa - 不生成"meta"pass(超级pass)(用于提取表面信息的光照映射和动态全局光照的pass)
  • noforwardadd - 禁用Forward(正向渲染)的叠加pass。这使得shader支持一个完整的方向光功能,与所有其他每个顶点/SH的光照计算。使shader更小。
  • nolppv - 禁用 Light Probe Proxy Volume (LPPV:光探测器代理体积,也有个组件可以了解)。
  • noshadowmask - 禁用Shadowmask(Shadowmask和Distance Shadowmask)。

Miscellaneous options

其他选项

  • softvegetation - 让surface shader仅在Soft Vegetation 打开时才被渲染。
  • interpolateview - 在顶点着色器中计算视图方向并进行插值;而不是在像素着色器中计算。这可以使像素着色更快。
  • halfasview - 将半方向向量传递到光照函数而不是视图方向。每个顶点将计算并归一化半方向。这让性能快,但并不完全正确。
  • approxview - Unity 5.0或之后的版本都删除了。改用interpolateview替换。
  • dualforward - 在正向渲染路径中使用dual lightmaps(两个lightmap)。
  • deithercrossfade - 可让Surface Shader支持抖动效果。您可以将此着色器应用于GameObject,用于该对象使用LOD Group组件的对象淡入淡出时使用。

要查看上面使用不同选项的不同之处,可以在Shadaer Inspector中使用"Show Generated Code"按钮查看帮助。

Surface Shader input structure

Surface Shader 输入数据的结构体

输入数据结构体Input通常都会有一些纹理坐标。纹理坐标必须命名开头为"uv",后跟纹理名称(或者以"uv2"开始使用第二个纹理坐标)。(如:我有的Property _MainTex纹理,那么Input 中与此Property的名对应使用,就得命名uv名称为:uv_MainTex

Input结构体可以放的数值:

  • float3 viewDir - 包含视角方向,用于计算视差效果,边缘光效,等。
  • float4加上COLOR语义 - 包含每个顶点的颜色。
  • float4 screenPos - 包含屏幕空间坐标。注意这对应GrabPass中不太适用;如果你如要自定义UV,你需要使用ComputeGrabScreenPos函数。
  • float3 worldPos - 包含世界空间坐标。
  • float3 worldRefl - 如果没有写入o.Normal,worldRefl则包含世界坐标的反射向量。例如,参见Reflect-Diffuse(反射-漫反射)着色器例子。
  • float3 worldNormal - 如果没有写入o.Normal,worldNormal则包含世界坐标法线向量。
  • float3 worldRefl; INTERNAL_DATA - 如果写入了o.Normal则包含反射向量。获取反射向量基于每个像素的法线贴图,使用WorldReflectionVector(IN, o.Norrmal)。查看Reflect-Bumped(凹凸反射)着色器例子。
  • float3 worldNormal; INTERNAL_DATA - 如果o.Normal写入了,则包含世界空间的法线向量。获取法线向量基于每个像素的法线贴图,使用WorldNormalVector(IN, o.Normal)

Surface Shaders and DirectX 11 HLSL syntax

Surface Shader与DirectX 11 HLSL 的语法

当前Surface Shader的一部分编译管线没有遵守DirectX 11-specific HLSL的语法,所以,如果你使用了HLSL的一些功能特性,如:StructuredBuffers,RWTextures等等 非DX9语法,您不得不将其封装到只有DX1的预处理器宏中。

查看 Platform Specific Differences和Shading Language页面了解更多详情。

你可能感兴趣的:(Unity,Shader,译文,Unity,Writing,Surface,Shaders)