光照模型

光照模型就是一个公式,使用这个公式来计算在某个点的光照效果。

在标准光照模型里面,我们把进入摄像机的光分为下面四个部分:

  • 自发光

    类似生活中的萤火虫等自己能够发光

  • 高光反射

    类似生活中的镜子,近似认为百分百反射出去

  • 漫反射

    类似生活中的光照射到墙壁上、桌子上的反光不会百分百反射出去,各个方向都会反射。

  • 环境光

    类似生活中的光照照射在某个物体上,物体漫反射然后反射到其他物体上这些过程的光是环境光。

以上都是模拟生活中的光照效果,并不等同于实际生活中的光照计算,实际生活中的光照会更加复杂。

光照模型中关于漫反射的计算

漫反射计算放在顶点函数里面就是逐顶点光照

Disffuse = 直射光颜色*max(0,cosθ) (θ是法线跟光照的夹角) 如果夹角小于0的话就是背光面就直接取黑色

理论知识:

  • 向量点乘(结果值)

    a*b=|a||b|cosθ

  • 向量叉乘(结果是向量)

    a*b=c c的一个向量,值是|a||b|sinθ

编写漫反射Shader

在Pass块里添加Tags{"LightMode"="ForwardBase"}和#include "Lighting.cginc" //引用一些写好的程序块 会包含一些获取光照的信息

只有定义了正确的LightMode才能得到一些Unity的内置光照变量。

  • normalize() 将一个向量单位化
  • max()用来取得函数中最大的一个
  • dot()用来取得两个向量的点积
  • _WorldSpaceLightPos0取得平行光的位置
  • _LightColor0取得平行光的颜色

    UNITY_MATRIX_MVP 这个矩阵是将模型空间转换到剪裁空间
  • _World2Object这个矩阵用来将一个方向从时间空间转换到模型空间
  • UNITY_LIGHTMODEL_AMBIENT 用来获取环境光
Shader "AladdinShader/04 Diffuse Tertex Shader"
{
Properties
{ }
SubShader {
Pass
{
Tags{"LightMode"="ForwardBase"} CGPROGRAM
#include "Lighting.cginc" //引用一些写好的程序块 会包含一些获取光照的信息
//_LightColor0 取得第一个直射光的颜色
//_WorldSpaceLightPos0 #pragma vertex vert
#pragma fragment frag struct a2v
{
float4 vertex:POSITION;
float3 normal:NORMAL; //模型空间下法线
}; struct v2f
{
float4 position:SV_POSITION;
fixed3 color:COLOR;
};
v2f vert(a2v v)
{
v2f f;
f.position = mul(UNITY_MATRIX_MVP, v.vertex); //获得世界空间的单位法线向量
fixed3 normalDir = normalize(mul(v.normal, (float3x3)unity_WorldToObject)); //从模型空间转到世界空间 float3x3 将一个4*4的矩阵强转成3*3的矩阵 //世界空间下的光照位置
fixed3 lightDir = _WorldSpaceLightPos0.xyz; //对于每一个点来说每一个光的位置就是光的方向(针对平行光) //取得漫反射的颜色
fixed3 diffuse = _LightColor0.rgb * max(0, dot(normalDir, lightDir));//取得第一个直射光的颜色
f.color = diffuse;
return f;
} fixed4 frag(v2f f):SV_Target
{
return fixed4(f.color,1);
} ENDCG
}
}
FallBack "VertexLit"
}

效果:

没有写反射光照之前的效果,红色是均匀的



写了光照效果之后,会看到正对光照地方很亮,背对光照的地方就很暗甚至黑色。



现在是逐顶点光照,顶点的数量是有限的,如果将计算放在片元函数里面计算效果会更好,但计算量也会更大,那就叫逐片元光照。

给物体自身添加颜色和环境光共同控制

上面物体的颜色只是受环境光的颜色影响,但实际生活中我们看到的物体的颜色是环境光和自身颜色混合的效果。我们在上面的例子的基础上,添加上物体本身的颜色:

给物体添加颜色属性然后*环境光

