真实景观渲染技巧【Three.js】
受到一些很棒的 three.js 演示、与 covid 相关的旅行禁令以及可能在 pinterest 上花太多时间看美丽的旅行照片的启发——我开始看看我是否可以使用 three.js 和r3f在浏览器中渲染一个令人信服的风景场景。
推荐:将 NSDT场景编辑器 加入你的3D开发工具链。
在过去一个月左右的时间里,我一直在尝试不同的方法,并在互联网上搜索有关如何使用浏览器技术渲染半现实景观的技巧。 我发现它很有价值,但也比我预期的要难得多。
我整理了一份简短指南,总结了我从 A 到 B 所使用的技巧和技巧:
TLDR:
我使用特定于地形的自定义实用程序扩展了 three.js 标准材质。 这种经过修改的材质使用多种纹理来为地形着色、塑造和照亮地形。 我对这些纹理中的一些进行平铺和分层,以确保地形在更大的观看距离范围内看起来不错。
我选择从一个名为 world creator 的图形用户界面生成和导出地形数据。在线演示可以访问这里,源码托管在GitHub。
1、技术
我将这篇文章结构化为我用来改进渲染的技术列表,而不是冗长的教程。 对于每一种技术,我都会提供一个简短的描述,如果你不熟悉它,这应该可以帮助你定位。 我还将提供一个提示/技巧部分,该部分应该阐明我如何在示例场景中使用该技术。 我希望这将使它对不同技能水平的人更容易浏览和有用。
动机限制:
- 你的几何图形越多,gpu 必须做的工作就越多。 如果没有尖端的几何虚拟化技术,在当前的硬件上不可能以 100% 的保真度实时渲染地形大小的对象。
- 我们可以在合理时间内下载的纹理大小有限制
- 可以使用 webGL 移动到 gpu 内存中的纹理纹理的大小是有限制的。 在旧手机上它可以低至 1024x1024
- webGL 允许你在单个对象上使用的纹理数量有限制(16)
工具:
- React(抱歉我忍不住)
- Three.js(很棒的3d渲染库)
- React-three-fiber(让你在 jsx 中使用 three.js)
- World Creator(用于制作渲染场景所需的各种纹理)
React + r3f 并不是绝对必要的,但将这些概念应用到 vanilla three.js 设置中应该很容易。 另请注意,World creator 不是免费的,但有很多替代方法可以生成高度图等。
2、高度/位移图
高度图将地形的垂直高度编码为从 0(黑色)到 1(白色)的像素值。 Three.js 内置处理位移的代码(顶点着色器)。 位移贴图(displacement map)可用于 3d 对象,但对于风景,我只使用了一个简单的平面。 最主要的是确保你的比例与生成高度图的任何程序或工具相匹配。 可以使用 displacementScale 和 displacementBias 来使 three.js 的比例匹配。
高度图是这样的图像:
提示:对于高度图中的每个像素,你至少需要对平面进行一次细分,否则three.js 着色器将不会有一个关联的顶点来定位。
技巧:除非相机靠近地面,否则高度图不需要特别高分辨率。 在上面的示例中,我使用了 1024*1024 高度图。 使地形看起来不错的大部分细节都来自法线贴图和漫反射贴图。
限制:2d 高度图无法表示 3d 地形细节,如洞穴或悬垂。
3、大气雾
过度简化天空“是蓝色的”,所以当你看它实际上把它背后的东西染成蓝色。 雾在 three.js 场景中是一种常见的技术,但它在风景中尤为重要,因为它可以帮助观众理解山丘、树木等的规模和排列:
<fog attach="fog" args={["#74bbd0", 300, 1800]} />
注意:使用的材质需要知道如何正确渲染雾。 如果你不扩展 three.js 材质,这将不会自动工作。
4、HDRI 照明
HDRI(高动态范围图像)是一种环绕场景的大纹理,可作为 PBR 材质的更逼真光源。 我喜欢光线具有更自然的方向和颜色,但找到适合我的场景的光线有点费力。 也就是说,我认为这是值得的,因为照明设置是对场景质量和气氛影响最大的因素之一。
// I used the Environment component from Drei with one of the preset HDRIs
import { Environment } from "@react-three/drei"export default Landscape(){return (// landape mesh ect...// hdri<Environment preset="park" />)
}
提示:
- polyhaven 是 HDRI 的重要来源网站。
- 尝试使用不同的 HDRI 和环境光级别。
技巧:尝试使用标准网格材质的 normalScale、 envMapIntensity 和 metalness 参数。 它们使你可以对对比度、颜色深度和亮度进行大量控制。
5、SPLAT纹理
对于大多数 3d 对象,我们使用称为漫反射纹理的单一纹理来应用颜色。 如果我们放大到接近地形大小的对象,这很快就会崩溃,因为每次将其尺寸加倍时,图像的文件大小/内存影响不会线性缩放。 在地形大小的对象上应用单个漫反射纹理会变得模糊或过大。
从逻辑上讲,我们应该能够通过混合和重复多个较小的纹理来解决这个问题,每个纹理对应一种地形类型(草地、泥地、岩石等)。
纹理splat是一种方法。 它的工作原理是获取多个纹理并将它们与另一个称为 splat 纹理的纹理中的颜色通道相关联。 splat 纹理中的一个像素被渲染为 100x100 图像 - 取决于我们的纹理大小和它们重复的次数 - 使得 splat 纹理明显小于相同细节级别的漫反射纹理。
这是 splat 纹理:
例如,如果 splat 中的像素是纯红色,那么我们将该区域渲染为泥土,如果它是纯绿色,则将其渲染为草地,如果它是红色和绿色的混合,那么我们可以线性组合瓷砖纹理的 rgb 值以 更自然地融合在草地和泥泞地区之间。 混合对于防止它看起来像 Minecraft 地图至关重要。
// inside the main function of the fragment shader ...
vec4 diffuse1 = texture2D(uDiffuse1, uv * 100.0);
vec4 diffuse2 = texture2D(uDiffuse2, uv * 100.0);
vec4 splat1 = texture2D(uSplat1, uv);vec4 color = diffuse1 * splat1.r + diffuse2 * splat1.g;diffuseColor = vec4( color.rgb, opacity );
提示:World creator 以 TGA 格式导出 splat 纹理,我以前从未听说过这种格式,并且发现使用起来有些困难,但幸运的是,Three.js 示例包含一个 TGA 加载器,可以处理将 .tga 文件加载到数据纹理中。
局限性:纹理平铺会导致明显的纹理重复,我们将在下面解决:
6、隐藏纹理重复
虽然这样做很容易,但没有什么要求我们将纹理放置在会产生不良平铺效果的网格图案类型中。 Inigo Quilez 有一篇关于修复纹理重复的多种方法的好文章,我在我的场景中使用了它。
简单的说,该技术本质上归结为使用随机噪声纹理和一些数学来更有机地在网格表面上无缝地放置和混合纹理。
// use instead of texture2D
vec4 textureNoTile( sampler2D samp, vec2 uv ){// sample variation patternfloat k = texture2D( uNoise, 0.005*uv ).x; // cheap (cache friendly) lookup// compute indexfloat l = k*8.0;float f = fract(l);float ia = floor(l);float ib = ia + 1.0;// offsets for the different virtual patternsfloat v = 0.4;vec2 offa = sin(vec2(3.0,7.0)*ia); // can replace with any other hashvec2 offb = sin(vec2(3.0,7.0)*ib); // can replace with any other hash// compute derivatives for mip-mappingvec2 dx = dFdx(uv), dy = dFdy(uv);// sample the two closest virtual patternsvec3 cola = texture2DGradEXT( samp, uv + v*offa, dx, dy ).xyz;vec3 colb = texture2DGradEXT( samp, uv + v*offb, dx, dy ).xyz;// // interpolate between the two virtual patternsvec3 col = mix( cola, colb, smoothstep(0.2,0.8,f-0.1*sum(cola-colb)) );return vec4(col,1.0);
}
7、法线贴图
他们让我们在给定点对表面的“正常”角度进行编码。 这有点 hack,但它有助于确定从该物体反射到相机的光量,使我们能够平滑或创建额外的细节,而无需渲染额外的三角形。 同样,这是 THREE.js 物理材质中内置的内容。
提示:在岩石等细节物体上使用法线贴图比使用你能找到的最高分辨率漫反射纹理重要得多。
8、多层次的法线
World Creator 导出整个地形的法线贴图,但也导出我们在景观中平铺的岩石纹理的法线贴图:
理想情况下,场景将受益于宏观悬崖面法线以及水平法线的更细微的凹凸和裂缝。 不幸的是,如果只是将法线纹理添加在一起,它们会变得浑浊和/或在某些地方会出现超级亮点或暗点。
Stephen Hill 对问题和可能的解决方案有很好的总结 , 它给着色器增加了一些复杂性,但在我看来这是值得的:
// adapted from original article so more than two normals can be blended
vec4 blend_normals(vec4 n1, vec4 n2){vec3 t = n1.xyz*vec3( 2, 2, 2) + vec3(-1, -1, 0);vec3 u = n2.xyz*vec3(-2, -2, 2) + vec3( 1, 1, -1);vec3 r = t*dot(t, u) /t.z -u;return vec4((r), 1.0) * 0.5 + 0.5;
}//usage:
vec4 blend = blend_normals(n1, n2);
vec4 triblend = blend_normals(blend, n3);
提示:当以不同的比例重复时,使用多个法线往往效果最好。 尽管上述技术在数学上比简单的线性组合更正确,但我发现应用多个相同大小的法线最终看起来就像随机噪声。 在演示岩石中,我使用一个大的用于景观细节,一个中等的用于岩石中的峭壁,一个小的用于额外的凹凸纹理。
9、未来的改进
实施基于四叉树的细节系统和纹理流以在相机附近渲染更高清晰度的纹理可以提高质量并减少初始加载时间。
用于渲染摇曳的草地或渲染摄像机附近的苔藓的植被系统也有助于提高场景的保真度,使你可以使用第三人称控制器在地图上四处走动。
原文链接:Three渲染真实景观 — BimAnt
相关文章:

真实景观渲染技巧【Three.js】
受到一些很棒的 three.js 演示、与 covid 相关的旅行禁令以及可能在 pinterest 上花太多时间看美丽的旅行照片的启发——我开始看看我是否可以使用 three.js 和r3f在浏览器中渲染一个令人信服的风景场景。 推荐:将 NSDT场景编辑器 加入你的3D开发工具链。 在过去一个…...

MySQL知识汇总:MySQL函数CASE WHEN用法详解
Case When的两种简单用法 用法一: CASE seasonWHEN Spring THEN 春天 WHEN Summer THEN 夏天 WHEN autumn THEN 秋天 else 冬天 end 用法二: CASE WHEN season Spring THEN 春天WHEN season Summer THEN 夏天WHEN season autumn THEN 秋天 els…...

Python学习-----模块1.0(模块的简介、定义与使用)
目录 前言: 1.什么是模块 2.模块的分类 (1)内置模块 (2)第三方模块 (3)自定义模块 3.模块的使用 4.自定义模块 5.模块和执行文件的判断 前言: 今天就开始讲Python中的模块篇…...

Linux进程学习【二】
✨个人主页: Yohifo 🎉所属专栏: Linux学习之旅 🎊每篇一句: 图片来源 🎃操作环境: CentOS 7.6 阿里云远程服务器 Perseverance is not a long race; it is many short races one after another…...
我问chatGPT,在JavaScript中构造函数和类的区别
问:构造器函数和面向中的类是同样的东西吗|? 答:构造器函数和面向对象中的类并不是同样的东西,它们之间有些许不同。 在面向对象编程中,类是一种抽象的概念,它描述了一类具有相同属性和行为的对象。类可以…...

软考高级-信息系统管理师之沟通管理(最新版)
项目沟通管理 1、项目沟通管理基础项目沟通管理的重要性项目沟通管理相关理论2、规划沟通管理3、管理沟通4、控制沟通项目沟通管理的技术和工具1、项目沟通管理基础 项目沟通管理的重要性 1、与1T项目成功有关的最重要的四个因素是:主管层的支持、用户参与、有经验的项目经理…...

PyQt5 自定义富文本编辑器
介绍 一款使用PyQt5和网页端框架wangEditor集成的富文本编辑器 代码片段 PyQt5客户端 与网页端建立连接def create_connect(self):self.web_view QWebEngineView()self.bridge JSBridge(self.web_view.page())self.web_view.load(QUrl.fromLocalFile(self.editor_path))w…...

【高可用系统架构设计】SLA服务可用性4个9是什么意思?如何保证服务的高可用性 HA(High Availability)?...
如何保证服务的高可用性 HA(High Availability)?高可用HA(High Availability)是分布式系统架构设计中必须考虑的因素之一,它通常是指,通过设计减少系统不能提供服务的时间。方法论上,高可用是通…...
微服务架构设计模式-(14)面向生产环境
生产环境要求 应用安全 数据权限 服务可配置性 不同环境的配置不一样,不能写死代码,所以要配置 可观测性 需要日志系统 应用安全 四个方面 身份验证 验证主体的身份解决方案 单体 cookie 微服务中 API Gateway 访问令牌 不透明令牌透明令牌ÿ…...
HTML5新增用法
新增语义化标签 并无特殊含义,是语义!语义!语义! <header> 头部区域 <nav> 导航区域 <main> 主体区域 <article> 内部标签 <section> 块级标签 <aside> 侧边栏标签 <footer> 尾部…...

富足金字塔:人的努力是为了扩大选择的范围
人的努力是为了扩大选择的范围,这是熵减的另一种表述。富足金字塔代表着人生的三重境界。第一层是温饱。人需要食物、水、住所。第二层是品质。能源、ICT、教育带来更有品质的生活,如智能门锁、智能马桶、扫地机、洗碗机、洗衣烘衣机。第三层是梦想。包括…...

C++类基础(十七)
类的继承——补充知识 ● public 与 private 继承(C Public, Protected and Private Inheritance) 改变了类所继承的成员的访问权限 //公有继承 struct Base { public:int x; private:int y; protected:int z; }; struct Derive : public Base //公有继承…...

LeetCode刷题复盘笔记—一文搞懂贪心算法之56. 合并区间(贪心算法系列第十四篇)
今日主要总结一下可以使用贪心算法解决的一道题目,56. 合并区间 题目:56. 合并区间 Leetcode题目地址 题目描述: 以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] [starti, endi] 。请你合并所有重叠的区间…...

