《Time Ghost》的制作:使用 DOTS ECS 制作更为复杂的大型环境
*基于 Unity 6 引擎制作的 demo 《Time Ghost》
开始《Time Ghost》项目时的目标之一是提升在 Unity 中构建大型户外环境的构建标准。为了实现这一目标,我们要有处理更为复杂的场景的能力、有足够的工具支持,同时它对引擎的核心图形、光照、后处理、渲染和性能也提出了更高的要求。虽然我们能够预见到 Unity 6 的图形改进能满足大部分需求,但工具方面仍面临挑战。
随着游戏世界变得越来越复杂,高效的工具对于管理自然资产的放置和渲染变得至关重要。我们需要一个智能系统来确保环境资产的真实分布与多样性。同时,由于计划使用大量的植被,因此渲染方面的技术解决方案,既要具备扩展性,也要在运行时保持较高的性能。
本文将分享构建《Time Ghost》场景环境中的一些做法,并解析我们所用的工作流程和工具。
生成散布数据
第一步,我们将构成环境基础的网格导入 DCC 软件(本例中是 Houdini)。这些网格可以是激光雷达(LiDAR)扫描、无人机扫描或在 Unity 中手动雕刻的地形。对于 Houdini,我们开发了散布分析工具。这些工具可以根据地形属性自动放置资产,帮助我们设计和生成细节丰富、多种多样的连贯的逼真环境。
此外,通过采用 SpeedTree 和标准摄影测量工作流程,我们还创建了高质量的植被预制件并将其散布在网格上。散布系统允许对随机性和密度进行微调,确保植被的自然分布和多样性。
接下来,我们将散布数据从 Houdini 导出为点缓存/点云,使用的是 Unity 在 GitHub 上提供的 VFX Toolbox 中的 Point Cache Exporter HDA 稍加改动的版本。这个工具可以保存每个散布实例的位置,同时保存其缩放、方向、颜色、年龄和健康属性,并为散布数据中的每种模型生成一个点缓存。
Unity 集成
利用 DOTS(面向数据技术栈)和 ECS(实体组件系统),我们可以创建包含成千上万个实体的场景,同时保持性能稳定。这是通过实体实例化和资源分配的精细管理实现的。
每个从 Houdini 导出的点云资产实际上只是由位置、方向、缩放等信息组成的集合,可能还包括一些额外的数据(例如年龄、健康状况、颜色等)。我们将所有 Houdini 导出的点云汇集到一个名为 PointCloudFromHoudiniAsset 的资源中。这个资源读取原始点云,根据命名规则找到要与每个点云搭配的预制件,并创建数据的内部表示形式。这些数据被存储在 PointCloudFromHoudiniAsset 中,随后在烘焙过程中被划分为多个空间分区,以便更快速地进行数据流式加载。
下一步是在 ECS 子场景中添加一个创作组件(authoring component),名为 ScatterPointCloudAuthoring。该组件将 PointCloudFromHoudiniAsset 和一些参数作为输入数据,这些参数可用于控制何时加载和卸载数据,以及如何对点云数据进行细分。
为了高效地流式传输数据,我们将点云数据细分为场景区块(scene sections),这些区块可以单独加载和卸载。这样,我们就可以根据距离视角的远近来加载和卸载不同的区块。区块的大小由创作组件中的 ScatterSceneSectionSize 属性控制。
然而,这些场景区块相对较大,如果一次性实例化所有数据,将导致 CPU 负载骤增。每个场景区块可能包含数十万个点,因此,这些区块会进一步细分为更小的图块(tile),称为“散布图块”(由创作组件中的 ScatterTileSize 属性控制)。实例化逻辑会根据重要性规则,选择接下来需要实例化的散布图块以及需要卸载的图块。
图块替身
即便可以高效地流式加载和卸载实例,我们依然面临需要渲染大量实例的问题。许多实例的体积较小,如草丛,在远处移动时仅覆盖屏幕的小块区域。因此,我们将部分散布实例烘焙为图块替身(tile impostor)。图块替身覆盖特定区域,并模仿该区域散布实例的外观。
数据直接从点云资产中获取,因为我们希望控制图块包含的植被类型。在本例中,我们仅关注草地资产,忽略同一区域内的树木。
图块替身(tile impostor)生成器从上方渲染属于该图块的所有实例,生成包含每个图块的近似颜色、法线和深度信息的低分辨率纹理。此外,一些最重要的植物类型被选中并从侧面和上方渲染到图集上。这个图集被所有图块共享,并用于为每个图块的低分辨率纹理数据生成细节。生成器还创建了一个由多个四角面组成的网格,代表图块并让四角面朝向视角。
在运行时,我们将每个图块的低分辨率纹理信息与更详细但通用的植被纹理集条目,投射到图块替身网格上,从而生成图块的近似外观。
随着摄像机逐渐远离某个区域,单个实例首先会切换到较低的细节级别(LOD),最终被图块替身所取代。图块替身也有多个细节级别,随着摄像机进一步远离,四角面的分布会变得更为稀疏。
提升大型场景性能的替身系统
对于场景中非常远的对象,我们使用八面体替身(octahedral imposters)。这种方法可以显示距离摄像机较远物体的简化版本,从而在视觉效果与性能之间取得平衡。我们开发了一个简单的工具,可以直接在 Unity 中生成并集成这些替身。这个工具简化了工作流程,提供了优化性能的同时保持高视觉标准的高效方法。
植被控制系统
我们的植被控制系统提供了复杂的配置设置,可以调整风速、风的变化和频率等环境效果,确保环境中动画元素的真实感和性能。
植被着色器接收健康和年龄属性,用以实现自然的颜色变化和更真实的风相应效果。比如,一株干燥的植物会更僵硬,摆动幅度小于绿色的植物。
场景中的实体也经过设计,可与角色进行逼真的交互。例如,植被会对角色的存在和移动做出动态响应。这个系统采用基于 GPU 的方法来处理与植被的交互(如碰撞),并通过简化的弹簧物理(spring physics)来计算和模拟角色与环境元素交互的效果。
高质量的环境光照
自适应探针体积(APV)
为了获得高质量的光照效果,场景通常需要在不同区域使用不同的光照设置。对于光线会在各种不规则表面上反弹的狭小空间,和光照相对均匀的开阔平原上,往往需要采用不同的处理方法。
Unity 6 引入了新的“自适应探针体积”功能,它会自动在最需要光照探针的地方放置探针。
(注:通过可视化工具展示光照探针的位置时,可以明显看出壕沟里的探针比平原上的更密集,可以捕捉到更为细致的光照变化。)
场景混合
场景混合(Scenario Blending)让我们可以烘焙不同的光照设置状态,并在这些状态之间进行平滑过渡。
这样就可以为同一环境的不同时间创建不同的光照场景。太阳角度和环境色的变化可以通过实时光照来实现,而烘焙的光照场景让间接光照也能够相匹配。
接下来的计划
在当今先进的数字环境创建中,实现大量自然资源的自然连续分布和光照处理(无论是细致的近景还是宽广的远景,)都是至关重要的。基于ECS的处理方法不仅提升了画面质量,还在数据处理和解读方面提供了极大的灵活性,同时考虑了大型实时3D项目的性能需求。
我们已经在 Unity Asset Store 中发布了《Time Ghost》demo 的两个 Unity 项目——一个是环境场景,另一个是角色。如果你想亲自体验上述流程的效果,可以下载《Time Ghost: Environment》项目,其中包含我们用 Unity 6 为《Time Ghost》创建的一个环境场景。
https://assetstore.unity.com/packages/essentials/tutorial-projects/time-ghost-environment-298911
示例旨在展示我们使用的技术和方法,帮助你评估是否可以将类似的思路应用到自己的项目中。
相关文章:

《Time Ghost》的制作:使用 DOTS ECS 制作更为复杂的大型环境
*基于 Unity 6 引擎制作的 demo 《Time Ghost》 开始《Time Ghost》项目时的目标之一是提升在 Unity 中构建大型户外环境的构建标准。为了实现这一目标,我们要有处理更为复杂的场景的能力、有足够的工具支持,同时它对引擎的核心图形、光照、后处理、渲染…...

详细描述一下 Elasticsearch 更新和删除文档的过程。
1、删 除 和 更 新 也 都 是 写 操 作 , 但 是 Elasticsearch 中的 文 档 是 不 可 变 的 , 因 此 不 能被 删 除 或 者 改 动 以 展 示 其 变 更 ; 2、磁盘 上 的 每 个 段 都 有 一 个 相 应 的 .del 文件 。当删 除 请 求 发 送 后 &#…...

OpenCV与Qt5开发卡尺找圆工具
文章目录 前言一、卡尺原理二、1D边缘提取三、圆拟合四、软件实现结束语 基于OpenCV与Qt5构建卡尺找圆工具 前言 博主近期基于海康Vision Master4.0做了一个工业视觉工程项目,其中就使用到了海康VM的找圆工具,然后博主根据其中的技术原理,也…...

【网络安全】Web Timing 和竞争条件攻击:揭开隐藏的攻击面
Web Timing 和竞争条件攻击:揭开隐藏的攻击面 在传统的 Web 应用中,漏洞的发现和利用通常相对容易理解。如果代码存在问题,我们可以通过发送特定输入来强制 Web 应用执行非预期的操作。这种情况下,输入和输出之间往往有直接关系&…...

