您的位置:首页 > 移动开发 > Unity3D

《Unity Shader入门精要》笔记(二) 光照初体验

2018-01-18 22:43 155 查看

第五章 开始Unity Shader学习之旅

Shader的属性是用来干嘛的?如何定义?Pass中如何使用这个属性?

属性主要是在Unity的编辑器面板显示、修改用的。定义参考UntiyShader官方文档

pass中想要使用这个属性,需要定义一个同名变量。shader中属性变量一般以下划线开始,例如
fixed4 _Color;


指定顶点、片元着色器函数

着色器代码在CGPROGRAM 和 ENDCG之间,使用CG/HLSL语言书写。 MSDN HLSL参考

CGPROGRAM
#pragma vertex vert
#pragma fragment frag
...
ENDCG


UNITY_MATRIX_MVP用来干嘛? mul函数?SV_POSITION又是什么东西? SV_Target呢?

UNITY_MATRIX_MVP是内建矩阵,是从模型空间到投影空间的转换矩阵。对于每个模型来说Unity会自动计算好几个常用的矩阵,以便使用,也减少重复计算。

mul函数就是操作矩阵跟向量、矩阵的函数。MV 操作就是就由mul完成。所以
mul(UNITY_MATRIX_MVP, v)
就是坐标转换了。

SV_POSITION 是标明目标值是顶点投影到屏幕的最终位置,一个Pass里面应该只能指定一个

SV_Target也是一个语义(semantics),这个是用来标识最终屏幕颜色的。

关于语义,参考UnityShader语义介绍 以及 MSDN语义介绍文档

DX10以后SV开头的系统数值语义,通常有特殊含义 ,如SV_POSITION标识目标值包含了可用于光栅化的变换后的坐标。

着色器为什么能做到顶点参数自定义?自定义结构体内容是如何被填充的?

Unity根据结构体中字段的语义标识来填充,能够接受的数据都是预定义好的。

顶点着色器能接受那些参数?自定义结构体如何定义?

参考UnityShader顶点着色器能输入哪些数据

POSITION
顶点坐标, typically a
float3
or
float4
.

NORMAL
法线, typically a
float3
.

TEXCOORD0
第一个uv坐标, typically
float2
,
float3
or
float4
.

TEXCOORD1
,
TEXCOORD2
and
TEXCOORD3
are the 2nd, 3rd and 4th UV coordinates, respectively.

TANGENT
切线 (used for normal mapping), typically a
float4
.

COLOR
is the per-vertex color, typically a
float4
.

// POSITION将被填充模型顶点坐标; NORMAL指定的字段将被填充法线
struct a2v {
float4 pos : POSITION;
float3 normal : NORMAL;
};


顶点着色器与片元着色器之间如何通信?

顶点着色器函数返回值若不是单独SV_POSITION则可以被传递给片元着色器。

TEXCOORD1很多时候用来存储的值不是uv坐标,而是一些计算需要的值,用来传递给片元着色器。 数据的传递和存储不拘一格,包括后面的法线、切线、高度贴图

要熟悉Unity提供的内置文件和变量,使用时
#include "UnityCG.cginc"
来包含目标文件中的函数变量。 参考UnityShader内建文件 以及 UnityShader中的内建函数。熟悉使用,不要重复造轮子。

如何调试Shader结果?

使用假色彩输出图像,同前面说的那样, 纹理,或者说颜色空间是着色器最好的数据存储方式,一切都是颜色。所以把要调试的数值转换成颜色输出来,就是最简单的调试方法了。

Windows上 VS2012的Graphics Debugger 参考UnityShader使用Windows上的VS2012调试

Unity自带的FrameDebug,只能简单看每一步pass的结果。

小心平台引起的语法差异

float half fixed类型的区别?

简单来说颜色类型的都使用fixed3 fixed4就没错了,half跟float现在基本没啥区别了。

参考UnityShader数据类型 以及 MSDN HLSL数据类型

小心使用分支与循环语句

分支判断语句中使用的条件变量最好是常数。

每个分支中包含的操作指令数尽可能少

分支的嵌套层数尽可能少