Andriod入门级开发
这学期有个课设,我们组我负责一个手机APP的开发,虽然刚开始说要实现什么智能导航,类似高德地图那种,但最后阉割的只剩一个Socket通信了,因为之前没有接触过(可能之后也不会再接触),记…...

DCL 数据控制语言
1、简介 DCL英文全称是Data Control Language(数据控制语言),用来管理数据库用户、控制数据库的访问权限。 2、管理用户 2.1 查询用户 select * from mysql.user;查询的结果如下: 其中 Host代表当前用户访问的主机, 如果为localhost, 仅代表只能够在当前本机访问…...

全网超详细的下载与安装VMware虚拟机以及为什么要安装VMware虚拟机
文章目录1. 文章引言2. 下载VMware3. 安装VMware1. 文章引言 我们使用最多的系统是windows系统,因为,国内电脑厂商的操作系统(os)基本是windows系统,比如华为、联想、华硕等电脑。 但线上的服务器大多是Linux系统,而我们经常使用…...

Python获取zabbix问题触发器
背景:阿里云的ECS服务器因为阿里云升级插件,导致安全防护程序重启,产生不同的端口。导致低自动发现注册的端口 大量报警。 解决:杀掉关于因为非业务 变更的端口检测的触发器。 相关文档: Zabbix监控之主机端口监控自…...

