真实景观渲染技巧【Three.js】

news2024/9/22 21:27:22

受到一些很棒的 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 pattern
    float k = texture2D( uNoise, 0.005*uv ).x; // cheap (cache friendly) lookup

    // compute index
    float l = k*8.0;
    float f = fract(l);

    float ia = floor(l);
    float ib = ia + 1.0;

    // offsets for the different virtual patterns
    float v = 0.4;
    vec2 offa = sin(vec2(3.0,7.0)*ia); // can replace with any other hash
    vec2 offb = sin(vec2(3.0,7.0)*ib); // can replace with any other hash

    // compute derivatives for mip-mapping
    vec2 dx = dFdx(uv), dy = dFdy(uv);

    // sample the two closest virtual patterns
    vec3 cola = texture2DGradEXT( samp, uv + v*offa, dx, dy ).xyz;
    vec3 colb = texture2DGradEXT( samp, uv + v*offb, dx, dy ).xyz;

    // // interpolate between the two virtual patterns
    vec3 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

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

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

相关文章

AnLogicFPGA设计的时序约束及时序收敛

本篇博文讲了三个内容&#xff1a;时序约束基本概念、时序约束命令、时序收敛技巧 时序约束基本概念 时序设计的实质就是满足每一个触发器的建立&#xff08;setup&#xff09;时间和保持&#xff08;hold&#xff09;时间。 建立时间(Tsu) 触发器的时钟信号沿到来以前&…

零信任-新华三H3C零信任介绍(12)

​目录 ​新华三零信任是什么&#xff1f; 新华三零信任架构特点 新华三零信任架构 新华三零信任架构适用场景 新华三零信任的未来发展展望 新华三零信任是什么&#xff1f; 建立新边界 全面身份化。新华三贯彻“永不信任&#xff0c;始终验证”的原则&#xff0c;通过对…

JavaWeb7-线程状态(生命周期)及转换过程

目录 1.所有线程状态&#xff08;共6种&#xff09; ①NEW-新建状态 ②RUNNABLE-运行状态 RUNNABLE&#xff08;得到时间片运行中状态&#xff09; READY&#xff08;已经保存了上下文&#xff0c;但还未得到时间片的就绪状态&#xff09;。 ③BLOCKED-阻塞状态 ④WAITI…

使用NutUI创建小程序和H5界面

做开发的时间长了&#xff0c;技术都是通用的&#xff0c;创建小程序和H5界面有很多的UI&#xff0c;本章节演示使用NutUI来创建&#xff0c;官网&#xff0c;NutUI - 移动端 Vue3 小程序组件库 1.使用HBuilder X创建一个uni-app的程序&#xff0c;如图所示 2. 安装UniNutUI …

nvm的使用与坑

1、nvm 介绍 Node Version Manager - 符合 POSIX 标准的 bash 脚本&#xff0c;用于管理多个活动的 node.js 版本 官网为 nvm-windows&#xff0c;点击这里进行下载 2、使用场景 比如有几个项目&#xff0c;这些项目的需求都不太一样&#xff0c;导致了这些个项目需要依赖的…

论文投稿指南——中文核心期刊推荐(管理学)

【前言】 &#x1f680; 想发论文怎么办&#xff1f;手把手教你论文如何投稿&#xff01;那么&#xff0c;首先要搞懂投稿目标——论文期刊 &#x1f384; 在期刊论文的分布中&#xff0c;存在一种普遍现象&#xff1a;即对于某一特定的学科或专业来说&#xff0c;少数期刊所含…

多彩的声音-课后程序(JAVA基础案例教程-黑马程序员编著-第四章-课后作业)

【案例4-3】多彩的声音 记得 关注&#xff0c;收藏&#xff0c;评论哦&#xff0c;作者将持续更新。。。。 【案例介绍】 案例描述 设计和实现一个Soundable发声接口&#xff0c;该接口具有发声功能&#xff0c;同时还能调节声音大小。 Soundable接口的这些功能将由有3种声音…

【C++的OpenCV】第一课-opencv的介绍和安装(Linux环境下)

第一课-目录一、基本介绍1.1 官网1.2 git源码1.3 介绍二、OpenCV的相关部署工作2.1 Linux平台下部署OpenCV一、基本介绍 1.1 官网 opencv官网 注意&#xff1a;官网为英文版本&#xff0c;可以使用浏览器自带的翻译插件进行翻译&#xff0c;真心不推荐大家去看别人翻译的&am…

vue实现xml在线编辑功能