分立器件---运算放大器关键参数
运算放大器 关键参数 1、供电电压:有单电源电压、双电源电压,双电源电压尽量两个电源都接。如图LM358B,供电电压可以是20V或者是40V和GND。 2、输入偏置电流IB:当运放输出直流电压为零时,运放两个输入端流进或者流出直流电流的平均值。同向输入端电流IB+与反向输入端电流…...

Stable Diffusion Controlnet常用控制类型解析与实战课程 4
本节内容,是stable diffusion Controlnet常用控制类型解析与实战的第四节课程。上节课程,我们陆续讲解了几个与图像风格约束相关的控制类型,本节课程我们再学习一些实用价值较高的控制类型,看一看他们提供了哪些控制思路。 一&…...

Linux 本地编译安装 gcc9
这里演示非sudo权限的本地linux 用户安装 gcc9 下载源代码: 可以从GCC官方网站或其镜像站点下载GCC 9的源代码压缩包。使用wget或curl命令,这通常不需要额外权限 wget https://ftp.gnu.org/gnu/gcc/gcc-9.5.0/gcc-9.5.0.tar.gz tar -xf gcc-9.5.0.tar…...

SpringBoot 自定义事件
在Spring Boot中,自定义事件和监听器是一种强大的机制,允许你在应用程序的不同部分之间进行解耦通信。你可以定义自定义事件,并在需要的时候发布这些事件,同时让其他组件通过监听器来响应这些事件。 以下是如何在Spring Boot中创…...

unity shader中的逐像素光源和逐顶点光源
在Unity Shader中,逐像素光源和逐顶点光源是两种不同的光照计算方法,它们之间存在显著的区别。 一、基本原理 逐顶点光源:这种方法在顶点着色器中计算每个顶点的光照值。然后,在片段着色器中,通过插值算法将这些顶点…...

MongoDB-副本集
一、什么是 MongoDB 副本集? 1.副本集的定义 MongoDB 的副本集(Replica Set)是一组 MongoDB 服务器实例,它们存储同一数据集的副本,确保数据的高可用性和可靠性。副本集中的每个节点都有相同的数据副本,但…...
【图像处理lec7】图像恢复、去噪
目录 一、图像退化与恢复概述 二、图像退化中的噪声模型 1、使用 imnoise 函数添加噪声 (1)imnoise 函数的概述 (2)函数语法 (3)支持的噪声类型与具体语法 (4)噪声类型的详细…...

C# 连接ClickHouse 数据库
在 C# 中连接 ClickHouse 数据库,您可以使用 ClickHouse.Client 库。这个库提供了对 ClickHouse 数据库的高效访问。以下是详细的步骤指南,帮助您在 C# 项目中连接和操作 ClickHouse 数据库。 1. 安装 ClickHouse.Client 包 首先,您需要在您…...

在安卓Android应用中实现二维码图像的保存与条形码文本合并
在开发Android应用时,我们经常需要处理图像和文本数据,特别是当涉及到二维码生成和条形码信息展示时。本文将介绍如何在Android应用中实现一个功能,即将二维码图像保存到设备存储,并在图像下方添加条形码文本信息。为了实现这一功…...

Vue3 重置ref或者reactive属性值
需要重新定义一个对象绑定复制给原对象 。 实例代码: const data () > ({groupId: ,groupCode: ,groupName: ,groupType: ,});const formData ref(data());//重置对象值 const reset()>{Object.assign(formData, data()…...

深入理解STL list erase
1、list erase后,当前的迭代器失效,返回指向下一个节点的迭代器 #include<list> #include<iostream> #include<vector> using namespace std;int main() {list<int> ls;ls.push_back(1);ls.push_back(2);ls.push_back(3);list&…...

使用 Python 从 ROS Bag 中提取图像:详解与实现
在机器人应用中,ROS (Robot Operating System) 是一个常见的框架。ROS Bag(rosbag)是 ROS 中用于记录和回放数据流(例如传感器数据、话题消息等)的一种强大工具。有时,我们需要将存储在 rosbag 文件中的图像…...

MYSQL执行一条update语句,期间发生了什么
客户端先通过连接器建立连接,连接器自会判断用户身份; 因为这是一条 update 语句,所以不需要经过查询缓存,但是表上有更新语句,是会把整个表的查询缓存清空的,所以说查询缓存很鸡肋,在 MySQL 8…...

