开启辅助访问
 找回密码
 注册帐号

扫一扫,访问微社区

教程分享

关注:577

当前位置:游戏蛮牛 技术专区 教程分享

查看: 685|回复: 3

[自学总结] 【Unity Shaders】学习笔记——SurfaceShader(十一)光照模型

[复制链接]  [移动端链接]
5熟悉之中
939/1000
排名
3170
昨日变化
3

188

主题

224

帖子

939

积分

Rank: 5Rank: 5

UID
128653
好友
0
蛮牛币
2017
威望
0
注册时间
2015-11-12
在线时间
124 小时
最后登录
2017-2-21
发表于 2016-10-18 11:45:50 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有帐号?注册帐号

x

如果你想从零开始学习Unity Shader,那么你可以看看本系列的文章入门,你只需要稍微有点编程的概念就可以。

水平有限,难免有谬误之处,望指出。

LitSphere(Matcap)

发光球体光照模型就是将发光球体的纹理映射在球体上,来实现光照效果。这可以创造一些效果细腻的发光球体效果,但是它不受光照影响,改变光照的方向,球体的光照效果不变。如果要在固定视角的场景里制作细腻的球体光照,这会是一个不错的选择。

准备小球纹理贴图:

1.png

2.png

3.png

1、定义Properties:

