Shader学习笔记(十一)

Shader 高级篇(七)

表面着色器

表面着色器(Surface Shader) 实际上就是在顶点/片元着色器之上又添加了一层抽象。按Aras 的话来解释就是,顶点/几何/片元着色器是硬件能“理解”的渲染方式,而开发者应该使用一种更容易理解的方式。

一个简单的例子

定义Shader BumpedDiffiuse
在这里插入图片描述

最终效果

在这里插入图片描述

编译指令

编译指令最重要的作用是指明该表面着色器使用的表面函数和光照函数,并设置一些可选参数。表面着色器的CG块中的第一句代码往往就是它的编译指令。编译指令的一般格式如下:

#pragma surface surfaceFunction lightModel [optionalparams]

其中,#pragma surface 用于指明该编译指令是用于定义表面着色器的,在它的后面需要使用的表面函数(surfaceFunction)和光照模型(lightModel),同时,还可以使用一些可选参数来控制表面着色器的一些行为。

1 表面函数

表面着色器的优点在于抽象出了 “表面” 这一概念。与之前遇到的顶点/片元抽象层不同,一个对象的表面属性定义了它的反射率、光滑度、透明度等值。而编译指令中的surfaceFunction就用于定义这些表面属性。surfaceFunction 通常就是名为surf的函数,它的函数格式是固定的:

void surf (Input IN, inout SurfaceOutput o)
void surf (Input IN, inout SurfaceOutputStandard o)
void surf (Input IN, inout SurfaceOutputStandardSpecular o)

其中,后两个是 Unity 5 中由于引入了基于物理的渲染而新添加的两种结构体。SurfaceOutput、SurfaceOutputStandard和SurfaceOutputStandardSpecular 都是 Unity 内置的结构体,它们需要配合不同的光照模型使用,会在下一节进行更详细地解释。

在表面函数中,会使用输入结构体Input IN 来设置各种表面属性,并把这些属性存储在输出结构体 SurfaceOutput、SurfaceOutputStandard 或 SurfaceOutputStandardSpecular 中,再传递给光照函数计算光照结果。可参考表面着色器

光照函数

Unity 内置了基于物理的光照模型函数 StandardStandardSpecular (在UnityPBSLighting.cginc 文件中被定义),以及简单的非基于物理的光照模型函数 LambertBlinnPhong (在Lighting.cginc 文件中被定义)。指定了使用Lambert 光照函数。
可以使用下面的函数来定义用于前向渲染中的光照函数:

//用于不依赖视角的光照模型,例如漫反射
half4 Lighting (SurfaceOutput s,half3 lightDir,half atten);
//用于依赖视角的光照模型,例如高光反射
half4 Lighting (SurfaceOutput s,half3 lightDir,half3 viewDir,half atten);

可参考表面着色器中的自定义光照模型 找到更全面的自定义光照模型的介绍。可参考表面着色器的光照例子,展示了如何使用表面着色器来自定义常见的漫反射、高光反射、基于光照纹理等常见的光照模型。

其他可选参数

可参考编写表面着色器中找到更加详细的参数和设置说明。

1.自定义的修改函数。除了表面函数和光照模型外,表面着色器还可以支持其他两种自定义的函数:顶点修改函数(vertex:VertexFunction)最后的颜色修改函数(finalcolor:ColorFunction)。顶点修改函数允许自定义一些顶点属性,例如,把顶点颜色传递给表面函数,或是修改顶点位置,实现某些顶点动画等。最后的颜色修改函数则可以在颜色绘制到屏幕前,最后一次修改颜色值,例如实现自定义的雾效等。
2.阴影。可通过一些指令来控制和阴影相关的代码。例如,addshadow 参数会为表面着色器生成一个阴影投影的Passfullforwardshadows 参数则可以在前向渲染路径中支持所有光源类型的阴影。可以用noshadow 参数来禁用阴影
3.透明度混合和透明度测试。可通过alphaalphatest 指令来控制透明度混合和透明度测试。例如:alphatest:VariableName 指令会使用名为 VariableName 的变量来剔除不满足条件的片元。此时,可能还需要使用上面提到的addshadow 参数来生成正确的阴影投影的Pass。
4.光照。一些指令可控制光照对物体的影响。如,noambient 参数会告诉Unity 不要应用任何环境光照或光照探针(light probe)。novertexlights 参数告诉 Unity 不要应用任何逐顶点光照。noforwardadd 会去掉所有前向渲染中的额外的Pass.还有一些用于控制光照烘培、雾效模拟的参数,如nolightmap、nofog 等。
5.控制代码的生成。如果确定该表面着色器只会在某些渲染路径中使用,就可以 exclude_path:deferredexclude_path:forwardexclude_path:prepass 来告诉 Unity 不需要为某些渲染路径生成代码。