前端性能优化思路
前端性能优化需要从多方面入手,包括减少资源加载时间、优化页面渲染、利用浏览器缓存、使用CDN加速,服务端渲染和预渲染、性能监控和分析。需要综合运用这些优化策略才能显著提升网页或应用的性能和用户体验 一、减少资源加载时间 1. 代码分割 原理: 代码分割允许我们将代…...

有向图判环(leetcode207,leetcode210)
有向图判环(leetcode207,leetcode210) 有向图判环 #include <iostream> #include <vector> using namespace std;struct graph {int V; // 顶点的数量vector<vector<int>> adj; // 邻接表数组…...

概率论得学习和整理25:EXCEL 关于直方图/ 频度图 /hist图的细节,2种做hist图的方法
目录 1 hist图的特点 2 hist的设置技巧:直接生成的hist图往往很奇怪不好用:因为横轴的分组不对 3 如何修改分组 4 设置开放边界,把长尾合并,得到hist图1 5 用原始表得到频数表 6 用上面的频数图做柱状图,再修改&…...

PHP8.4下webman直接使用topthink/think-orm
环境信息 操作系统win11php 8.4.1webman-framework ^1.6.8MySQL 8.4.3topthink/think-orm ^3.0 说明 PHP8.3以下版本 直接使用webman提供的webman/think-orm更方便。 PHP 环境换为 8.4 使用webman/think-orm 报了个错;所以换topthink/think-orm,根据文…...

【从零开始入门unity游戏开发之——C#篇04】栈(Stack)和堆(Heap),值类型和引用类型,以及特殊的引用类型string,垃圾回收( GC)
文章目录 知识回顾一、栈(Stack)和堆(Heap)1、什么是栈和堆2、为什么要分栈和堆3、栈和堆的区别栈堆 4、总结 二、值类型和引用类型1、那么值类型和引用类型到底有什么区别呢?值类型引用类型 2、总结 三、特殊的引用类…...

基于微信小程序的小区疫情防控ssm+论文源码调试讲解
第2章 程序开发技术 2.1 Mysql数据库 为了更容易理解Mysql数据库,接下来就对其具备的主要特征进行描述。 (1)首选Mysql数据库也是为了节省开发资金,因为网络上对Mysql的源码都已进行了公开展示,开发者根据程序开发需…...

第P2周:Pytorch实现CIFAR10彩色图片识别
🍨 本文为🔗365天深度学习训练营 中的学习记录博客🍖 原作者:K同学啊 目标 实现CIFAR-10的彩色图片识别实现比P1周更复杂一点的CNN网络 具体实现 (一)环境 语言环境:Python 3.10 编 译 器: …...

CTFHub 命令注入-综合练习(学习记录)
综合过滤练习 命令分隔符的绕过姿势 ; %0a %0d & 那我们使用%0a试试,发现ls命令被成功执行 /?ip127.0.0.1%0als 发现一个名为flag_is_here的文件夹和index.php的文件,那么我们还是使用cd命令进入到文件夹下 http://challenge-438c1c1fb670566b.sa…...

OpenCV目标检测 级联分类器 C++实现
一.目标检测技术 目前常用实用性目标检测与跟踪的方法有以下两种: 帧差法 识别原理:基于前后两帧图像之间的差异进行对比,获取图像画面中正在运动的物体从而达到目标检测 缺点:画面中所有运动中物体都能识别 举个例子…...

QT6 Socket通讯封装(TCP/UDP)
为大家分享一下最近封装的以太网socket通讯接口 效果演示 如图,界面还没优化,后续更新 废话不多说直接上教程 添加库 如果为qmake项目中,在.pro文件添加 QT network QT core gui QT networkgreaterThan(QT_MAJOR_VERS…...

elasticsearch设置密码访问
1 用户认证介绍 默认ES是没有设置用户认证访问的,所以每次访问时,直接调相关API就能查询和写入数据。现在做一个认证,只有通过认证的用户才能访问和操作ES。 2 开启加密设置 1.生成证书文件 /usr/share/elasticsearch/bin/elasticsearch-…...

彻底理解如何优化接口性能
作为后端研发,必须要掌握怎么优化接口的性能或者说是响应时间,这样才能提高系统的系能,本文通过如下两个方面进行分析: 一.后端代码 有如下几步: 1.缓存机制 这是最场景的方式,当使用了缓存后,…...

C# 位运算
一、数据大小对应关系 说明: 将一个数据每左移一位,相当于乘以2。因此,左移8位就是乘以2的8次方,即256。 二、转换 1、 10进制转2进制字符串 #region 10进制转2进制字符串int number1 10;string binary Convert.ToString(num…...