扩展阅读《GPU精粹2》

第六章 Unity中的基础光照

什么是光照模型?BRDF是什么东西?环境光?自发光?漫反射,高光都是个啥?

所谓光照模型就是对真实世界光照的一个数学建模。计算的比较细比较真的就叫BPS,常见的都是一些简化的数学模型,为了减少计算量。常见的Phong及Lambert以及Blinn-Phong模型。

现实世界中,我们能看到一个物体,受到的各种光线的反射、折射影响太复杂,标准光照模型把光线分为4个部分:

自发光 2. 高光反射 3. 漫反射 4. 环境光

那高光反射跟漫反射有什么区别呢?简单理解就是高光反射才是反射,漫反射应该叫散射,漫反射会把光线反射到各个方向。参考下金属的反光,就是高光了。

环境光、自发光没啥好解释的,望文知义。

漫反射、高光如何计算?

漫反射采用Lambert定律:反射光线的强度与表面法线和光源方向之间夹角的余弦值成正比。 好,之前的数学知识开始排上用场了。n⃗ ⋅l⃗ =|n⃗ ||l⃗ |cosθ,只要N和L都是单位向量,就妥了。正式的公式如下: Clight为光线颜色,Mdiffuse为材质反射颜色

Cdiffuse=(Clight⋅Mdiffuse)max(0,n⃗ ⋅l⃗ );

高光的计算就稍微复杂一点了,主要是跟观察方向有关。如下图:



而r⃗ =2(n⃗ ⋅I⃗ )n⃗ −I⃗ 计算得出。那么这个公式到底几个意思?怎么理解呢?r⃗ +I⃗ 的结果肯定是在n⃗ 方向上,而大小为I⃗ 在n⃗ 上的投影的2倍。根据前面向量点积的公式,2(n⃗ ⋅I⃗ )就是投影的2倍了。注意计算点积是r跟v。公式如下:

cspecular=(clight⋅mspecular)max(0,v̂ ⋅r)Mgloss

另一种简化计算方法(实际是PBS中的微表面反射的简化版本),就是计算光线向量跟视线向量的中值,再与法向量点乘得到ĥ =normalize(v+I)。公式也变成了下面这样,点积部分为法向量跟ĥ :



cspecular=(clight⋅mspecular)max(0,n̂ ⋅ĥ )Mgloss

其中使用的Mgloss,是光泽度,max(0,n̂ ⋅ĥ )Mgloss这部分的取值图像大概就是这样:



可以理解Mgloss越大,图像越陡峭,高亮范围就越小。

(顺便发现一个在线画数学图的网站)

逐顶点光照跟逐像素光照的区别?如何选择?

针对每个顶点计算一次光照,当然比每个像素都计算一遍光照要节省的多。由于逐像素光照的消耗,所以使用要谨慎了。

逐像素的效果要优于逐顶点。一般来说,最多四个光源可以使用逐像素光照,其他光源就得只使用顶点光照了。

Unity光照实践要点

Pass中设置
Tags{ "LightMode" = "ForwardBase"}


引用光照的相应头文件
#include "Lighting.cginc"


属性要使用,需要定义对应的变量,变量命名以下划线开头,如_DiffuseColor;

内建变量熟悉 UNITY_MATRIX_MVP UNITY_LIGHTMODEL_AMBIENT _WorldSpaceLightPos0

使用Fallback “Diffuse”

对于平行光,_WorldSpaceLightPos0就是向量,计算光照方向时,不用再减顶点或像素位置

光照在世界空间和模型空间计算有没有区别?没有。 如果嫌法线转世界空间不方便,可以简单的把光照向量转到模型空间来计算。

集中一下上面的链接:

UntiyShader官方文档

MSDN HLSL参考

HLSL内建函数列表

UnityShader语义介绍

MSDN语义介绍文档

UnityShader顶点着色器能输入哪些数据

UnityShader内建文件

UnityShader中的内建函数

UnityShader使用Windows上的VS2012调试

UnityShader数据类型

MSDN HLSL数据类型

《GPU精粹2》
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  unity shader