先看效果 避免误会 这是一个在线编辑器 我们可以在这上面随意的编写xml代码格式 我们修改上面的内容之后 就可以在控制台输出内容 如果这正是您想要的东西 那就可以先创建一个vue项目 我们先引入依赖 npm install brace -S npm install element-ui -S npm install vue-cli…

原型链污染

目录 前置知识 原型对象 prototype和__proto__的区别 原型链概念 原型链的继承 原型 链污染 原型链污染原理 javascript中可能会存在原型链污染的危险函数 原型链污染的实际应用 JavaScript中可以触发弹窗的函数 前置知识 原型对象 在JavaScript中&#xff0c;每个函…

9-静态链表及其有关操作

链表可以用malloc/new和结构体加指针的方式来实现&#xff0c;那种实现方式实现的链表又被称为动态链表。但是我们还可以利用数组的方式来实现一个链表&#xff0c;这种实现方式称为静态链表。 静态单链表 我们知道&#xff0c;一个链表节点主要由两大部分组成&#xff1a;数…

黑马Spring学习笔记(一)——IOC/DI核心概念、入门案例

目录 一、Spring系统架构和学习路线 二、Spring核心概念 2.1 IOC、IOC容器、Bean、DI 2.1.1 IOC&#xff08;Inversion of Control&#xff09;控制反转 2.1.2 DI&#xff08;Dependency Injection&#xff09;依赖注入 2.2 核心概念小结 三、入门案例 3.1 IOC入门…

【C++入门】引用、内联函数、auto关键字、基于范围的for循环(C++11)、指针空值nullptr(C++11)

文章目录引用引用概念引用特性引用使用场景常引用内联函数宏的优缺点&#xff1f;C有哪些技术替代宏&#xff1f;auto关键字auto不能推导的场景基于范围的for循环(C11)指针空值nullptr(C11)引用 引用概念 引用不是新定义一个变量&#xff0c;而是给已存在变量取了一个别名&…

一篇搞懂UnitTest

unittest单元测试框架是受到 JUnit 的启发&#xff0c;与其他语言中的主流单元测试框架有着相似的风格。其支持测试自动化、支持将测试样例聚合到测试集中&#xff0c;并将测试与报告框架独立开来。unittest模块是Python标准库中的模块。在此之前需要先了解几个概念&#xff1a…

linux高级命令之线程执行带有参数的任务

线程执行带有参数的任务学习目标能够写出线程执行带有参数的任务1. 线程执行带有参数的任务的介绍前面我们使用线程执行的任务是没有参数的&#xff0c;假如我们使用线程执行的任务带有参数&#xff0c;如何给函数传参呢?Thread类执行任务并给任务传参数有两种方式:args 表示以…

NTC热敏电阻

NTC热敏电阻&#xff1a; 负温度系数热敏电阻。 Negative Temperature Coefficient Thermistor 特性&#xff1a; 由锰 (Mn) 、镍 (Ni) 、钴 (Co) 等成分的氧化物烧制而成的陶瓷。阻值随温度上升而下降。 工作温度范围宽&#xff1a;一般的都可用于-40℃ to 125℃。有的高…

[Pytorch] Linear层输出nan

参考链接&#xff1a; https://discuss.pytorch.org/t/well-formed-input-into-a-simple-linear-layer-output-nan/74720/11 总结原因&#xff1a; numpy需要更新 PS. 查看numpy版本号 打开Anaconda Prompt 进入环境 输入命令conda activate envname 然后输入pip show numpy…

MongoDB 自动增长

MongoDB 自动增长 MongoDB 没有像 SQL 一样有自动增长的功能&#xff0c; MongoDB 的 _id 是系统自动生成的12字节唯一标识。但在某些情况下&#xff0c;可能需要实现 ObjectId 自动增长功能。而MongoDB 并没有提供这个功能&#xff0c;那么可以通过编程的方式来实现_id字段自…

Qt音视频开发14-音视频文件保存基类的设计

一、前言 视频综合应用示例&#xff0c;包括了多种内核&#xff0c;在保存文件这个功能上&#xff0c;需要一个通用的文件保存基类AbstractSaveThread&#xff0c;这个基类定义了是否打印线程消息标志位、直接写入还是排队写入标志位、文件生成后是否调用转换合并标志位、是否…

Linux下的Jenkins安装教程

当前环境 CentOS 7.8Java 11&#xff08;注意当前jenkins支持的Java版本最低为Java11&#xff09;FinalShell 3.9&#xff08;操作环境&#xff09; 安装Jenkins PS&#xff1a;不建议使用Docker安装Jenkins&#xff0c;因为使用Jenkins的时候一般会调用外部程序&#xff0c;…