Shader "AladdinShader/04 Diffuse Tertex Shader"
{
Properties
{
_Diffuse("Diffuse",Color)=(1,1,1,1) //添加自身的颜色
}
SubShader {
Pass
{
Tags{"LightMode"="ForwardBase"} CGPROGRAM
#include "Lighting.cginc" //引用一些写好的程序块 会包含一些获取光照的信息
//_LightColor0 取得第一个直射光的颜色
//_WorldSpaceLightPos0 #pragma vertex vert
#pragma fragment frag fixed4 _Diffuse; struct a2v
{
float4 vertex:POSITION;
float3 normal:NORMAL; //模型空间下法线
}; struct v2f
{
float4 position:SV_POSITION;
fixed3 color:COLOR;
};
v2f vert(a2v v)
{
v2f f;
f.position = mul(UNITY_MATRIX_MVP, v.vertex); fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.rgb;//获得系统内置的环境光 //获得世界空间的单位法线向量
fixed3 normalDir = normalize(mul(v.normal, (float3x3)unity_WorldToObject)); //从模型空间转到世界空间 float3x3 将一个4*4的矩阵强转成3*3的矩阵 //世界空间下的光照位置
fixed3 lightDir = _WorldSpaceLightPos0.xyz; //对于每一个点来说每一个光的位置就是光的方向(针对平行光) //取得漫反射的颜色
fixed3 diffuse = _LightColor0.rgb * max(0, dot(normalDir, lightDir)) * _Diffuse.rgb;//取得第一个直射光的颜色 颜色融合
f.color = diffuse + ambient; //颜色增加 增强
return f;
} fixed4 frag(v2f f):SV_Target
{
return fixed4(f.color,1);
} ENDCG
}
}
FallBack "VertexLit"
}

效果:



这样直射光设置成白色,颜色本身设置成绿色,并且在面板中调整颜色,物体就显示成这种颜色。颜色融合一般是颜色的改变,颜色相加是强度增强。

环境光设置:Window->Lighting->Ambient Source->Color 一般不建议很强的环境光

逐像素光照

Shader "AladdinShader/05 Diffuse fragment Shader"
{
Properties
{
_Diffuse("Diffuse",Color)=(1,1,1,1) //添加自身的颜色
}
SubShader {
Pass
{
Tags{"LightMode"="ForwardBase"} CGPROGRAM
#include "Lighting.cginc" //引用一些写好的程序块 会包含一些获取光照的信息
//_LightColor0 取得第一个直射光的颜色
//_WorldSpaceLightPos0 #pragma vertex vert
#pragma fragment frag fixed4 _Diffuse; struct a2v
{
float4 vertex:POSITION;
float3 normal:NORMAL; //模型空间下法线
}; struct v2f
{
float4 position:SV_POSITION;
fixed3 worldNormalDir:COLOR0;
};
v2f vert(a2v v)
{
v2f f;
f.position = mul(UNITY_MATRIX_MVP, v.vertex);
f.worldNormalDir = mul(v.normal, (float3x3)unity_WorldToObject);
return f;
} fixed4 frag(v2f f):SV_Target
{
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.rgb;//获得系统内置的环境光 //获得世界空间的单位法线向量
fixed3 normalDir = normalize(f.worldNormalDir); //从模型空间转到世界空间 float3x3 将一个4*4的矩阵强转成3*3的矩阵 //世界空间下的光照位置
fixed3 lightDir = _WorldSpaceLightPos0.xyz; //对于每一个点来说每一个光的位置就是光的方向(针对平行光) //取得漫反射的颜色
fixed3 diffuse = _LightColor0.rgb * max(0, dot(normalDir, lightDir)) * _Diffuse.rgb;//取得第一个直射光的颜色 颜色融合
fixed3 tempColor = diffuse + ambient; //颜色增加 增强
return fixed4(tempColor,1);
} ENDCG
}
}
FallBack "VertexLit"
}

效果图:



一个是逐顶点光照,一个是逐像素光照,自己看还是能看出区别的。逐像素光照会更消耗性能一些,如果不需要很高的精度的话就可以用逐顶点光照代替。

半兰伯特光照模型

模型表面的明亮度直接取决于光线向量(light vector)和表面法线(normal)两个向量将夹角的余弦值。

