光照模型

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

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

  • 自发光

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

  • 高光反射

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

  • 漫反射

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

  • 环境光

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

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

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

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

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. QT 杂记

    1.按F4切换designer和Edit视图. 2.加载同目录下的js文件: import "XXX.js" as MyJs //首字母一定要大写 3.qml 引用的js中对象.字 ...

  2. Jmeter在Windows上分布式压测遇到的坑

    1.五星坑:远程启动测试,响应数据为空. controller运行jmeter脚本后,GUI无性能数据返回. agent的jmeter server显示连接后立即结束.看似执行实则响应数据为空. 出现 ...

  3. RocketMQ学习笔记(15)----RocketMQ的消息模式

    在前面学习ActiveMQ时,看到ActiveMQ可以是队列消息模式,也可以是订阅发布模式. 同样,在RocketMQ中,也存在两种消息模式,即是集群消费模式和广播消费模式. 1. 集群消费模式 跟A ...

  4. MxCAD5.2 20180726更新

    下载地址: http://www.mxdraw.com/ndetail_105.html 1. 增加属性匹配功能 2. 增加List命令 3. 增加CAD图纸审图批注功能 4. 环形阵列功能

  5. nginx做反向代理配置文件的例子

    worker_processes ; error_log logs/error.log; #error_log logs/error.log notice; #error_log logs/error ...

  6. C语言编辑编译及集成开发环境

    C语言编辑编译及集成开发环境 编辑器 在不同的操作系统上使用不同的编辑器,保存源代码文件时,文件名应指出程序的功能扩展名应为.c. 编译器 编译器把源代码编译成机器语言的二进制指令即目标代码生成目标文 ...

  7. oracle数据库子查询的结果需要使用多次解决办法

    with c as (select a.trandt,sum(a.tranam) tranam from tran a group by a.trandt )--将子查询抽取出来,以后可以直接用.该方 ...

  8. 牛客多校Round 9

    Solved:1 rank:112 E. Music Game 题解说有个非简化的原题 bzoj4318 #include <bits/stdc++.h> using namespace ...

  9. vue中websoket的使用

    首先安装npm install --save  websocket-heartbeat-js@^1.0.7 在main.js中  引入并挂载全局方法 import WebsocketHeartbeat ...

  10. Java排序算法全

    目录 Java排序算法代码 零. 排序基类 一. 选择排序 二. 插入排序 三. 希尔排序 四. 归并排序 1. 自顶向下 2. 自底向上 五. 快速排序 1. 基本版 2. 双路切分版 3. 三路切 ...