【Aladdin Unity3D Shader编程】之二 光照模型(一)
光照模型
光照模型就是一个公式,使用这个公式来计算在某个点的光照效果。
在标准光照模型里面,我们把进入摄像机的光分为下面四个部分:
自发光
类似生活中的萤火虫等自己能够发光
高光反射
类似生活中的镜子,近似认为百分百反射出去
漫反射
类似生活中的光照射到墙壁上、桌子上的反光不会百分百反射出去,各个方向都会反射。
环境光
类似生活中的光照照射在某个物体上,物体漫反射然后反射到其他物体上这些过程的光是环境光。
以上都是模拟生活中的光照效果,并不等同于实际生活中的光照计算,实际生活中的光照会更加复杂。
光照模型中关于漫反射的计算
漫反射计算放在顶点函数里面就是逐顶点光照
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编程】之二 光照模型(一)的更多相关文章
- 【Aladdin Unity3D Shader编程】之三 光照模型(二)
高光反射模型 Specular=直射光*pow(cosθ,高光的参数) θ:是反射光和视野方向的夹角 编写高光反射Shader Shader "AladdinShader/07 Specul ...
- 【Aladdin Unity3D Shader编程】之一 基本入门
OpenGL.DirectX以及GLSL.HLSL.CG OpenGL和DirectX是图像应用编程接口,用于渲染二维或者三维图形. GLSL着色语言是用来在OpenGL中着色编程的语言,有点在于跨平 ...
- 【Aladdin Unity3D Shader编程】之四 贴图纹理
关于纹理贴图介绍 纹理坐标也叫UV坐标,UV坐标都是0~1,并不是我们所理解的像素坐标,相当于是一个百分比. 编写shader映射纹理 将纹理的颜色取代漫反射的颜色 Shader "Alad ...
- 【浅墨Unity3D Shader编程】之二 雪山飞狐篇:Unity的基本Shader框架写法&颜色、光照与材质
本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接:http://blog.csdn.net/poem_qianmo/article/details/40955607 作者:毛星云(浅墨) ...
- 【浅墨Unity3D Shader编程】之一 夏威夷篇:游戏场景的创建 & 第一个Shader的书写
本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接:http://blog.csdn.net/poem_qianmo/article/details/40723789 作者:毛星云(浅墨) ...
- 【浅墨Unity3D Shader编程】之三 光之城堡篇:子着色器、通道与标签的写法 & 纹理混合
本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接:http://hpw123.net/a/C__/kongzhitaichengxu/2014/1117/120.html 作者:毛星云 ...
- 【浅墨Unity3D Shader编程】之中的一个 夏威夷篇:游戏场景的创建 & 第一个Shader的书写
本系列文章由@浅墨_毛星云 出品.转载请注明出处. 文章链接:http://blog.csdn.net/poem_qianmo/article/details/40723789 作者:毛星云(浅墨) ...
- Unity3d 网络编程(二)(Unity3d内建网络各项參数介绍)
这里是全部Unity3d在网络中能用到相关的类及方法.纵观參数功能, Unity3d来写一个手游是不二的选择: RPC 能够传递的參数 int float string NetworkPlayer N ...
- [Unity3D]Shader编程之动态屏幕遮罩
转载 https://blog.csdn.net/u012741077/article/details/78425834 屏幕可视范围跟随目标物体移动,可修改可视范围大小,边缘渐变大小.以及遮罩颜色, ...
随机推荐
- ERwin 正向工程
1.物理模型带字段备注 COMMENT ON 将模型切换至 physical 模式选择 Model ---> Domain Dictionary , 在 tab 标签中,切换至comment 然 ...
- ERwin逻辑模型
1.自动排序 Format>>Preferences>>Layout Entire Diagram CA ERwin
- 梦想CAD控件关于id与handle问题
ID和句柄具有各自的特点: (1) ID:在一个任务中,本次任务中都是独一无二的.在不同的任务中,同一个图形对象的ID可能不同. (2) 句柄:在一个任务中,不能保证每个对象的句柄都唯一,但是在一个图 ...
- linux 下mysql无法启动 mysql.sock
在公司装的一键安装的lnmp环境,启动mysql时候发现mysql.sock不存在, 然后我进行查找 最后在 /usr/local/mysql/bin/mysql_safe 重新启动下 然后启动 ...
- 完善本地搭建的jekyll环境(Windows)
序:上篇文章虽然在本地搭建好了jekyll环境,但是却存在一些问题,如通过jekyll new创建的站点无法正常跑起来.中文编码有问题.这说明之前搭建的环境有不周之处. PS:因之前自己搭建环境时并未 ...
- instance_name,db_name,oracle_sid之间的关系
一]对ORACLE_SID的理解 --------------------------------------------------------------------------------Ora ...
- concepts in Turbulent Flow
Table of Contents 1. Concepts/Glossary 1.1. Turbulent eddy viscosity ,μt 1.2. Turbulent kinetic ener ...
- STM32F103移值FreeRtos笔记
RTOS版本:FreeRTOS_V8.2.2 一.下载FreeRTOS源文件 这个可以在百度上下载,或者在官网上面下载http://www.freertos.org/a00104.html ...
- [bzoj1925][Sdoi2010][地精部落] (序列动态规划)
Description 传说很久以前,大地上居住着一种神秘的生物:地精. 地精喜欢住在连绵不绝的山脉中.具体地说,一座长度为 N 的山脉 H可分 为从左到右的 N 段,每段有一个独一无二的高度 Hi, ...
- spring与quartz整合实现分布式动态创建,删除,改变执行时间定时任务(mysql数据库)
背景:因为在项目中用到了定时任务,当时想到了spring的quartz,写完发现费了很大功夫,光是整合就花了一上午,其中最大的问题就是版本问题,项目中用的是spring3.2.8的版本,查阅发现,3. ...