原型链污染
目录 前置知识 原型对象 prototype和__proto__的区别 原型链概念 原型链的继承 原型 链污染 原型链污染原理 javascript中可能会存在原型链污染的危险函数 原型链污染的实际应用 JavaScript中可以触发弹窗的函数 前置知识 原型对象 在JavaScript中,每个函…...
ClickHouse详解
一、概念ClickHouse是一个用于联机分析(OLAP)的列式数据库管理系统(DBMS)。OLAP场景的关键特征绝大多数是读请求数据以相当大的批次(> 1000行)更新,而不是单行更新;或者根本没有更新。已添加到数据库的数据不能修改。对于读取,从数据库中提取相当多的…...
02_Docker 安装
02_Docker 安装 文章目录02_Docker 安装2.1 安装 Docker 的先决条件2.2 在 Ubuntu 和 Debain 中安装 Docker2.2.1 检查前提条件1. 内核2.检查 Device Manager2.2 安装 DockerDocker 支持非常多的Linux平台,包括Ubuntu和RHEL,除此之外,Docker还…...

idea大量爆红问题解决
问题描述 在学习和工作中,idea是程序员不可缺少的一个工具,但是突然在有些时候就会出现大量爆红的问题,发现无法跳转,无论是关机重启或者是替换root都无法解决 就是如上所展示的问题,但是程序依然可以启动。 问题解决…...

