当前位置:网站首页>Unity 的基础光照
Unity 的基础光照
2022-07-27 20:11:00 【YF云飞】
前言
光学中,我们是用辐射度来量化光。
光照按照不同的散射方向分为两种形式:漫反射(diffuse)和高光反射(specular)。
高光反射描述物体是如何反射光线的,漫反射则表示有多少光线会被折射、吸收和散射出表面。根据入射光线的数量和方向,我们可以计算出射光线的数量和方向,通常使用出射度描述它。辐射度和出射度之间是线性关系的,它们之间的比值就是材质的漫反射和高光反射属性。
接下来将会介绍Unity内的两种光照方式实现的原理以及代码实现:
内容
BRDF 模型
早期的游戏引擎一般只有一个光照模型,BRDF 模型,即标准光照模型(Bidirectional Reflectance Distribution Function),又称 Phong 模型。
它的基本方法是,把进入到摄像机内的光线分为 4 部分,每部分使用一种方法来计算它的贡献度。
- 自发光 描述当给定一个方向时,一个表面本身会向该方向发射多少辐射量。注意,如果没有使用全局光照,这些自发光的表面并不会照亮周围的物体,只是他本体看起来更亮而已。
- 高光反射(金属之类的) 描述当光线从光源照射到模型表面时,该表面会在完全镜面反射方向散射多少辐射量。
- 漫反射 该表面会向四周散射多少辐射量
- 环境光 描述其他所有的间接光照(就是其他物体的发射的光线)。
兰伯特定律
发射光线的强度与表面法线和光源方向之间的夹角余弦值成正比。
漫发射的计算公式
C = (c * m) * max( 0 , n * l )。
小写 c 为光源颜色,m 为漫反射颜色,n 是表面法线,l 是指向光源的单位矢量。需要注意应该防止发现和光源点乘的结果为负值(避免物体被从后面来的光源照亮),所以用 max 函数限制其为正数。
高光反射的计算公式
- r = 2(n * l)n - l
- C = (c * m) * (max(0,v * r)) ^ gloss
n,l 代表意义与漫反射公式相同,r 为光的反射方向矢量,m 为高光反射颜色,v 为 视角方向矢量,gloss 为材质的光泽度,gloss 越大亮点就越小。
Blinn 模型的高光反射计算公式
与上述 Phong 模型不同的是,Blinn 模型引入了一个新矢量 h,通过对 v 和 l 的取平均后再归一化得到:h = (v + l) / | v + l |。
公式为:C = (c * m) * (max ( 0, n * h ))^gloss
逐像素与逐顶点光照
在片元着色器中计算,称为逐像素光照。在顶点着色器中计算,称为逐顶点光照(高罗德着色)。逐顶点光照是在每个顶点上计算光照,然后在渲染图元内部进行线性插值,最后输出成像素颜色。由于顶点数目小于像素数目,所以其计算量小于逐像素光照,因此在阴影交界处会出现锯齿,精细度不如逐像素光照。
Unity 的环境光和自发光
环境光可以通过 Shader 的内置变量 UNITY_LIGHTMODEL_AMBIENT 访问
自发光只需要在片元着色器输出最后的颜色之前,把材质的自发光颜色添加到输出颜色上就行。
漫反射和高光反射的 Shader 实现
漫反射光照模型(逐顶点)
Shader "Unity Shader Book/Chapter6/Diffuse Vertex-Level"
{
Properties
{
_Diffuse("Diffuse",Color) = (1.0,1.0,1.0,1.0)
}
SubShader
{
Tags { "LightMode"="ForwardBase" }
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Lighting.cginc"
fixed4 _Diffuse;
struct appdata
{
float4 vertex : POSITION; //顶点在模型空间的坐标
float3 normal : NORMAL; //法线
} ;
struct v2f
{
fixed3 color : COLOR; //输出颜色
float4 pos : SV_POSITION; //输出位置
} ;
v2f vert (appdata v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex); //模型空间转换到裁剪空间
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz; //环境光
fixed3 worldNormal = normalize(mul(v.normal,(float3x3)unity_WorldToObject)); //法线方向n
fixed3 worldLight = normalize(_WorldSpaceLightPos0.xyz); //光源位置
fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal,worldLight)); //公式计算
o.color = ambient + diffuse;
return o;
}
fixed4 frag (v2f i) : SV_Target
{
return fixed4(i.color,1.0);
}
ENDCG
}
}
}高光反射模型(逐顶点)
Shader "Unity Shader Book/Chapter6/SpecularVertexLevel"
{
Properties
{
_Diffuse("Diffuse",Color) = (1.0,1.0,1.0,1.0)
_Specular("Specular",Color) = (1.0,1.0,1.0,1.0)
_Gloss("Gloss",Range(8.0,256)) = 20 //镜面反射面积大小
}
SubShader
{
Tags { "LightMode"="ForwardBase" } //小心,如果没有这个光源会反向
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Lighting.cginc"
fixed4 _Diffuse;
fixed4 _Specular;
float _Gloss;
struct appdata
{
float4 vertex : POSITION;
float3 normal : NORMAL;
} ;
struct v2f
{
float3 color: COLOR;
float4 pos : SV_POSITION;
} ;
v2f vert (appdata v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
//等同于 "o.pos = mul(UNITY_MATRIX_MVP,v.vertex);"
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
fixed3 worldNormal = normalize(mul(v.normal,(float3x3)unity_WorldToObject));
//或使用 UnityObjectToWorldNormal(v.normal)
fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal,worldLightDir));
fixed3 reflectDir = normalize(reflect(-worldLightDir,worldNormal)); //反射方向矢量r
fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - mul(unity_ObjectToWorld,v.vertex).xyz); //视线方向
fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(saturate(dot(reflectDir,viewDir)),_Gloss); //公式计算
o.color = ambient + diffuse + specular;
return o;
}
fixed4 frag (v2f i) : SV_Target
{
return fixed4(i.color,1.0);
}
ENDCG
}
}
}边栏推荐
- It is said that Huawei will cut the order again! Supply chain manufacturers are more difficult
- 美国官员建议特朗普阻止英飞凌收购赛普拉斯
- Iptables learning
- 联发科携手三星推出全球首款支持Wi-Fi 6的8K电视
- In depth understanding of redis master-slave principle
- What is private traffic?
- [cloud native] deploy redis cluster in k8s
- Cy3荧光标记抗体/蛋白试剂盒 (10~100mg标记量)
- 2022/3/11 考试总结
- 中芯国际购买的ASML光刻机顺利进厂,但并未非EUV光刻机!
猜你喜欢

