Three.js PBR渲染入门
myzbx 2024-12-04 13:59 16 浏览
最近基于物理的渲染(PBR)已成为实时和电影3D场景渲染的行业标准方法。顾名思义,这种渲染技术基于现实世界物理定律,根据场景中的材料和照明设置来计算表面对光的反应方式。PBR是Disney公司为其动画制作发明的技术,也用于现代游戏引擎,如Unreal和Frostbite。令人惊讶的是,压缩后仅 600kb的three.js核心使我们能够使用与这些巨头一样的渲染技术,甚至还可以在智能手机等低功耗设备上运行。就在几年前,这还是需要强大算力支撑的尖端技术,而现在我们可以在任何地方只需网络浏览器就可以运行。
使用Three.js的PBR很简单,只需切换我们使用的材料并添加光源即可。我们将介绍最重要的three.js PBR 材质,MeshStandardMaterial。在这个教程里我们不会深入PBR技术的实现细节,但如果你有兴趣了解更多,Physically Based Rendering: From Theory To Implementation 这本书是完全免费的。
1、照明和材料
在计算机图形渲染系统照明和材料中有着内在的联系。我们不能只谈论一个而避开另一个,这就是为什么在这个教程中我们需要介绍DirectionalLight 。这种光模仿来自遥远的光源(如太阳)的光线。稍后我们将更详细地探讨灯光和材料是如何相互作用的。要使用 MeshStandardMaterial这样的PBR 材料,我们必须为现场添加光线。这是有道理的 - 在现实世界中,如果没有光,我们看不见任何东西。与之相反,MeshBasicMaterial 材料不是基于物理的,不需要光线。
2、白天和夜间模式的切换问题
使用老派的、非PBR渲染来创建好看的场景需要大量乏味的参数调整。考虑这个场景:你为建筑展示设置了白天的起居室场景,阳光透过窗户,在房间周围营造出美丽的高光和阴影。稍后,你决定添加夜间模式,以展示房间周围的照明装置。使用非 PBR 技术的话,这种调整需要做大量工作。所有的照明和材料参数都需要调整,然后重新不停调整,直到夜景看起来和白天的场景一样好。
现在,想象同样的场景,但这次使用的是物理模型正确的照明和材料。要将白天切换到夜间,只需关闭代表太阳的灯,然后打开灯具中的灯。主天花板灯是一百瓦白炽灯泡?检查现实世界中等效灯泡的包装,记下它输出多少流明,然后在代码中应用该值,工作就完成了。
精心制作的基于物理的材料在所有照明条件下看起来都很棒。
3、启用物理正确的照明
在为场景添加光线之前,我们将切换到使用物理正确的照明强度计算。物理正确的照明与基于物理的渲染不是一回事,但是,将两者同时使用以便给我们一个完整的物理准确的场景是有意义的。物理正确的照明意味着使用真实世界的物理方程计算光线如何随着距离光源(衰减)而衰减。这是相当简单的计算,你可以在任何物理教科书找到这些方程。另一方面,基于物理的渲染涉及以物理正确的方式计算光线与表面的反应。这些方程要复杂得多。幸运的是,我们不必完全理解原理就可以使用它们!
要开启物理正确的照明,只需启用渲染器的.physicallyCorrectLights设置:
function createRenderer() {
const renderer = new WebGLRenderer();
// turn on the physically correct lighting model
renderer.physicallyCorrectLights = true;
return renderer;
}
默认情况下,此设置将禁用以保持向后兼容性。但是,开启它并没有什么不良的后果,因此我们将一直启用这个选项。为了使颜色和照明以物理上正确的方式工作,我们还需要调整一些参数,然而通过启用此设置,我们朝着生产级物理精确的场景照明迈出了重要的第一步。
4、创建物理大小的场景
要使物理上正确的照明准确无误,我们需要构建物理大小的场景。如果你的房间有1000公里长,使用来自真实灯泡的数据是没有意义的!如果你想用100瓦的灯泡照亮一个房间,就像在同等真实房间的灯泡一样,你必须以米为单位的正确尺度来建造房间。
在three.js中,单位是米
- 我们之前创建的2×2×2立方体,每边有两米长。
- camera.far = 100意味着我们可以看到100米远。
- camera.near = 0.1意味着离相机0.1米以内的物体将看不见。
使用米是一种惯例而不是规则。如果你不遵循这一惯例,除了物理上正确的照明不能正常运作之外,其他特性仍然会工作。事实上,在某些情况下,使用不同的尺度是有意义的。例如,如果你正在构建一个大规模的空间模拟,可能会决定使用1 个单位=1000 公里。但是,如果你想要物理上正确的照明,那么就必须使用此公式将场景构建为真实世界的规模:
1 个单位=1 米
如果引入了由另一位艺术家构建的以英尺、英寸、厘米等单位计量的模型,则应将其重新缩放到米。
5、Three.js中的照明
如果你在黑暗的房间里打开灯泡,该房间中的物体将以两种方式接收光线:
- 直接照明:直接来自灯泡并击中物体的光线。
- 间接照明:光线在集中物体之前从墙壁和房间内的其他物体上反射出来,改变颜色,每次反射都会损失一部分强度。
与之匹配,three.js中的光分为两种类型:
- Direct lights,模拟直接照明。
- Ambient lights,这是一种廉价且大致可信的方式模拟间接照明。
我们可以轻松模拟直接照明。直接光线从光源中出来,并以直线继续,直到它们击中物体,或不击中物体。然而,间接照明更难模拟,因为这样做需要计算从场景中所有表面无限次反射的无限数量的光线。没有足够强大的计算机来做到这一点,即使我们把自己限制在仅仅计算几千光射线,每个光只考虑几次反射(射线跟踪),它仍然需要太长的时间来计算。因此,如果我们想要在我们的场景中实现逼真的照明,需要某种方式来模拟间接照明。在Three.js中有几种技术可以做到,环境光(Ambient Light)是其中之一。其他技术包括基于图像的照明 (IBL) 和光探头,我们将在后续教程中介绍。
6、直接照明
在这一章中,我们将添加DirectionalLight来模拟来自太阳或其他非常明亮的遥远光源。我们将在稍后部分再讨论Ambient Light。Three.js核心提供了四种直接光,每种光类型都模拟了共同的实际光源:
- DirectionalLight => 阳光
- PointLight => 灯泡
- RectAreaLight => 条带照明或亮窗
- SpotLight => 聚光灯
默认情况下,阴影会被禁用
现实世界和three.js之间的一个区别是,在three.js中即使我们使用PBR,在默认情况下物体也不会阻挡光线。光路径上的每个物体都会受到照明,即使有一堵墙挡路。落在物体上的光会照亮它,但会直接穿过并照亮后面的物体。
我们可以逐个物体、逐个光源的手动启用阴影。但是,阴影成本很高,因此我们通常只启用一两盏灯的阴影,尤其是在我们的场景需要在移动设备上工作的情况下。只有直接的光线类型才能投射阴影,环境光不会产生阴影。
7、DirectionalLight介绍
定向光的光线
DirectionalLight (定向光)旨在模仿遥远的光源,如太阳,光线不会随着距离而褪色。场景中的所有物体无论放置在哪里,都会被同样程度地照亮,即使是在灯光后面。
定向光的光线是平行的,从光源位置向目标照射。 默认情况下,目标被放置在我们场景的原点(0,0,0),所以当我们移动光源,它将永远照向原点。
8、添加DirectionalLight
好了, 让我们给场景加一个DirectionalLight。打开或创建components/lights.js模块,该模块将遵循与该文件夹中其他组件相同的模式。首先,我们将导入该类,然后实现并导出createLights方法:
import { DirectionalLight } from 'three';
function createLights() {
const light = null; // TODO
return light;
}
export { createLights };
定向光构造器需要两个参数,颜色和强度。在这里,我们创建一个强度为8的纯白光:
function createLights() {
// Create a directional light
const light = new DirectionalLight('white', 8);
return light;
}
Three.js中所有的光都有颜色和强度设置,继承自Light基类。
9、放置光源
定向光从light.position射向light.target.position。正如我们上面提到的,光和目标的默认位置是我们场景的中心(0,0,0)。这意味着光目前从(0,0,0)射向(0,0,0)。这确实有效,但看起来不太好。我们可以通过调整light.position来提高表现力。我们将移动它到位置(10,10,10)。
import { DirectionalLight } from 'three';
function createLights() {
// Create a directional light
const light = new DirectionalLight('white', 8);
// move the light right, up, and towards us
light.position.set(10, 10, 10);
return light;
}
export { createLights };
现在,光线从(10,10,10)射向(0,0,0)。
10、World.js设置
在World.js,导入新模块:
import { createCamera } from './components/camera.js';
import { createCube } from './components/cube.js';
import { createLights } from './components/lights.js';
import { createScene } from './components/scene.js';
import { createRenderer } from './systems/renderer.js';
import { Resizer } from './systems/Resizer.js';
...
然后创建一个光源并将其添加到场景中。为场景添加光线就像添加mesh对象:
class World {
constructor(container) {
camera = createCamera();
scene = createScene();
renderer = createRenderer();
container.append(renderer.domElement);
const cube = createCube();
const light = createLights();
scene.add(cube, light);
const resizer = new Resizer(container, camera, renderer);
}
请注意,我们在scene.add 调用中同时添加了光源和mesh对象。
11、切换到PBR材质
添加光不会有任何立竿见影的效果,因为我们目前正在使用MeshBasicMaterial。正如我们前面提到的,这种材料忽略了现场的任何灯光。在这里我们将切换到MeshStandardMaterial。
顾名思义,MeshBasicMaterial是Three.js中最基本的材料,它根本不对灯光做出反应,网格对象的整个表面都用单一颜色着色,不考虑视角或距离,因此对象看起来甚至不是三维的。我们只能看到一个2D轮廓。
现在我们用MeshStandardMaterial替换基本材料。这是一种高质量、通用、物理精确的材料,使用真实世界的物理方程对光线做出反应。顾名思义,MeshStandardMaterial应该是几乎所有情况下的"标准"材料。辅以精心制作的纹理,我们可以使用MeshStandardMaterial 重建任何表面。
12、Three.js材料基类
如果在上述两个场景中打开"Material"菜单,就会看到两种材料具有许多相同的设置,例如transparent(材料是否透明)、opacity(透明度)、visible(显示/隐藏)等等。原因是所有的Three.js材料,都继承自Material基类。你不能直接使用Material,必须利用某个继承类,例如MeshStandard 或 MaterialBasic 。
13、切换立方体的材料
前往cube.js我们将切换到此新材料。首先需要导入它:
import { BoxBufferGeometry, Mesh, MeshStandardMaterial } from 'three';
然后,更新createCube 函数,将老式、无聊的基本材料切换到新的标准材料:
function createCube() {
const geometry = new BoxBufferGeometry(2, 2, 2);
// Switch the old "basic" material to
// a physically correct "standard" material
const material = new MeshStandardMaterial();
const cube = new Mesh(geometry, material);
return cube;
}
14、更改材料的颜色
我们将在此模块中再进行一次更改,并将材料的颜色设置为紫色。设置材料参数与three.js中的其他类略有不同,因为我们需要使用具有命名参数的规范对象:
const spec = {
color: 'purple',
}
const material = new MeshStandardMaterial(spec);
为了保持代码简短可读,我们采用内联式对象声明:
function createCube() {
const geometry = new BoxBufferGeometry(2, 2, 2);
// Switch the old "basic" material to
// a physically correct "standard" material
const material = new MeshStandardMaterial({ color: 'purple' });
const cube = new Mesh(geometry, material);
return cube;
}
在上面的代码中,我们使用CSS颜色名称设置颜色。
15、旋转立方体
作为教程的最后一部分,让我们旋转立方体,这样我们不再能从正面观察它。调整对象的旋转工作方式与设置其位置的方式大致相同。将以下代码添加到cube.js模块:
function createCube() {
const geometry = new BoxBufferGeometry(2, 2, 2);
// Switch the old "basic" material to
// a physically correct "standard" material
const material = new MeshStandardMaterial({ color: 'purple' });
const cube = new Mesh(geometry, material);
cube.rotation.set(-0.5, -0.1, 0.8);
return cube;
}
可以设置为你喜欢的值。现在它终于看起来像一个立方体,而不是一个正方形。
原文链接:http://www.bimant.com/blog/three-js-pbr-intro/
- 上一篇:图像颜色特征提取
- 下一篇:推荐50个超实用的 Chrome 扩展,建议收藏
相关推荐
- 荒野大镖客2游戏壁纸图片
-
...
- 巫师3:狂猎游戏壁纸图片
-
...
- 腾讯混元发布游戏视觉生成平台
-
5月20日,腾讯正式发布混元游戏视觉生成平台(简称“混元游戏”),这是依托混元大模型打造的首个工业级AIGC游戏内容生产引擎,大幅优化游戏资产生成与游戏制作流程。其面向游戏工业级内容生产,为游戏美术设...
- 腾讯混元游戏视觉生成平台发布,首个工业级AIGC游戏内容生产引擎
-
IT之家5月20日消息,腾讯混元团队刚刚宣布:腾讯混元游戏视觉生成平台(以下简称“混元游戏”)正式发布。这是首个工业级AIGC游戏内容生产引擎,大幅优化了游戏资产生成与游戏制作流程。据官方...
- 巫师3:狂猎 游戏壁纸图片
-
点个“关注”,我们一起看世界。...
- 【防诈宣传】检察官提醒您:警惕高考“分数游戏”,守护学子未来梦想!
-
亲爱的考生和家长们:随着高考的结束,相信每一位考生都期待着那激动人心的成绩公布时刻。然而,在这个特殊的时期,一些不法分子也趁机而动,利用考生和家长们的急切心理,炮制出各种“提前查分”“花钱改分”“低分...
- 让轻薄本也能玩转3A游戏和AI 当前主流核显到底什么水平
-
集成显卡和入门级独立显卡在过去的一段时间内可以说是拼的你死我活,但随着英特尔锐炬、AMDRadeonM的出现,以N卡为主的入门级独显被逐渐淘汰掉,其中最知名的莫过于MX350、MX450等,而现在...
- 通俗解读段位六合一 -游戏资讯-和平精英
-
我来个逗啊~新赛季冲战神的策略和玩法变了,刚刚和平精英官方发布了最新的段位和加分模式,很多同学们看的是一头雾水,今天学友哥一分钟帮大伙们通俗解读段位新赛季段位六合一,新加分机制和匹配模式对玩家的影响;...
- 永久死亡游戏哪些人气高 最新永久死亡游戏排行榜
-
探索游戏世界最炙手可热的秘境!最新永久死亡游戏排行榜揭示玩家心水之选。从生存挑战到硬核策略,这些人气之作带你领略不死不休的冒险体验。一窥究竟,哪款游戏能在生死边缘激起你的无尽热情?继续阅读,揭晓年度最...
- 第三十一篇 七巧板游戏
-
昨晚和爱人聊天,她说到他们学校培训部门开发了适合他们集团特色的七巧板拓展训练,让我回想起我们曾经也在一次拓展训练中进行过一次七巧板游戏,给我留下了极深印象,特别是随着这几年的复盘,我认为它超越我曾经参...
- 玩家愤怒源于期待落差!诛仙世界是创新还是换皮?
-
嘿,亲爱的小伙伴们,诛仙世界,你玩了吗?就算没玩过,这几天,我想你应该也听过这游戏的名字,无论是夸的还是喷的......好吧,大多数都是喷的。但不管怎么看,作为2024年问世的唯一一款纯PC端游,在这...
- 从3岁到99岁都能玩!扑克牌「天花板级」玩法攻略,速藏!
-
扑克牌的玩法种类繁多,不同地区和文化衍生出各具特色的规则。以下是一些常见且有趣的扑克玩法分类整理,供你参考:一、经典传统玩法1.斗地主-3人游戏,1位地主对抗2位农民,通过出牌速度和策略取胜。2....
- 小学成绩到底有没有实际意义?别让分数蒙住你的眼
-
家人们!刷到这条先别划走!今天咱必须唠唠这个让无数家长抓头发、学生心里打鼓的世纪难题——小学成绩到底有没有实际意义?有人拍着胸脯说“小学那点知识,到中学努努力就补回来了”,也有人愁得直叹气“孩子小学成...
- 游戏玩家吵了10年的问题,终于被我们测出了答案!
-
友友们大家来啦!今天来和大家一起分享精彩话题老规矩先点赞再看文!1.4090这显卡,贵得我心疼,但专业领域它就是王!2.3060和A3000L,比比看,谁才是视频编辑的王者?3.游戏画质这么高,黑...
- 3分钟玩转国服新实装的职阶星图分值系统 建议无脑强化狂阶打手
-
fgo国服这次的系统大规模的更新,引入了全新的系统,也就是所谓的职阶星图分值系统。对于这个系统,估计不少玩家没整明白到底是怎么回事,这次就来手把手的说明和解释一下,方便玩转这个新系统,包括该系统带来的...
- 一周热门
- 最近发表
- 标签列表
-
- HTML 简介 (30)
- HTML 响应式设计 (31)
- HTML URL 编码 (32)
- HTML Web 服务器 (31)
- HTML 表单属性 (32)
- HTML 音频 (31)
- HTML5 支持 (33)
- HTML API (36)
- HTML 总结 (32)
- HTML 全局属性 (32)
- HTML 事件 (31)
- HTML 画布 (32)
- HTTP 方法 (30)
- 键盘快捷键 (30)
- CSS 语法 (35)
- CSS 选择器 (30)
- CSS 轮廓宽度 (31)
- CSS 谷歌字体 (33)
- CSS 链接 (31)
- CSS 定位 (31)
- CSS 图片库 (32)
- CSS 图像精灵 (31)
- SVG 文本 (32)
- 时钟启动 (33)
- HTML 游戏 (34)