光照模型

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

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

  • 自发光

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

  • 高光反射

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

  • 漫反射

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

  • 环境光

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

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

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

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

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. 删除链表中重复的结点_java

    package algorithms; /* public class ListNode { int val; ListNode next = null; ListNode(int val) { th ...

  2. ES 提案的各状态

    JavaScrpit,亦即 ECMAScript,新功能的演进是由一个叫 TC39 这么个组织在统筹协调和推进的. 一般新特性会由社区先提案,被采纳后开始进入下一流程.一个提案到最终落地到成为标准,需 ...

  3. maven入门链接

    http://www.cnblogs.com/now-fighting/p/4857625.html

  4. PHP+Python,轻量维护超轻松

    window下安装Python 直接去Python官网下载msi安装程序安装即可(选择自定义安装才能修改程序安装路径哦) widows下Python的数据库访问模块PyMysql的安装 1.open ...

  5. 利用 Python 批量修改文件名

    开发的第一步,首先得熟悉脚本中使用的模块函数,废话不多说,开干! 1 函数介绍 1.1 os 模块 (1)os.lisdir() >>> import os >>> ...

  6. python爬虫21 | 对于b站这样的滑动验证码,不好意思,照样自动识别

    今天 要来说说滑动验证码了 大家应该都很熟悉 点击滑块然后移动到图片缺口进行验证 现在越来越多的网站使用这样的验证方式 为的是增加验证码识别的难度 那么 对于这种验证码 应该怎么破呢 接下来就是 学习 ...

  7. swing之单选框和复选框

    import java.awt.Container; import java.awt.GridLayout; import javax.swing.*; public class num_1v ext ...

  8. stall and flow separation on airfoil or blade

    stall stall and flow separation Table of Contents 1. Stall and flow separation 1.1. Separation of Bo ...

  9. 【Codeforces 246D】Colorful Graph

    [链接] 我是链接,点我呀:) [题意] 让你找到所有和x颜色的点中,和该颜色的点颜色不同的相邻的点的个数(重复颜色算一次) 求出哪种颜色的所要求的点的数量最多. [题解] 对于每一条边只会被查到两次 ...

  10. selectByExampleWithBLOBs-----搜索结果包含大字段类型----搜索结果包含大字段类型

    http://www.jb51.net/article/121482.htm mybatis generator 使用方法教程(生成带注释的实体类)