【Overload游戏引擎细节分析】Lambert材质Shader分析
一、经典光照模型:Phong模型
现实世界的光照是极其复杂的,而且会受到诸多因素的影响,这是以目前我们所拥有的处理能力无法模拟的。经典光照模型冯氏光照模型(Phong Lighting Model)通过单独计算光源成分得到综合光照效果,然后添加到材质表面特定的点。冯光照模型的主要由3个部分组成:环境(Ambient)、漫反射(Diffuse)和镜面(Specular)光照。
- 环境光照(Ambient Lighting): 即使在黑暗的情况下,世界上也仍然有一些光亮,所以物体永远不会是完全黑暗的。我们使用环境光照来模拟这种情况,也就是无论如何永远都给物体一些颜色。计算这个光照并不涉及任何关于光的方向或人眼观察场景方向。
- 漫反射光照(Diffuse Lighting):模拟一个发光物对物体的方向性影响(Directional Impact)。它是冯氏光照模型最显著的组成部分。面向光源的一面比其他面会更亮。Lambert方程是计算漫反射的一种方式。
- 镜面光照(Specular Lighting):也成高光项,模拟有光泽物体上面出现的亮点。镜面光照的颜色,相比于物体的颜色更倾向于光的颜色。

二、Lambert漫反射模型
兰伯特光照模型是经验模型,主要用于计算漫反射光照。漫反射有以下特点:
- 反射强度与观察者的角度没有关系,向任何方向的反射都是一样的;
- 反射强度与光线的入射角度有关系,当入射光垂直于物体表面时,光照最强,随着光线与法线夹角变大反射强度逐渐变小。

兰伯特定律(Lambert’s law):反射光线的强度与表面法线和光源方向之间夹角的余弦值成正比,夹角越大,受到的光线照射量越少,当夹角大于90度,光线照射物体背面,此时认为光照强度为0。


计算公式:
B d = C I c o s ( θ ) = C I ( L ⋅ N ) B_{d}=\mathbf{C} \mathbf{I}cos(\theta) = \mathbf{C} \mathbf{I}(\mathbf{L}\cdot\mathbf{N}) Bd=CIcos(θ)=CI(L⋅N)
其中:
C—光的颜色
I —光照强度
L—光源方向,入射光的反方向,默认已单位化
N—物体的法向,默认已单位化
三、Overloal创建材料
Overload中在左下角Assert菜单上右键,可以找到创建材料的入口。其提供了Lambert材质,创建完成后,会在Material Editor面板找到其可配置参数。