[C#] 纯文本查看 复制代码
 Properties {  
        _MainTint ("Diffuse Tint", Color) = (1,1,1,1)  
        _MainTex ("Base (RGB)", 2D) = "white" {}  
        _NormalMap ("Normal Map", 2D) = "bump" {}  
    }  


2、编写预编译命令:

[C#] 纯文本查看 复制代码
#pragma surface surf Unlit vertex:vert 
        #pragma target 3.0


3、在subshader里关联properties:

[C#] 纯文本查看 复制代码
float4 _MainTint;  
        sampler2D _MainTex;  
        sampler2D _NormalMap;


4、定义光照函数Unlit:

[C#] 纯文本查看 复制代码
inline half4 LightingUnlit (SurfaceOutput s, fixed3 lightDir, fixed atten)  
        {  
            half4 c = half4(1,1,1,1);  
            c.rgb = s.Albedo;  
            c.a = s.Alpha;  
            return c;  
        } 


这是一个无光照的光照函数,因为我们要用纹理上的光照效果,所以不需要计算光照。

5、定义Input结构体:

[C#] 纯文本查看 复制代码
struct Input {  
            float2 uv_MainTex;  
            float2 uv_NormalMap;  
            float3 tan1;  
            float3 tan2;  
        }; 


6、定义顶点函数:

[C#] 纯文本查看 复制代码
 void vert (inout appdata_full v, out Input o)   
        {  
            UNITY_INITIALIZE_OUTPUT(Input,o);  
            
            TANGENT_SPACE_ROTATION;  
            o.tan1 = mul(rotation, UNITY_MATRIX_IT_MV[0].xyz);  
            o.tan2 = mul(rotation, UNITY_MATRIX_IT_MV[1].xyz);  
        } 


解释:
NITY_INITIALIZE_OUTPUT(Input,o);在HLSLSupport.cginc文件里是这样定义的:

[C#] 纯文本查看 复制代码
#if defined(UNITY_COMPILER_HLSL) || defined(SHADER_API_PSSL) || defined(SHADER_API_GLES3) || defined(SHADER_API_GLCORE)
#define UNITY_INITIALIZE_OUTPUT(type,name) name = (type)0;
#else
#define UNITY_INITIALIZE_OUTPUT(type,name)
#endif


如果是HLSL编译器或某些版本的Shader API,则将变量赋值为0,否则什么都不做。这样编译器就不会报错说变量未初始化。
TANGENT_SPACE_ROTATION;是Unity提供的一个宏,它定义了一个rotation矩阵用于从Object Space变换到Tangent Space。它在UnityCG.cginc里的定义如下:

[C#] 纯文本查看 复制代码
// Declares 3x3 matrix 'rotation', filled with tangent space basis
#define TANGENT_SPACE_ROTATION \
    float3 binormal = cross( normalize(v.normal), normalize(v.tangent.xyz) ) * v.tangent.w; \
    float3x3 rotation = float3x3( v.tangent.xyz, binormal, v.normal ));


binormal是切空间的Y轴,tangent是切空间的X轴,normal是切空间的Z轴。为什么它定义了一个切空间旋转参考:
http://blog.csdn.net/cyxisgreat/article/details/49779513#comments

UNITY_MATRIX_IT_MV是Object Space(or Model Space)变换到View Space(or Eye Space)的矩阵的逆转置矩阵。View Space以摄像机为原点,摄像机朝向为Z轴。[]是取出矩阵的一列,UNITY_MATRIX_IT_MV[0].xyz是说将向量(1,0,0)(即X轴)左乘MV矩阵的逆转置矩阵。UNITY_MATRIX_IT_MV[1].xyz则是向量(0,1,0)(即Y轴)左乘MV矩阵的逆转置矩阵。
顺便科普一下,OpenGL是列向量,变换矩阵应该左乘向量。如果要将法线从Object Space变换到View Space是不能用MV矩阵的,原因参考:
http://www.cnblogs.com/flytrace/p/3379816.html

要将法线从Object Space变换到View Space要用MV矩阵的逆转置矩阵。那么,反过来,如果要将法线从View Space变换到Object Space只要将MV矩阵的逆转置矩阵右乘法线即可。这里的代码可以理解为将View Space的X轴和Y轴变换到了Object Space。变换到了Object Space以后再乘rotation变换到Tangent Space。

7、最后,编写表面处理函数:

[C#] 纯文本查看 复制代码
void surf (Input IN, inout SurfaceOutput o)   
        {  
            float3 normals = UnpackNormal(tex2D(_NormalMap, IN.uv_NormalMap));  
            o.Normal = normals;  
  
            float2 litSphereUV;  
            litSphereUV.x = dot(IN.tan1, o.Normal);  
            litSphereUV.y = dot(IN.tan2, o.Normal);  
          
            half4 c = tex2D (_MainTex, litSphereUV*0.5+0.5);  
            o.Albedo = c.rgb * _MainTint;  
            o.Alpha = c.a;  
        }  


这部分需要的解释不多。在表面处理函数里将法线和tan1、tan2点乘,相当于是把法线投影到了View Space的X轴和Y轴上。后面就是将法线当作UV来采样。乘0.5加0.5是把区间变到[0,1]。

LitSphere有点像把我们能看见的小球的那一面当作一层皮扒下来,然后平铺在纹理上,使纹理上的球严丝合缝地投影在了小球上。效果如下:

psb.jpg

如果我们用纹理本身的UV坐标的话,小球图片是矩形,四周还有黑边,那么采样到小球上会是一个变形的四周有黑边的圆球图案。相当于是把画了个球的纹理贴在球身上。而用法线作UV的话,就把纹理上有球的那部分映射到了我们看得见的球的表面。

我觉得把这理解为把球的表面投影到纹理上更好理解一点。这样要把法线从切空间变换到视空间,每个顶点都要变换,计算量太大,所以换过来,转换到切空间计算会cheap一点。

这个光照模型也叫Matcap(Material Capture)。

这个光照模型只能用于比较圆的物体,比如Sphere和Capsule,Cube是不能用的,因为Cube能看见的法线就只有三个,所以没办法使用这个光照模型。

另一个版本的Matcap
http://wiki.unity3d.com/index.php/MatCap


回复

使用道具 举报

排名
32558
昨日变化
29

0

主题

9

帖子

14

积分

Rank: 1

UID
176596
好友
0
蛮牛币
2
威望
0
注册时间
2016-10-19
在线时间
1 小时
最后登录
2016-10-20
发表于 2016-10-19 01:29:30 | 显示全部楼层
这个很不错

回复

使用道具 举报

排名
23848
昨日变化
25

0

主题

24

帖子

75

积分

Rank: 2Rank: 2

UID
177185
好友
1
蛮牛币
142
威望
0
注册时间
2016-10-21
在线时间
43 小时
最后登录
2017-2-19
发表于 2016-11-2 22:00:40 | 显示全部楼层
LZ很多东西都是搬运的吧

回复 支持 反对

使用道具 举报

排名
32558
昨日变化
29

0

主题

20

帖子

37

积分

Rank: 1

UID
32427
好友
1
蛮牛币
36
威望
0
注册时间
2014-7-4
在线时间
13 小时
最后登录
2017-1-21
发表于 2016-11-12 14:40:52 | 显示全部楼层
感谢大神分享
[发帖际遇]: 一个袋子砸在了 hui007 头上,hui007 赚了 1 蛮牛币. 幸运榜 / 衰神榜

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册帐号

本版积分规则

快速回复 返回顶部 返回列表