It's time to say goodbye gracefully to nullpointexception

Take you to master makefile analysis

浅谈数仓的数据治理

Jeninkins offline deployment

2022年软件开发的趋势

Preparation of peptide kc2s modified albumin nanoparticles / targeting peptide GX1 modified human serum albumin nanoparticles probe

cron 表达式

多肽KC2S修饰白蛋白纳米粒/靶向肽GX1修饰人血清白蛋白纳米粒探针的研究制备

Quartus:Instantiation of ‘sdram_model_plus‘ failed. The design unit was not found.

PyQt5快速开发与实战 4.10 窗口绘图类控件
随机推荐
[cloud native] deploy redis cluster in k8s
Six employees have been confirmed! Samsung closed the turtle tail mobile phone factory for the third time!
Cache learning
饿了么input输入框设置type=‘number‘时,去掉后面的上下按钮
Uniswap集成sudoswap,能否拉开NFT流动性新序幕?
Buuctf brushes eleven questions (05)
云计算服务主要安全风险及应对措施
Jeninkins离线部署
传英特尔明年将采用台积电6nm EUV工艺
RN search highlight
物联网架构完全指南
Purple light FPGA solves the mask problem! Boost the overall speed-up of mask production
2022/4/11 考试总结
Video human behavior detection
Understanding and use of third-party library
组件的传参
初中三年回忆录
雅思听力——剑雅5——Text1
In depth understanding of redis master-slave principle
Eight years of love between me and the message queue