2.4 传统经验光照模型详解

一、光照模型

光照模型(illumination model),也称为明暗模型,用于计算物体某点处的光强(颜色值)。从算法理论基础而言,光照模型分为两类:一种是基于物理理论的,另一种是基于经验模型的。

基于物理理论的光照模型:偏重于使用武力的度量和统计方法,效果非常真实,但是计算复杂,实现起来也较为困难。

经验模型:是对光照的一种模拟,通过实践总结出简化的方法,简化了真实光照计算,并能达到不错的效果。

 

1.1 为什么需要光照模型

现实世界的光照是极其复杂的,而且会受到诸多因素影响,有限的计算能力无法完全模拟。使用简化的光照模型对现实的情况进行近似,使得计算处理起来会更容易,并且零效果更符合需求。这些光照模型就是基于我们对光的特性的理解。

1.2 光照模型的发展

二、局部光照模型的组成

定义:局部光照模型只关心直接光照部分,即直接从光源发出并照射到物体表面并反射至摄像头的光线。

组成:

    • 漫反射
    • 高光反射
    • 环境光
    • 自发光

漫反射

定义:在光照模型的定义中,当光线从光源照射到模型表面时,光线均匀被反射到各个方向,这种现象就是漫反射。在漫反射的过程中,光线发生额了吸收和散射,而因此改变颜色方向。

如何计算:漫反射光照符合Lambert定律,反射光强与法线和光源方向之间的夹角余弦值成正比。

基础理论:在光学中通常使用辐射度来量化光。

其中光源每秒发出的能量为辐射通量P

单位面积接受的光量为辐射密度(辐照度)P/A

当光源垂直照射的单位面积的辐照度为E1 = P/A1

将光束以某个角度照射到更大的平面上的辐射度为E2 = P/A2

简洁的来说:反射光线的强度与表面法线和光源方向之间的夹角的余弦成正比。

高光/镜面反射

定义:当光线到达物体表面并发生了反射,观察室现在反射光线的附近时,便能够观察到高光反射。高光反射描述了光线与物体表面发生的反射(光强不变,方向改变)。

高光反射的反射率水根据一种菲尼尔效应的物理现象决定的,通常使用对应的反射贴图描述物体表面的反射率,并且使用光泽度(粗糙度,反光度)描述高光范围的大小。

环境光

定义:在局部光照模型中,由于没有考虑间接光照影响,因此为了处理这种间接光照,从而引入环境光。

计算:

通常使用漫反射的反照率来只是环境光找的反射量,个模型假定场景中发生多次散射和反射,并在所有方向上均等的射向目标物体。

渲染结果:

自发光

定义:顾名思义,物体自身发射的光线,通常作为单独的一项加入光照模型,一般使用一张发光贴图描述物体的自放光。

局部光照模型的整体效果

三、着色模型

1、Gourand模型(逐顶点着色)

定义:以顶点为单位计算光量在通过差值得到每个像素点的光亮度。

在表现物体光滑性上有较好的表现,但值不再是线性变化的时候,比如镜面高光,由于线性差值导致内插值不可能大于顶点值。因此高光只能出现在顶点。

由于使用的颜色差值,会导致镜面高高蔓延到周边。

代码部分:

  • 是在定点着色器中计算的(因为是逐顶点)
  • 顶点颜色使用的是Phong模型的结果
  • 高光部分用的是观察方向和反射方向的余弦值
  • 计算完之后将它座位顶点所携带的颜色
  • 在片元/像素着色器中,直接将顶点携带的颜色赋值给了返回颜色

最终效果:

左边是Gourand模型

2、Flat模型

平面着色模型,计算多边形的单个强度,每个三角形只有一个法线方向。以相同的光强度值显示多边形的所有点。适用于lowpoly风格的场景。

四、经典光照模型

1、Lambert模型

光照公式:

n:表面法线

l:指向光源的单位矢量

mdiffuse:材质的漫反射颜色

clight:光源颜色

防止法线和光源方向点乘的结果为负值,为此使用取最大值的函数来将其截取到0,这样可以防止物体被从后面来的光源照亮。

漫反射效果与观察者位置无关,于光源位置有关。

代码部分:

主光源入射光 * 漫反射材质的颜色 * 法线方向与光照方向的点积

渲染效果:

可以看出漫反射至于光源和表面法线有关,与观察者无关。

2、Phong模型

如何计算:

在这四个矢量中,我们实际上只需要知道其中3个矢量即可,而第四个矢量——反射方向,可以通过其他信息计算得到:

r计算过程参考:几何向量:计算光线反射reflect向量_空间几何中怎么求入射光的反射向量_羊羊2035的博客-CSDN博客

mgloss:材质的光泽度(反光度),它用于控制高光区域的“亮点”有多宽,数值越大,亮点越小。