Material Setting是渲染管线的配置,比较通用。Shader Setting是其使用的Shader入参,可以看到其可以设置一个漫反射贴图,还可设置漫反射的光颜色。所谓材料就是Shader+unform参数+贴图,其中Shader是其核心计算逻辑。下面就分析一下其使用的Shader。
四、shader分析
Lambert材质使用的Shader在Lambert.glsl文件中,其前半部分是Vertex Shader,后半部分是Fragment Shader,源码如下:
#shader vertex
#version 430 corelayout (location = 0) in vec3 geo_Pos; // 顶点坐标
layout (location = 1) in vec2 geo_TexCoords; // 顶点纹理坐标
layout (location = 2) in vec3 geo_Normal; // 顶点法线layout (std140) uniform EngineUBO // UBO方式传入MVP矩阵
{mat4 ubo_Model;mat4 ubo_View;mat4 ubo_Projection;vec3 ubo_ViewPos;float ubo_Time;
};out VS_OUT // 顶点着色器输出
{vec3 FragPos; // 顶点世界坐标系下的坐标vec3 Normal; // 顶点法线vec2 TexCoords; // 顶点纹理
} vs_out;void main()
{vs_out.FragPos = vec3(ubo_Model * vec4(geo_Pos, 1.0)); // 使用模型矩阵计算全局坐标系下的坐标vs_out.Normal = normalize(mat3(transpose(inverse(ubo_Model))) * geo_Normal); // 计算全局坐标系下的法线vs_out.TexCoords = geo_TexCoords; // 纹理坐标不用变gl_Position = ubo_Projection * ubo_View * vec4(vs_out.FragPos, 1.0); // 计算NDC坐标
}#shader fragment
#version 430 coreout vec4 FRAGMENT_COLOR;in VS_OUT
{vec3 FragPos;vec3 Normal;vec2 TexCoords;
} fs_in;uniform vec4 u_Diffuse = vec4(1.0, 1.0, 1.0, 1.0); // 漫反射光颜色
uniform sampler2D u_DiffuseMap; // 漫反射贴图
uniform vec2 u_TextureTiling = vec2(1.0, 1.0);
uniform vec2 u_TextureOffset = vec2(0.0, 0.0);const vec3 c_lightPosition = vec3(-9000.0, 10000.0, 11000.0); // 光源位置
const vec3 c_lightDiffuse = vec3(1.0, 1.0, 1.0); // 光源强度
const vec3 c_lightAmbient = vec3(0.3, 0.3, 0.3); // 环境光强度vec3 Lambert(vec3 p_fragPos, vec3 p_normal)
{const float diffuse = max(dot(p_normal, normalize(c_lightPosition - p_fragPos)), 0.0); // L点乘Nreturn clamp(c_lightDiffuse * diffuse + c_lightAmbient, 0.0, 1.0); // 漫反射与环境光叠加
}void main()
{const vec4 diffuse = texture(u_DiffuseMap, u_TextureOffset + vec2(mod(fs_in.TexCoords.x * u_TextureTiling.x, 1), mod(fs_in.TexCoords.y * u_TextureTiling.y, 1))) * u_Diffuse; // 获取贴图颜色FRAGMENT_COLOR = vec4(Lambert(fs_in.FragPos, fs_in.Normal) * diffuse.rgb, diffuse.a);
}
Vertex Shader的入参有顶点坐标、纹理坐标、法线、模型视图投影矩阵。其逻辑很简单,没有特殊操作,计算法线、NDC坐标完事。
Fragment Shader中,先从纹理中获取片元颜色并与设置的环境光颜色相乘,这是最强的光颜色。如果贴图没有设置,那么texture函数返回的是1.0,至于原因前面的文章中分析过。函数Lambert是核心计算逻辑,包含了Lambert计算公式,其先计算L,在与法线点乘,最终结果就是 c o s ( θ ) cos(\theta) cos(θ)。漫反射的光强度与环境光强度都是写死的。两者累计,用clamp保证最终结果在0到1之间,修正了 c o s ( θ ) < 0 cos(\theta) <0 cos(θ)<0的情况。可见这种材质没有高光成分。
相关文章:
【Overload游戏引擎细节分析】Lambert材质Shader分析
一、经典光照模型:Phong模型 现实世界的光照是极其复杂的,而且会受到诸多因素的影响,这是以目前我们所拥有的处理能力无法模拟的。经典光照模型冯氏光照模型(Phong Lighting Model)通过单独计算光源成分得到综合光照效果,然后添加…...
二进制搭建 Kubernetes+部署网络组件+部署CornDNS+负载均衡部署+部署Dashboard
二进制搭建 Kubernetes v1.20 k8s集群master01:20.0.0.50 kube-apiserver kube-controller-manager kube-scheduler etcd k8s集群master02:20.0.0.100k8s集群node01:20.0.0.110 kubelet kube-proxy docker etcd k8s集群node02:20.…...
【 OpenGauss源码学习 —— 列存储(update_pages_and_tuples_pgclass)】
列存储(update_pages_and_tuples_pgclass) 概述update_pages_and_tuples_pgclass 函数ReceivePageAndTuple 函数estimate_cstore_blocks 函数get_attavgwidth 函数get_typavgwidth 函数 vac_update_relstats 函数 测试案例 声明:本文的部分内…...
爬虫进阶-反爬破解7(逆向破解被加密数据:全方位了解字体渲染的全过程+字体文件的检查和数据查看+字体文件转换并实现网页内容还原+完美还原上百页的数据内容)
目录 一、全方位了解字体渲染的全过程 1.加载顺序 2.实践操作:浏览器中调试字体渲染 3.总结: 二、字体文件的检查和数据查看 1.字体文件的操作软件 2.映射关系的建立 3.实践操作:翻找样式和真实内容 4.总结: 三、字体文…...
系统架构设计师之RUP软件开发生命周期
系统架构设计师之RUP软件开发生命周期...
VM虚拟机 13.5 for Mac
VMware Fusion Pro for Mac是一款强大的虚拟机软件,可以在Mac操作系统中创建、运行和管理多个虚拟机,使用户可以在一台Mac电脑上同时运行多个操作系统和应用程序。 以下是VMware Fusion Pro for Mac的主要特点: 1. 支持多种操作系统ÿ…...
一篇教你学会Ansible
前言 Ansible首次发布于2012年,是一款基于Python开发的自动化运维工具,核心是通过ssh将命令发送执行,它可以帮助管理员在多服务器上进行配置管理和部署。它的工作形式依托模块实现,自己没有批量部署的能力。真正具备批量部署的是…...
Mysql第四篇---数据库索引优化与查询优化
文章目录 数据库索引优化与查询优化索引失效案例数据准备1. 全值匹配2 最佳左前缀法则(联合索引)主键插入顺序4 计算、函数导致索引失效5 类型转换(自动或手动)导致索引失效6 范围条件右边的列索引失效7 不等于(!或者<>)索引失效8 is null可以使用索引, is not null无法使…...
SpringBoot手动获取实例
1.首先创建一个接口里面是关于建库建表的方法 public interface MetaMapper {//三个核心建表方法void createExchangeTable();void createQueueTable();void createBingdingTable(); } 2.启动类中定义一个ConfigurableApplicationContext 类型的变量context接收SpringApplica…...
栈(Stack)的概念+MyStack的实现+栈的应用
文章目录 栈(Stack)一、 栈的概念1.栈的方法2.源码分析 二、MyStack的实现1.MyStack的成员变量2.push方法3.isEmpty方法和pop方法4.peek方法 三、栈的应用1.将递归转化为循环1.调用递归打印2.通过栈逆序打印链表 栈(Stack) 一、 栈…...
C语言进阶第九课 --------动态内存管理
作者前言 🎂 ✨✨✨✨✨✨🍧🍧🍧🍧🍧🍧🍧🎂 🎂 作者介绍: 🎂🎂 🎂 🎉🎉🎉…...
嵌入式 Tomcat 调校
SpringBoot 嵌入了 Web 容器如 Tomcat/Jetty/Undertow,——这是怎么做到的?我们以 Tomcat 为例子,尝试调用嵌入式 Tomcat。 调用嵌入式 Tomcat,如果按照默认去启动,一个 main 函数就可以了。 简单的例子 下面是启动…...
初始化固定长度的数组
完全解析Array.apply(null,「length: 1000」) 创建固定长度数组,并且初始化值。直接可以使用map、forEach、reduce等有遍历性质的方法。 如果直接使用Array(81),map里面的循环不会执行。 //方法一 Array.apply(null, { length: 20 })//方法二 Array(81)…...
实现基于 Jenkins 的多服务器打包方案
实现基于 Jenkins 的多服务器打包方案 在实际项目中,我们经常会遇到需要将一个应用程序或服务部署到不同的服务器上的需求。而使用 Jenkins 可以很方便地自动化这个过程。 设置参数 首先,我们需要设置一些参数,以便在构建过程中指定要部署…...
探索现代IT岗位:职业机遇的海洋
目录 1 引言2 传统软件开发3 数据分析与人工智能4 网络与系统管理5 信息安全6 新兴技术领域 1 引言 随着现代科技的迅猛发展,信息技术(IT)行业已经成为了全球经济的关键引擎,改变了我们的生活方式、商业模式和社会互动方式。IT行…...
np.linspace精确度
前言 今天发现一个大坑,如果是序列是小数的话,不要用np.linspace,而要用np.arrange指定等差序列。比如入下图中a和b是一样的意思,但是b是有较大误差的。 anp.arange(0,4,0.4) bnp.linspace(0,4,10) print("a",a) prin…...
GD32_定时器输入捕获波形频率
GD32_定时器输入捕获波形频率(多通道轮询) 之前项目上用到一个使用定时器捕获输入采集风扇波形频率得到风扇转速的模块,作为笔记简单记录以下当时的逻辑结构和遇到的问题,有需要参考源码、有疑问或需要提供帮助的可以留言告知 。…...
单窗口单IP适合炉石传说游戏么?
游戏道具制作在炉石传说中是一个很有挑战的任务,但与此同时,它也是一个充满机遇的领域。在这篇文章中,我们将向您展示如何在炉石传说游戏中使用动态包机、多窗口IP工具和动态IP进行游戏道具制作。 作者与主题的关系:作为一名热爱炉…...
win11安装docekr、docker-compose
1.docker安装 下载地址:Install Docker Desktop on Windows | Docker Docs 出问题别慌,看清楚提示信息,cmd更新wsl,什么是wsl,百度好好理解一下哦 2.docker-compose安装 还是去官方看看怎么说的,然后跟着处…...
Postman的简单使用
Postman简介 官网 Postman是Google公司开发的一款功能强大的网页调试与发送HTTP请求,并能运行测试用例的Chrome插件 使用Postman进行简单接口测试 新建测试 → 选择请求方式 → 请求URL,下面用百度作为例子: 参考文档 [1] Postman使用教程…...
R语言AI模型部署方案:精准离线运行详解
R语言AI模型部署方案:精准离线运行详解 一、项目概述 本文将构建一个完整的R语言AI部署解决方案,实现鸢尾花分类模型的训练、保存、离线部署和预测功能。核心特点: 100%离线运行能力自包含环境依赖生产级错误处理跨平台兼容性模型版本管理# 文件结构说明 Iris_AI_Deployme…...
服务器硬防的应用场景都有哪些?
服务器硬防是指一种通过硬件设备层面的安全措施来防御服务器系统受到网络攻击的方式,避免服务器受到各种恶意攻击和网络威胁,那么,服务器硬防通常都会应用在哪些场景当中呢? 硬防服务器中一般会配备入侵检测系统和预防系统&#x…...
oracle与MySQL数据库之间数据同步的技术要点
Oracle与MySQL数据库之间的数据同步是一个涉及多个技术要点的复杂任务。由于Oracle和MySQL的架构差异,它们的数据同步要求既要保持数据的准确性和一致性,又要处理好性能问题。以下是一些主要的技术要点: 数据结构差异 数据类型差异ÿ…...
EtherNet/IP转DeviceNet协议网关详解
一,设备主要功能 疆鸿智能JH-DVN-EIP本产品是自主研发的一款EtherNet/IP从站功能的通讯网关。该产品主要功能是连接DeviceNet总线和EtherNet/IP网络,本网关连接到EtherNet/IP总线中做为从站使用,连接到DeviceNet总线中做为从站使用。 在自动…...
Element Plus 表单(el-form)中关于正整数输入的校验规则
目录 1 单个正整数输入1.1 模板1.2 校验规则 2 两个正整数输入(联动)2.1 模板2.2 校验规则2.3 CSS 1 单个正整数输入 1.1 模板 <el-formref"formRef":model"formData":rules"formRules"label-width"150px"…...
Mobile ALOHA全身模仿学习
一、题目 Mobile ALOHA:通过低成本全身远程操作学习双手移动操作 传统模仿学习(Imitation Learning)缺点:聚焦与桌面操作,缺乏通用任务所需的移动性和灵活性 本论文优点:(1)在ALOHA…...
C语言中提供的第三方库之哈希表实现
一. 简介 前面一篇文章简单学习了C语言中第三方库(uthash库)提供对哈希表的操作,文章如下: C语言中提供的第三方库uthash常用接口-CSDN博客 本文简单学习一下第三方库 uthash库对哈希表的操作。 二. uthash库哈希表操作示例 u…...
【Elasticsearch】Elasticsearch 在大数据生态圈的地位 实践经验
Elasticsearch 在大数据生态圈的地位 & 实践经验 1.Elasticsearch 的优势1.1 Elasticsearch 解决的核心问题1.1.1 传统方案的短板1.1.2 Elasticsearch 的解决方案 1.2 与大数据组件的对比优势1.3 关键优势技术支撑1.4 Elasticsearch 的竞品1.4.1 全文搜索领域1.4.2 日志分析…...
论文阅读:LLM4Drive: A Survey of Large Language Models for Autonomous Driving
地址:LLM4Drive: A Survey of Large Language Models for Autonomous Driving 摘要翻译 自动驾驶技术作为推动交通和城市出行变革的催化剂,正从基于规则的系统向数据驱动策略转变。传统的模块化系统受限于级联模块间的累积误差和缺乏灵活性的预设规则。…...
Python实现简单音频数据压缩与解压算法
Python实现简单音频数据压缩与解压算法 引言 在音频数据处理中,压缩算法是降低存储成本和传输效率的关键技术。Python作为一门灵活且功能强大的编程语言,提供了丰富的库和工具来实现音频数据的压缩与解压。本文将通过一个简单的音频数据压缩与解压算法…...
