Unity Shader自定义光照模型
2016-08-14 23:38
483 查看
前几天去一家公司面试,因为简历上写着“能写简单的Shader”,就被问了一个问题:怎么自定义一个光照模型?
直接懵逼了,隐隐约约能联想到的什么漫反射光+镜面反射光+环境光...难道是这个?光照模型就是#pragam surface surf Lambert里面的那个Lambert呗?这不都是写好的吗?还能自定义啊?!本着“程序是严谨的”的心态,宁可说不知道,也不能瞎说。。。
今天有空,抓紧学习一下自定义光照模型...
首先,新建一个SurfaceShader,打开后做如下修改
#pragma surface surf Standard fullforwardshadows
>> #pragma surface surfMyLightingModel
之后,在SubShader块儿中实现这个光照模型:
这个的方法名注意,要前面多了一个“Lighting”,如果直接写“MyLightingModel”是会报错滴...因为找不到,这里具体是怎么做的我也不知道,以后知道了再来补充。
其中lightDir是点到光源的单位向量,atten(attenuation)是衰减系数。如果要用到点到摄像机(观察者)的单位向量,就需要另一个参数:half3 viewDir(因为这个模型是个漫反射模型,就先不考虑观察者角度了)。
dot方法是点乘(点积),在这里求的是入射光线和该点法线的相似度,相似度越高,反射的光线就越多。
关于这个_LightColor0变量,查了一下,比较复杂,是根据当前环境中的各种光源计算出来的...我们只管用就好了。
以上就实现了一个简单的反射的光照模型。
最后来一个漫反射+镜面反射的光照模型,是不是传说中的冯氏反射模型呢?暂且就当做是吧...
最后来点理论知识,关于漫反射和镜面反射的计算方式。
漫反射:
漫反射与镜面反射的主要区别是法线的分布。如果物体完全光滑的话,那么法线完全垂直于平面,例如镜面及锃亮的金属表面。而很多看起来很光滑平整的物体,如纸,桌面,衣服等,实际上,用放大镜仔细观察,就会看到其表面是凹凸不平的。法线并不与肉眼看见的面垂直,而是与实际的面平行。
漫反射:光射到粗糙表面时,表面会把光线向着四面八方反射,所以即使入射线平行,由于各点的法线方向不一致,造成反射光线向不同的方向无规则地反射。这种反射光称为漫反射光。
漫反射的计算
diffuse = Kd x colorLight xmax(N*L,0)
Kd漫反射系数
colorLight 光的颜色
N单位法线向量
L由点指向光源的单位向量
其中N与L点乘,如果结果小于等于0,则漫反射为0
![](https://oscdn.geek-share.com/Uploads/Images/Content/201608/7b7f923035a350a056e39f8e62687602)
镜面反射:
光射到表面光滑平整,法线均匀的物体表面上,这种反射光称为镜面反射光。
![](https://oscdn.geek-share.com/Uploads/Images/Content/201608/132e343152166f1515ca59cf6d60aae6)
Ks 镜面系数
colorLight 光的颜色
N 单位法线向量
L 由点指向光源的单位向量
V 由点指向观察者的单位向量
H(L+V)向量的单位化向量,即normalize(L+V)
shininess镜面强度系数,值越小,高光越分散;值越高,高光越集中。
facing如果N与L的点乘大于0,则facing为1,如果小于等于0,则facing为0
![](https://oscdn.geek-share.com/Uploads/Images/Content/201608/84494b3c021edb12bc58e5b2a0e9b73d)
部分内容参考和引用自风宇冲http://blog.sina.com.cn/s/blog_471132920101dhnv.html
所谓的光照模型(光照方程),就是模型对光线做出的反应。因为材质和表面光滑度的不同,在光线照射到物体表面后,因为对光线的吸收和折射反射等等,最终进入眼睛的光线。
比较经典的一个例子,游戏《半条命》中使用的HalfLambert,修改一下我们的第一个光照模型:
嗯,很简单,想怎么算就怎么算。但是,要做出炫酷的效果,要学的理论知识还有很多很多...
直接懵逼了,隐隐约约能联想到的什么漫反射光+镜面反射光+环境光...难道是这个?光照模型就是#pragam surface surf Lambert里面的那个Lambert呗?这不都是写好的吗?还能自定义啊?!本着“程序是严谨的”的心态,宁可说不知道,也不能瞎说。。。
今天有空,抓紧学习一下自定义光照模型...
首先,新建一个SurfaceShader,打开后做如下修改
#pragma surface surf Standard fullforwardshadows
>> #pragma surface surfMyLightingModel
之后,在SubShader块儿中实现这个光照模型:
inline float4 LightingMyLightingModel(SurfaceOutput s, fixed3 lightDir, fixed atten) { float difLight = max(0, dot (s.Normal, lightDir)); float4 col; col.rgb = s.Albedo * _LightColor0.rgb * (difLight * atten * 2); col.a = s.Alpha; return col; }</span>
这个的方法名注意,要前面多了一个“Lighting”,如果直接写“MyLightingModel”是会报错滴...因为找不到,这里具体是怎么做的我也不知道,以后知道了再来补充。
其中lightDir是点到光源的单位向量,atten(attenuation)是衰减系数。如果要用到点到摄像机(观察者)的单位向量,就需要另一个参数:half3 viewDir(因为这个模型是个漫反射模型,就先不考虑观察者角度了)。
dot方法是点乘(点积),在这里求的是入射光线和该点法线的相似度,相似度越高,反射的光线就越多。
关于这个_LightColor0变量,查了一下,比较复杂,是根据当前环境中的各种光源计算出来的...我们只管用就好了。
以上就实现了一个简单的反射的光照模型。
最后来一个漫反射+镜面反射的光照模型,是不是传说中的冯氏反射模型呢?暂且就当做是吧...
float4 LightingPhongModel(SurfaceOutput s, float3 lightDir,half3 viewDir, half atten) { float4 col; float diffuseF = max(0,dot(s.Normal,lightDir)); float specF; float3 H = normalize(lightDir+viewDir); float specBase = max(0,dot(s.Normal,H)); specF = pow(specBase,8); col.rgb = s.Albedo * _LightColor0 * diffuseF *atten + _LightColor0*specF; col.a = s.Alpha; return col; }</span>
float3 H = normalize(lightDir+viewDir); float specBase = max(0,dot(s.Normal,H)); specF = pow(specBase,8);</span>这三句是用来计算镜面反射的,镜面反射必然与观察者的位置有关,所以这个方法里用到了这个viewDir参数。
最后来点理论知识,关于漫反射和镜面反射的计算方式。
漫反射:
漫反射与镜面反射的主要区别是法线的分布。如果物体完全光滑的话,那么法线完全垂直于平面,例如镜面及锃亮的金属表面。而很多看起来很光滑平整的物体,如纸,桌面,衣服等,实际上,用放大镜仔细观察,就会看到其表面是凹凸不平的。法线并不与肉眼看见的面垂直,而是与实际的面平行。
漫反射:光射到粗糙表面时,表面会把光线向着四面八方反射,所以即使入射线平行,由于各点的法线方向不一致,造成反射光线向不同的方向无规则地反射。这种反射光称为漫反射光。
漫反射的计算
diffuse = Kd x colorLight xmax(N*L,0)
Kd漫反射系数
colorLight 光的颜色
N单位法线向量
L由点指向光源的单位向量
其中N与L点乘,如果结果小于等于0,则漫反射为0
镜面反射:
光射到表面光滑平整,法线均匀的物体表面上,这种反射光称为镜面反射光。
Ks 镜面系数
colorLight 光的颜色
N 单位法线向量
L 由点指向光源的单位向量
V 由点指向观察者的单位向量
H(L+V)向量的单位化向量,即normalize(L+V)
shininess镜面强度系数,值越小,高光越分散;值越高,高光越集中。
facing如果N与L的点乘大于0,则facing为1,如果小于等于0,则facing为0
部分内容参考和引用自风宇冲http://blog.sina.com.cn/s/blog_471132920101dhnv.html
所谓的光照模型(光照方程),就是模型对光线做出的反应。因为材质和表面光滑度的不同,在光线照射到物体表面后,因为对光线的吸收和折射反射等等,最终进入眼睛的光线。
比较经典的一个例子,游戏《半条命》中使用的HalfLambert,修改一下我们的第一个光照模型:
float difLight = max(0, dot (s.Normal, lightDir)); float hLambert = difLight * 0.5 + 0.5; float4 col; col.rgb = s.Albedo * _LightColor0.rgb * (hLambert * atten * 2); col.a = s.Alpha; return col;
嗯,很简单,想怎么算就怎么算。但是,要做出炫酷的效果,要学的理论知识还有很多很多...
相关文章推荐
- Unity Shader自定义光照模型
- Unity shader教程-第五课:自定义光照模型之Half Lambert模型
- Unity Shader-兰伯特光照模型与Diffuse Shader
- [UnityShaderCookbook 读书笔记] [02] 光照模型
- Unity3D ShaderLab 自定义光照模型
- Unity3D for VR 学习(9): Unity Shader 光照模型 (illumination model)
- [Unity基础]从“漫反射光照模型”了解Unity Shader渲染原理
- 【Unity Shader】 Lambert(兰伯特)光照模型
- Unity Shader 学习笔记(十二)漫反射卷积光照模型
- Unity Shader渲染顺序 坐标系 和光照模型
- 与Intel的古老显卡的战斗----Ward光照模型的高光部分的Unity Shader的编写
- [Unity Shader]光照模型对物体的假设
- Unity Shaders and Effects Cookbook (1-2)创建自定义漫反射光照模型
- Unity3D for VR 学习(9): Unity Shader 光照模型 (illumination model)
- unity中使用自定义shader进行光照贴图烘培无法出现透明度的坑爹问题
- <unity shader入门精要> - unity shader 中实现漫反射光照模型
- Unity实现标准光照模型的Shader代码
- unity shader 入门之路(五)标准光照模型理论
- [Unity Shader]光照模型对物体的假设
- UnityShader初级篇——实现逐顶点高光反射光照模型