《Qt C++ 与 OpenCV:解锁视频播放程序设计的奥秘》
引言:探索视频播放程序设计之旅 在当今数字化时代,多媒体应用已渗透到我们生活的方方面面,从日常的视频娱乐到专业的视频监控、视频会议系统,视频播放程序作为多媒体应用的核心组成部分,扮演着至关重要的角色。无论是在个人电脑、移动设备还是智能电视等平台上,用户都期望…...
MySQL 隔离级别:脏读、幻读及不可重复读的原理与示例
一、MySQL 隔离级别 MySQL 提供了四种隔离级别,用于控制事务之间的并发访问以及数据的可见性,不同隔离级别对脏读、幻读、不可重复读这几种并发数据问题有着不同的处理方式,具体如下: 隔离级别脏读不可重复读幻读性能特点及锁机制读未提交(READ UNCOMMITTED)允许出现允许…...

el-switch文字内置
el-switch文字内置 效果 vue <div style"color:#ffffff;font-size:14px;float:left;margin-bottom:5px;margin-right:5px;">自动加载</div> <el-switch v-model"value" active-color"#3E99FB" inactive-color"#DCDFE6"…...

RNN避坑指南:从数学推导到LSTM/GRU工业级部署实战流程
本文较长,建议点赞收藏,以免遗失。更多AI大模型应用开发学习视频及资料,尽在聚客AI学院。 本文全面剖析RNN核心原理,深入讲解梯度消失/爆炸问题,并通过LSTM/GRU结构实现解决方案,提供时间序列预测和文本生成…...
iOS性能调优实战:借助克魔(KeyMob)与常用工具深度洞察App瓶颈
在日常iOS开发过程中,性能问题往往是最令人头疼的一类Bug。尤其是在App上线前的压测阶段或是处理用户反馈的高发期,开发者往往需要面对卡顿、崩溃、能耗异常、日志混乱等一系列问题。这些问题表面上看似偶发,但背后往往隐藏着系统资源调度不当…...
Java毕业设计:WML信息查询与后端信息发布系统开发
JAVAWML信息查询与后端信息发布系统实现 一、系统概述 本系统基于Java和WML(无线标记语言)技术开发,实现了移动设备上的信息查询与后端信息发布功能。系统采用B/S架构,服务器端使用Java Servlet处理请求,数据库采用MySQL存储信息࿰…...

招商蛇口 | 执笔CID,启幕低密生活新境
作为中国城市生长的力量,招商蛇口以“美好生活承载者”为使命,深耕全球111座城市,以央企担当匠造时代理想人居。从深圳湾的开拓基因到西安高新CID的战略落子,招商蛇口始终与城市发展同频共振,以建筑诠释对土地与生活的…...
多模态图像修复系统:基于深度学习的图片修复实现
多模态图像修复系统:基于深度学习的图片修复实现 1. 系统概述 本系统使用多模态大模型(Stable Diffusion Inpainting)实现图像修复功能,结合文本描述和图片输入,对指定区域进行内容修复。系统包含完整的数据处理、模型训练、推理部署流程。 import torch import numpy …...
OD 算法题 B卷【正整数到Excel编号之间的转换】
文章目录 正整数到Excel编号之间的转换 正整数到Excel编号之间的转换 excel的列编号是这样的:a b c … z aa ab ac… az ba bb bc…yz za zb zc …zz aaa aab aac…; 分别代表以下的编号1 2 3 … 26 27 28 29… 52 53 54 55… 676 677 678 679 … 702 703 704 705;…...