【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 ...
随机推荐
- c#.net 调用BouncyCastle生成PEM格式的私钥和公钥
RsaKeyPairGenerator r = new RsaKeyPairGenerator(); r.Init()); AsymmetricCipherKeyPair keys = r.Gener ...
- 一个自己做的easyui datagird扩展
var a; $(function () { $("body").bind("contextmenu", function () { return false; ...
- JavaScript权威指南 第二章 词法结构
这章主要把保留字说一下 JavaScript 把一些标识符拿出来用做自己的关键字.因此,就不能再在程序中把这些关键字用做标识符了: break delete function return typeo ...
- Spark配置参数调优
1.配置多个executor 在项目中,由于数据量为几百万甚至千万级别,如果一个executor装载的对象过多,会导致GC很慢.项目中,我们使一个worker节点执行app时启动多个executor, ...
- OAF_EO系列4 - Create详解和实现(案例)
2014-06-02 Created By BaoXinjian
- HTML格式与布局
一.position:fixed 锁定位置(相对于浏览器的位置),例如有些网站的右下角的弹出窗口. <head> <title>123</title> <st ...
- phpmyadmin数据库导入出错
SQL 查询: -- phpMyAdmin SQL Dump-- version 3.5.1-- http://www.phpmyadmin.net---- 主机: localhost-- 生成日期: ...
- shell中实现自动登录(bash环境脚本中)
自己的脚本: #!/bin/bash expect -c " set timeout 3600; spawn su -; expect *assword:*; ...
- REST架构实质(转)
REST(Representational State Transfer) 曾经被误解为只是CRUD(增删改查),从这个层面上,好像REST只是和RPC一个层面的东西,没有什么了不起,其实这些都是对R ...
- 编译器错误消息: CS0234: 命名空间“Purple”中不存在类型或命名空间名称“Model”(是否缺少程序集引用?)
编译错误 “/storeimg”应用程序中的服务器错误. 编译错误 说明: 在编译向该请求提供服务所需资源的过程中出现错误.请检查下列特定错误详细信息并适当地修改源代码. 编译器错误消息: CS023 ...