mspecular:材质的高光反射颜色,它用于控制该材质对于高光反射的强度和颜色。

Clight:光源的颜色和强度

r:反射光线

v:视线向量

反应了光泽度与高光反射的关系

光泽度渲染效果:

最终计算公式:

代码部分:

unity的环境光宏 * 漫反射材质

最终渲染结果:

3、Blinn-Phong模型

在Phong的基础上引入了一个新的矢量h,他是通过vl取平均后在归一化得到的。

然后使用nh之间的夹角进行计算,而非vr之间的夹角。

计算公式:

最终计算公式:

代码部分:

最终渲染结果:

4、Phong和Blinn-Phong模型的区别

通过对Phong模型和Blinn-Phong模型公式对比,可以知道公式的不同之处在于使用了半角向量与发现的点积结果。

半角向量的使用带来的变化:

    • 计算更加简洁,半角向量的计算更加简洁
    • 当光源与视线都在表面之上时,半角向量与发现的角度永远不大于90度

设想一种情况,当材质的反光度非常低时,因此物体被光线照射的大部分区域都会发生高光反射。这些去榆中的一部分高光部分的反射向量与视线的夹角超过了90度。此时,如果使用Phong模型就会导致高光区域一部分发生缺失。这是由于Phong模型只会考虑实现与光照分布在法线两侧的情况。当时视线与光照在发现同侧时且高光反射对亮度有较大影响时,就会发生断层。

五、光照模型展示

作业

说出能量守恒的理念在基础光照模型中的作用

我理解的在光照模型中的能量守恒理念就是:光源所发出的能量(光线)经过物体多次表面反弹、散射、射入等后,其能量总和不会发生变化。

能量守恒是PBR的一个重要概念。它可以保证美术合适的设置材质的反射率和albedo值,而不破坏物理规则。虽然在着色系统中强制能量守恒的物理限制并不等价于最后好看的着色效果,但起码可以使得渲染效果不至于背离物理规则太远,保证在不同光照条件下物体的光照表现一致性。

基于能量守恒的理念,自己写一套完整的光照模型,需要包含环境光照