如果漫反射光强设置为Diffuse,入射光光强为I,光方向和法线夹角为θ,那么兰伯特光照模型可以用下面的公式表示:Diffuse = I * cosθ。

兰伯特光照模型 模型背面全都是黑色都看不清楚

为了解决这个问题,改造一些兰伯特光照模型的公式,让背光部分也随着光照强度改变而改变。

半兰伯特光照模型:

为了解决兰伯特模型背光面全都是黑的看不清楚的问题。

Diffuse=直射光颜色 * (cosθ * 0.5 + 0.5)

Shader修改

Shader "AladdinShader/06 Diffuse fragment Half Lanbote Shader"
{
Properties
{
_Diffuse("Diffuse",Color)=(1,1,1,1) //添加自身的颜色
}
SubShader {
Pass
{
Tags{"LightMode"="ForwardBase"} CGPROGRAM
#include "Lighting.cginc" //引用一些写好的程序块 会包含一些获取光照的信息
//_LightColor0 取得第一个直射光的颜色
//_WorldSpaceLightPos0 #pragma vertex vert
#pragma fragment frag fixed4 _Diffuse; struct a2v
{
float4 vertex:POSITION;
float3 normal:NORMAL; //模型空间下法线
}; struct v2f
{
float4 position:SV_POSITION;
fixed3 worldNormalDir:COLOR0;
};
v2f vert(a2v v)
{
v2f f;
f.position = mul(UNITY_MATRIX_MVP, v.vertex);
f.worldNormalDir = mul(v.normal, (float3x3)unity_WorldToObject);
return f;
} fixed4 frag(v2f f):SV_Target
{
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.rgb;//获得系统内置的环境光 //获得世界空间的单位法线向量
fixed3 normalDir = normalize(f.worldNormalDir); //从模型空间转到世界空间 float3x3 将一个4*4的矩阵强转成3*3的矩阵 //世界空间下的光照位置
fixed3 lightDir = _WorldSpaceLightPos0.xyz; //对于每一个点来说每一个光的位置就是光的方向(针对平行光) float halfLambert = dot(normalDir, lightDir) * 0.5 + 0.5; //半兰伯特光照模型
//取得漫反射的颜色
fixed3 diffuse = _LightColor0.rgb * halfLambert * _Diffuse.rgb;//取得第一个直射光的颜色 颜色融合
fixed3 tempColor = diffuse + ambient; //颜色增加 增强
return fixed4(tempColor,1);
} ENDCG
}
}
FallBack "VertexLit"
}



会明显的感觉模型亮度变亮了,而且背面也不会纯黑了也会渐变,而且正面颜色也会鲜明一些,这样整体效果会更好一些。

Shader学习交流群:

316977780

【Aladdin Unity3D Shader编程】之二 光照模型(一)的更多相关文章

  1. 【Aladdin Unity3D Shader编程】之三 光照模型(二)

    高光反射模型 Specular=直射光*pow(cosθ,高光的参数) θ:是反射光和视野方向的夹角 编写高光反射Shader Shader "AladdinShader/07 Specul ...

  2. 【Aladdin Unity3D Shader编程】之一 基本入门

    OpenGL.DirectX以及GLSL.HLSL.CG OpenGL和DirectX是图像应用编程接口,用于渲染二维或者三维图形. GLSL着色语言是用来在OpenGL中着色编程的语言,有点在于跨平 ...

  3. 【Aladdin Unity3D Shader编程】之四 贴图纹理

    关于纹理贴图介绍 纹理坐标也叫UV坐标,UV坐标都是0~1,并不是我们所理解的像素坐标,相当于是一个百分比. 编写shader映射纹理 将纹理的颜色取代漫反射的颜色 Shader "Alad ...

  4. 【浅墨Unity3D Shader编程】之二 雪山飞狐篇:Unity的基本Shader框架写法&颜色、光照与材质

    本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接:http://blog.csdn.net/poem_qianmo/article/details/40955607 作者:毛星云(浅墨)  ...

  5. 【浅墨Unity3D Shader编程】之一 夏威夷篇:游戏场景的创建 & 第一个Shader的书写

    本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接:http://blog.csdn.net/poem_qianmo/article/details/40723789 作者:毛星云(浅墨)  ...

  6. 【浅墨Unity3D Shader编程】之三 光之城堡篇:子着色器、通道与标签的写法 & 纹理混合

    本系列文章由@浅墨_毛星云 出品,转载请注明出处.   文章链接:http://hpw123.net/a/C__/kongzhitaichengxu/2014/1117/120.html 作者:毛星云 ...

  7. 【浅墨Unity3D Shader编程】之中的一个 夏威夷篇:游戏场景的创建 & 第一个Shader的书写

    本系列文章由@浅墨_毛星云 出品.转载请注明出处. 文章链接:http://blog.csdn.net/poem_qianmo/article/details/40723789 作者:毛星云(浅墨)  ...

  8. Unity3d 网络编程(二)(Unity3d内建网络各项參数介绍)

    这里是全部Unity3d在网络中能用到相关的类及方法.纵观參数功能, Unity3d来写一个手游是不二的选择: RPC 能够传递的參数 int float string NetworkPlayer N ...

  9. [Unity3D]Shader编程之动态屏幕遮罩

    转载 https://blog.csdn.net/u012741077/article/details/78425834 屏幕可视范围跟随目标物体移动,可修改可视范围大小,边缘渐变大小.以及遮罩颜色, ...

