【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使用教程…...

信号继电器驱动芯片(led驱动芯片)
驱动继电器需要配合BAV99(防止反向脉冲)使用 具体应用参考开源项目 电阻箱 sbstnh/programmable_precision_resistor: A SCPI programmable precision resistor (github.com) 这个是芯片的输出电流设置 对应到上面的实际开源项目其设置电阻为1.5K&…...

IDEA配置HTML和Thymeleaf热部署开发
IDEA配置HTML和Thymeleaf热部署开发 1.项目配置2. IDEA配置3. 使用 需求:现在我们在开发不分离项目的时候(SpringBootThmeleaf)经常会改动了类或者静态html文件就需要重启一下服务器, 这样不仅时间开销很大,而且经常重…...

Nginx动静分离
为了加快网站的解析速度,可以把动态页面和静态页面由不同的服务器来解析,加快解析速度。降低原来单个服务器的压力。 在动静分离的tomcat的时候比较明显,因为tomcat解析静态很慢,其实这些原理的话都很好理解,简单来说&…...

Spring中AOP详解
目录 一、AOP的概念 二、AOP的底层实现原理 2.1 JDK的动态代理 2.1.1 invocationhandler接口 2.1.2 代理对象和原始类实现相同的接口 interfaces 2.1.3 类加载器ClassLoador 2.1.4 编码实现 2.2 Cglib动态代理 2.2.1 Cglib动态代理编码实现 三、AOP如何通过原始对象的id获取到代…...

Unity DOTS系列之Filter Baking Output与Prefab In Baking核心分析
最近DOTS发布了正式的版本, 我们来分享一下DOTS里面Baking核心机制,方便大家上手学习掌握Unity DOTS开发。今天给大家分享的Baking机制中的Filter Baking Output与Prefab In Baking。 对啦!这里有个游戏开发交流小组里面聚集了一帮热爱学习游戏的零基础…...

Matlab读写操作
随机生成一个3*3矩阵,对矩阵进行按列升序排列 >> Arand(3,3); >> [B, ~] sort(A, 2); >> B B 0.4898 0.6797 0.70940.4456 0.6551 0.75470.1626 0.2760 0.6463在不同数值类型下显示π的值 1、默认数值类型 >> p_defa…...

Android 开发技巧:音乐播放器的后台处理【Service、Handler、MediaPlayer】
给定部分完成的MusicPlayer项目,实现其中未完成的service部分: 1、创建MusicService类,通过service组件实现后台播放音乐的功能; 2、在MainActivity中通过ServiceConnection连接MusicService,实现对音乐播放的控制&…...

使用Windows平台的Hyper-V虚拟机安装CentOS7的详细过程
Hyper-V虚拟机安装CentOS7 前言常见Linux系统CentOSUbuntuDebianKaliFedoraArch LinuxMintManjaroopenSUSE Hyper-V开启Hyper-V打开Hyper-V Hyper-V的使用新建虚拟机开始安装分区配置开始安装 修改yum源为阿里源 前言 作为一名开发者,就服务器而言,接触最…...

某马机房预约系统 C++项目(二) 完结
8.4、查看机房 8.4.1、添加机房信息 根据案例,我们还是先在computerRoom.txt中直接添加点数据 //几机房 机器数量 1 20 2 50 3 1008.4.2、机房类创建 同样我们在头文件下新建一个computerRoom.h文件 添加如下代码: #pragma once #include<i…...

npm 安装到指定文件夹
创建一个文件夹,用vscode或者cmd打开, 执行 npm install --prefix ./ 路径 包名, npm install --prefix ./ 包名 , 就会将包安装在当前文件夹, 例如: npm install --prefix ./ -g oppo-minigame…...