Shader "Lpk/Blinn-Phong"
{Properties{_Diffuse          ("Diffuse", Color)         = (1,1,1,1)_MainTex          ("Texture", 2D)            = "white"{}_NormalMap        ("Normal", 2D)             = "pink"{}_LocalNormalScale ("LocalNormal",Range(0,1)) = 0_Specular         ("SpecularColor", Color)   = (1,1,1,1)_Gloss            ("Gloss", Range(1.0,255))  = 20_CubeMap          ("Env map",CUBE)           = ""{}_EnvScale         ("Env Scale",Range(0,1))   = 1}SubShader{Tags { "RenderType"="Opaque" }Pass{CGPROGRAM#pragma vertex vert#pragma fragment frag//引入头文件#include "UnityCG.cginc"#include "Lighting.cginc"struct appdata{float4 vertex : POSITION;float2 uv0 : TEXCOORD0;float2 uv1 : TEXCOORD1;float3 normal : NORMAL;float4 tangent : TANGENT;};struct v2f{float2 uv0 : TEXCOORD0;float2 uv1 : TEXCOORD1;float4 vertex : SV_POSITION;float3 worldNormal : TEXCOORD2;float3 tangentNormal : TEXCOORD3;float3 bitangentNormal : TEXCOORD4;float3 worldPos : TEXCOORD5;};sampler2D   _MainTex;float4      _MainTex_ST;sampler2D   _NormalMap;float4      _NormalMap_ST;fixed4      _Diffuse;fixed4      _Specular;float       _Gloss;float       _LocalNormalScale;samplerCUBE _CubeMap;float       _EnvScale;v2f vert (appdata v){v2f o;               //将顶点从模型空间转换到裁剪空间o.vertex = UnityObjectToClipPos(v.vertex);//把发现转换到世界空间//o.worldNormal = mul(v.normal,(float3x3)unity_WorldToObject);(旧写法)o.worldNormal = UnityObjectToWorldNormal(v.normal);o.worldPos = mul(unity_ObjectToWorld,v.vertex).xyz;//计算UV Offset与Tilingo.uv0 = TRANSFORM_TEX(v.uv0,_MainTex);o.uv1 = TRANSFORM_TEX(v.uv1,_NormalMap);//计算法线切线、副切线o.tangentNormal = normalize(mul(unity_ObjectToWorld,float4(v.tangent.xyz,0.0)).xyz);o.bitangentNormal = normalize(cross(o.worldNormal,o.tangentNormal) * v.tangent.w);return o;}fixed4 frag (v2f i) : SV_Target{//--基础的计算//纹理采样fixed4 mainTex = tex2D(_MainTex,i.uv0);//环境光fixed3 amibent = UNITY_LIGHTMODEL_AMBIENT.xyz * _Diffuse.rgb * mainTex.rgb;//归一化光方向fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);//归一化法线,即使在vert归一化也不行,从vert到frag阶段有差值处理,传入的法线方向并不是vertex shader直接传出的fixed3 worldNormal = normalize(i.worldNormal);//--计算法线贴图fixed3x3 tangentRotation = fixed3x3(i.tangentNormal,i.bitangentNormal,worldNormal);fixed3 normalTangent = UnpackNormal(tex2D(_NormalMap, i.uv1));//将法线从切线空间转换到世界空间fixed3 normalWorld = normalize(mul(normalTangent.rgb,tangentRotation));fixed3 finalNormal = lerp(worldNormal,normalWorld,_LocalNormalScale);//--Lambert//计算法线与入射光的点积sfixed3 NdotL= max(0, dot(finalNormal, worldLightDir));//Lambert颜色(漫反射)fixed3 lambertColor = mainTex.rgb * _Diffuse.rgb * _LightColor0.rgb * NdotL;//--Phong//计算反射方向R,worldLight表示光源方向(指向光源),入射光线方向为-worldLightDirfixed3 reflectDir = normalize(reflect(-worldLightDir, finalNormal));//计算该视角方向fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - i.worldPos.xyz);//计算VdotR,视角与反射光线的点积 fixed3 VdotR = max(0,dot(viewDir, reflectDir));//计算phong颜色fixed3 phong = pow(VdotR,_Gloss)* _Specular.rgb;//--Blinn-Phong//计算半角向量fixed3 halfDir = normalize(worldLightDir + viewDir);//计算NdotHfixed3 NdotH = saturate(dot(finalNormal,halfDir));//计算Blinn-Phongfixed3 blinnphong = pow(NdotH,_Gloss) * _Specular.rgb;//漫反射与高光有个过渡fixed3 specular = lerp(lambertColor * blinnphong, blinnphong,_Gloss / 255);//环境贴图fixed3 worldRef = normalize(reflect(-viewDir, finalNormal));fixed4 reflectColor = texCUBElod(_CubeMap, fixed4(worldRef.rgb,(255 - _Gloss) * 8/(255))) * _EnvScale;//环境贴图与漫反射有个过渡reflectColor.rgb = lerp(reflectColor * lambertColor.rgb,reflectColor,_Gloss/255);//--最终颜色fixed4 finalColor = fixed4(lambertColor + amibent + reflectColor.rgb + specular ,1.0);//fixed4 finalColor = fixed4( reflectColor.rgb,1.0);return finalColor; }ENDCG}}
}

兰伯特光照模型 Phong光照模型 Blinn-Phong光照模型

环境光贴图 环境光贴图=0.2 环境光贴图=1

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/16735.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【MATLAB第61期】基于MATLAB的GMM高斯混合模型回归数据预测

【MATLAB第61期】基于MATLAB的GMM高斯混合模型回归数据预测 高斯混合模型GMM广泛应用于数据挖掘、模式识别、机器学习和统计分析。其中,它们的参数通常由最大似然和EM算法确定。关键思想是使用高斯混合模型对数据(包括输入和输出)的联合概率…

<Doc>Windows常见的doc命令

一:管理员身份运行cmd命令: 方式一:搜索框输入cmd,回车,点击:以管理员身份运行 出现如图所示: 方式二:快捷键运行方式: 1.按winr,在运行窗口中输入cmd。 …

JavaSE类和对象(重点:this引用、构造方法)

目录 一、类的定义方式以及实例化 1.面向对象 Java是一门纯面向对象的语言(Object Oriented Program,简称OOP),在Java的世界里一切皆为对象。 2.类的定义和使用 1.在java中定义类时需要用到class关键字 3.类的实例化 4.类实例化的使用 二、this引用 …

Java API指南:掌握常用工具类与字符串操作

文章目录 1. API简介2. Java API的使用2.1 创建和使用Java API工具类2.2 使用String类进行字符串操作 结语 导语: Java作为一门功能强大的编程语言,其成功之处不仅在于语法结构的简洁明了,更因为其丰富的API(Application Programm…

中药配方煎药-亿发智能中药汤剂煎煮系统,智慧中药房的数字化升级

随着中药的普及,在治病、养生等方面都发挥这积极作用,但中药煎煮过程繁琐,如果有所差错将会影响药品的药性。为了满足当今用户对中药的需求,增强生产效率和业务水平,亿发中药煎配智能管理系统应运而生,为用…

【JMeter】JMeter添加插件

目录 一、前言 二、插件管理器 三、推荐插件 1.Custom Thread Groups (1)Ultmate Thread Group (2)Stepping Thread Group 2.3 Basic Graph 资料获取方法 一、前言 ​ 在我们的工作中,我们可以利用一些插件来帮…

github gitlab 多用户多平台切换

一、背景 我需要用账号1 来登录并管理github 账号 我需要用账号2 来登录并管理gitlab 账号 二、设置账号 邮箱 设置账号1用户名与邮箱 git config --global user.name "miaojiang" git config --global user.email "187133163.com" 三、生成本地密钥…

中小企业如何低成本实施MES管理系统

中小企业在市场竞争中需要有高效的管理体系来支持其运营和发展。中小企业MES管理系统是一种先进的管理系统,可以提升工厂智能化水平,提高生产效率,是中小企业必须采取的有效管理工具。然而,由于资金和技术的限制,中小企…

反转链表(JS)

反转链表 题目 给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。 示例 1: 输入:head [1,2,3,4,5] 输出:[5,4,3,2,1]示例 2: 输入:head [1,2] 输出:[2,1]示例 3&…

MySQL初探

Background 通过阅读小林coding,大致了解了mysql数据库的种种特点,与之前学的数据库实现大体思路相同,感觉学习不能停留在理论层面,要调研生产级别的中间件实现。 一条代码运行在mysql上的流程 1. 连接的过程需要先经过 TCP 三次…

php://filter绕过死亡exit

文章目录 php://filter绕过死亡exit前言[EIS 2019]EzPOP绕过exit 参考 php://filter绕过死亡exit 前言 最近写了一道反序列化的题,其中有一个需要通过php://filter去绕过死亡exit()的小trick,这里通过一道题目来讲解 [EIS 2019]EzPOP 题目源码&#…

C语言每日一题:9.《数据结构》链表的中间节点+链表的倒数第k个节点。

第一题: 题目链接: >思路一: 1.第一遍遍历链表,直到找到尾结束第一次遍历,遍历的过程中记录链表长度。定义长度为k。 2.确定中间是第几个节点,计算是k/21根据题目要求。 3.再一次去遍历我们的数组&…

实战!聊聊工作中使用了哪些设计模式

实战!聊聊工作中使用了哪些设计模式 策略模式 业务场景 假设有这样的业务场景,大数据系统把文件推送过来,根据不同类型采取不同的解析方式。多数的小伙伴就会写出以下的代码: if(type"A"){//按照A格式解析}else if(t…

Electron逆向调试

复杂程序处理方式: 复杂方式通过 调用窗口 添加命令行参数 启动允许调用,就可以实现调试发布环境的electron程序。 断点调试分析程序的走向,程序基本上会有混淆代码处理, 需要调整代码格式,处理程序。

基于 Docker 的深度学习环境:Windows 篇

本篇文章,我们聊聊如何在 Windows 环境下使用 Docker 作为深度学习环境,以及快速运行 SDXL 1.0 正式版,可能是目前网上比较简单的 Docker、WSL2 配置教程啦。 写在前面 早些时候,写过一篇《基于 Docker 的深度学习环境&#xff…

Hbase基础概念

HBase 一、HBase的数据模型1.HBase数据存储结构2.HBase存储概念3.HBase基本架构 二、HBase Shell1.DDL(Data Definition Language)1.namespace2.table 2.DML(Data Manipulation Language)1.写入数据2.读取数据3.删除数据 三、HBase组成架构1. Master架构…

STM32 CubeMX 定时器(普通模式和PWM模式)

STM32 CubeMX STM32 CubeMX 定时器(普通模式和PWM模式) STM32 CubeMXSTM32 CubeMX 普通模式一、STM32 CubeMX 设置二、代码部分STM32 CubeMX PWM模式一、STM32 CubeMX 设置二、代码部分总结 STM32 CubeMX 普通模式 一、STM32 CubeMX 设置 二、代码部分 …

使用Pytest生成HTML测试报告

背景 最近开发有关业务场景的功能时,涉及的API接口比较多,需要自己模拟多个业务场景的自动化测试(暂时不涉及性能测试),并且在每次测试完后能够生成一份测试报告。 考虑到日常使用Python自带的UnitTest,所…

【JVM】详细解析java创建对象的具体流程

目录 一、java创建对象的几种方式 1.1、使用new关键字 1.2、反射创建对象 1.2.1、Class.newInstance创建对象 1.2.2、调用构造器再去创建对象Constructor.newInstance 1.3、clone实现 1.4、反序列化 二、创建对象的过程 2.1、分配空间的方式 1、指针碰撞 2、空闲列表 …

ElementUI 实现动态表单数据校验(已解决)

文章目录 🍋前言:🍍正文1、探讨需求2、查阅相关文档([element官网](https://element.eleme.cn/#/zh-CN/component/form))官方动态增减表单项示例3、需求完美解决4、注意事项 🎃专栏分享: &#…