随机推荐

  1. 并发编程学习笔记(6)----公平锁和ReentrantReadWriteLock使用及原理

    (一)公平锁 1.什么是公平锁? 公平锁指的是在某个线程释放锁之后,等待的线程获取锁的策略是以请求获取锁的时间为标准的,即使先请求获取锁的线程先拿到锁. 2.在java中的实现? 在java的并发包中 ...

  2. Linux终端常用快捷操作

    命令或文件名自动补全:在输入命令或文件名的前几个字母后,按Tab键,系统会自动补全或提示补全 上下箭头:使用上下箭头可以回溯之前的命令,增加命令的重用,减少输入工作量 !加之前输入过的命令的前几个字母 ...

  3. 第三节:执行一些EF的增删改查

    针对两表操作 一丶增加 #region 05-增加操作 /// <summary> /// 05-增加操作 /// </summary> /// <param name= ...

  4. 字符串、散列--P1598 垂直柱状图

    题目描述 写一个程序从输入文件中去读取四行大写字母(全都是大写的,每行不超过100个字符),然后用柱状图输出每个字符在输入文件中出现的次数.严格地按照输出样例来安排你的输出格式. 输入输出格式 输入格 ...

  5. [USACO] 奶牛混合起来 Mixed Up Cows

    题目描述 Each of Farmer John's N (4 <= N <= 16) cows has a unique serial number S_i (1 <= S_i & ...

  6. 腾讯云,搭建Git服务器

    下载安装 git 任务时间:5min ~ 10min Git 是一款免费.开源的分布式版本控制系统,用于敏捷高效地处理任何或小或大的项目. 此实验以 CentOS 7.2 x64 的系统为环境,搭建 ...

  7. codechef营养题 第二弹

    第二弾が始まる! codechef problems 第二弹 一.Backup Functions 题面 One unavoidable problem with running a restaura ...

  8. FJoi2017 1月21日模拟赛 comparison(平衡树+thita重构)

    题目大意: 经黄学长指出,此题原题出自2014湖北省队互测 没有人的算术 规定集合由二元组(A,B)构成,A.B同时也是两个这样的集合,即A.B本身也是二元组 规定二元组S为严格最小集合,S=(S,S ...

  9. Spring核心技术(四)——Spring的依赖及其注入(续二)

    前面两篇文章描述了IoC容器中依赖的概念,包括依赖注入以及注入细节配置.本文将继续描述玩全部的依赖信息. 使用 depends-on 如果一个Bean是另一个Bean的依赖的话,通常来说这个Bean也 ...

  10. 第2章 取得大家的支持 录播感悟(意外的Sprint)

    关于<取得大家的支持>这个故事我看了三遍,做了计划,做了时间轴,因为之前有过第1章<知易行难>的沟通和磨合后,相信会顺利很多吧!可是却是意外不断的发生: 1.本人车钥匙掉停车场 ...