【Unity Shaders】学习笔记——SurfaceShader(十一)光照模型
【Unity Shaders】学习笔记——SurfaceShader(十一)光照模型
转载请注明出处:http://www.cnblogs.com/-867259206/p/5664792.html
如果你想从零开始学习Unity Shader,那么你可以看看本系列的文章入门,你只需要稍微有点编程的概念就可以。
水平有限,难免有谬误之处,望指出。
LitSphere(Matcap)
发光球体光照模型就是将发光球体的纹理映射在球体上,来实现光照效果。这可以创造一些效果细腻的发光球体效果,但是它不受光照影响,改变光照的方向,球体的光照效果不变。如果要在固定视角的场景里制作细腻的球体光照,这会是一个不错的选择。
准备小球纹理贴图:



定义Properties:
Properties {
_MainTint ("Diffuse Tint", Color) = (1,1,1,1)
_MainTex ("Base (RGB)", 2D) = "white" {}
_NormalMap ("Normal Map", 2D) = "bump" {}
}
编写预编译命令:
#pragma surface surf Unlit vertex:vert
#pragma target 3.0
在subshader里关联properties:
float4 _MainTint;
sampler2D _MainTex;
sampler2D _NormalMap;
定义光照函数Unlit:
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;
}
这是一个无光照的光照函数,因为我们要用纹理上的光照效果,所以不需要计算光照。
定义Input结构体:
struct Input {
float2 uv_MainTex;
float2 uv_NormalMap;
float3 tan1;
float3 tan2;
};
定义顶点函数:
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文件里是这样定义的:
#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里的定义如下:
// 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轴。为什么它定义了一个切空间旋转看这篇。
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矩阵的,原因看这篇博文。要将法线从Object Space变换到View Space要用MV矩阵的逆转置矩阵。那么,反过来,如果要将法线从View Space变换到Object Space只要将MV矩阵的逆转置矩阵右乘法线即可。这里的代码可以理解为将View Space的X轴和Y轴变换到了Object Space。变换到了Object Space以后再乘rotation变换到Tangent Space。
最后,编写表面处理函数:
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有点像把我们能看见的小球的那一面当作一层皮扒下来,然后平铺在纹理上,使纹理上的球严丝合缝地投影在了小球上。效果如下:
如果我们用纹理本身的UV坐标的话,小球图片是矩形,四周还有黑边,那么采样到小球上会是一个变形的四周有黑边的圆球图案。相当于是把画了个球的纹理贴在球身上。而用法线作UV的话,就把纹理上有球的那部分映射到了我们看得见的球的表面。
我觉得把这理解为把球的表面投影到纹理上更好理解一点。这样要把法线从切空间变换到视空间,每个顶点都要变换,计算量太大,所以换过来,转换到切空间计算会cheap一点。
这个光照模型也叫Matcap(Material Capture)。
这个光照模型只能用于比较圆的物体,比如Sphere和Capsule,Cube是不能用的,因为Cube能看见的法线就只有三个,所以没办法使用这个光照模型。
另一个版本的Matcap
【Unity Shaders】学习笔记——SurfaceShader(十一)光照模型的更多相关文章
- 【Unity Shaders】学习笔记——SurfaceShader(十)镜面反射
[Unity Shaders]学习笔记——SurfaceShader(十)镜面反射 如果你想从零开始学习Unity Shader,那么你可以看看本系列的文章入门,你只需要稍微有点编程的概念就可以. 水 ...
- 【Unity Shaders】学习笔记——SurfaceShader(四)用纹理改善漫反射
[Unity Shaders]学习笔记——SurfaceShader(四)用纹理改善漫反射 转载请注明出处:http://www.cnblogs.com/-867259206/p/5603368.ht ...
- 【Unity Shaders】学习笔记——SurfaceShader(三)BasicDiffuse和HalfLambert
[Unity Shaders]学习笔记——SurfaceShader(三)BasicDiffuse和HalfLambert 转载请注明出处:http://www.cnblogs.com/-867259 ...
- 【Unity Shaders】学习笔记——SurfaceShader(一)认识结构
[Unity Shaders]学习笔记——SurfaceShader(一)认识结构 转载请注明出处:http://www.cnblogs.com/-867259206/p/5595747.html 写 ...
- 【Unity Shaders】学习笔记——SurfaceShader(九)Cubemap
[Unity Shaders]学习笔记——SurfaceShader(九)Cubemap 如果你想从零开始学习Unity Shader,那么你可以看看本系列的文章入门,你只需要稍微有点编程的概念就可以 ...
- 【Unity Shaders】学习笔记——SurfaceShader(八)生成立方图
[Unity Shaders]学习笔记——SurfaceShader(八)生成立方图 转载请注明出处:http://www.cnblogs.com/-867259206/p/5630261.html ...
- 【Unity Shaders】学习笔记——SurfaceShader(七)法线贴图
[Unity Shaders]学习笔记——SurfaceShader(七)法线贴图 转载请注明出处:http://www.cnblogs.com/-867259206/p/5627565.html 写 ...
- 【Unity Shaders】学习笔记——SurfaceShader(六)混合纹理
[Unity Shaders]学习笔记——SurfaceShader(六)混合纹理 转载请注明出处:http://www.cnblogs.com/-867259206/p/5619810.html 写 ...
- 【Unity Shaders】学习笔记——SurfaceShader(五)让纹理动起来
[Unity Shaders]学习笔记——SurfaceShader(五)让纹理动起来 转载请注明出处:http://www.cnblogs.com/-867259206/p/5611222.html ...
随机推荐
- 【转】java 自动装箱与拆箱
java 自动装箱与拆箱 这个是jdk1.5以后才引入的新的内容,作为秉承发表是最好的记忆,毅然决定还是用一篇博客来代替我的记忆: java语言规范中说道:在许多情况下包装与解包装是由编译器自行完成的 ...
- gcc中动态库和静态库的链接顺序
so文件:动态库a文件: 静态库exe文件:可执行程序(linux下以文件属性来标示是否是可执行文件,与后缀名无关) 经过自己写的一些测试程序,大致了解了下gcc中链接顺序问题,总结出以下几点:1,动 ...
- ie浏览器的渲染原理
IE下载或者渲染顺序大致如下: IE下载的顺序是从上到下,渲染的顺序也是从上到下,下载和渲染是同时进行的. 在渲染到页面的某一部分时,其上面的所有部分都已经下载完成(但并不是说所有相关联的元素都已经下 ...
- 2. scala中的数组
一. 数组声明 定长数组 scala> new Array[String](5) res1: Array[String] = Array(null, null, null, null, null ...
- DBA_Oracle DBA常用表汇总(概念)
2014-06-20 Created By BaoXinjian
- Report_矩阵报表的实现(案例)
2014-05-31 Created By BaoXinjian
- HTTP协议与HTTPS的区别
permike 原文 HTTP协议与HTTPS的区别 HTTP协议 HTTP协议主要应用是在服务器和客户端之间,客户端接受超文本. HTTP是在七层网络模型中的应用层的协议,由发送请求和接受响应构成, ...
- poj 2567 Code the Tree 河南第七届省赛
Code the Tree Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 2350 Accepted: 906 Desc ...
- M2M协议
1, M2M协议 M2M是Machine-to-Machine/Man的简称,是一种以机器终端智能交互为核心的.网络化的应用与服务.M2M协议规定了人机和机器之间交互需要遵从的通信协议.随着科学技术的 ...
- jQuery图片延迟加载插件jQuery.lazyload
插件描述:jQuery图片延迟加载插件jQuery.lazyload,使用延迟加载在可提高网页下载速度.在某些情况下,它也能帮助减轻服务器负载. 使用方法 引用jquery和jquery.lazy ...