两个结构体

一个表面着色器需要使用两个结构体:表面函数的输入结构体 Input,以及存储了表面属性的结构体 SurfaceOutput(Unity 5 新引入了另外两个同种的结构体 SurfaceOutputStandardSurfaceOutputStandardSpecular

数据来源:Input 结构体

Input 结构体包含了许多表面属性的数据来源,因此,它作为表面函数的输入结构体(如果自定义了顶点修改函数,它还会是顶点修改函数的输出结构体)。表列出了Input结构体中内置的其他变量。
在这里插入图片描述

表面属性:SurfaceOutput 结构体

有了Input 结构体来提供所需要的数据后,就可据此计算各种表面属性。因此,另一个结构体就是用于存储这些表面属性的结构体,即 SurfaceOutputSurfaceOutputStandardSurfaceOutputStandardSpecular,它会作为表面函数的输出,随后会作为光照函数的输入来进行各种光照计算。相比与 Input 结构体的自由性,这个结构体里面的变量是提前就声明好的,不可以增加也不会减少。SurfaceOutput 的声明可在Lighting.cginc 文件中找到:

struct SurfaceOutput {
fixed3 Albedo;
fixed3 Normal;
fixed3 Emission;
half Specular;
fixed Gloss;
fixed Alpha;
};

SurfaceOutputStandardSurfaceOutputStandardSpecular的声明可以在 UnityPBSLighting.cginc 中找到:

struct SurfaceOutputStandard {
fixed3 Albedo;
fixed3 Normal;
fixed3 Emission;
half Metallic;
half Smoothness;
half Occlusion;
fixed Alpha;
};
struct SurfaceOutputStandardSpecular {
fixed3 Albedo;
fixed3 Specular;
fixed3 Normal;
half3 Emission;
half Smoothness;
half Occlusion;
fixed Alpha;
};

在一个表面着色器中,只需要选择上述三者中的其一即可,这取决于选择使用的光照模型。Unity 内置的光照模型有两种,一种是Unity 5 之前的、简单的、非基于物理的光照模型,包括了 LambertBlinnPhong; 另一种是Unity 5 添加的、基于物理的光照模型,包括StandardStandardSpecular,这种模型会更加符合物理规律,但计算也会复杂很多。如果使用了非物理的光照模型,通常会使用 SurfaceOutput 结构体,而如果使用了基于物理的光照模型 StandardStandardSpecular,分别使用 SurfaceOutputStandardSurfaceOutputStandardSpecular 结构体。其中,SurfaceOutputStandard 结构体用于默认的金属工作流程(MetallicWorkflow),对应了Standard 光照函数;而SurfaceOutputStandardSpecular 结构体用于高光工作流程(Specular Workflow),对应了StandardSpecular 光照函数。

表面着色器实例分析

实现的效果是对模型进行膨胀
这种效果的实现非常简单,就是在顶点修改函数中沿着顶点法线方向扩张顶点位置。为了分析表面着色器中4个可自定义函数(顶点修改函数、表面函数、光照函数和最后的颜色修改函数)的原理,本例中对这4个函数全部采用了自定义的实现。

Shader部分
在这里插入图片描述

最终效果

在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值