《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 用上面的频数图做柱状图,再修改&…...

装饰模式(Decorator Pattern)重构java邮件发奖系统实战
前言 现在我们有个如下的需求,设计一个邮件发奖的小系统, 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其…...
1688商品列表API与其他数据源的对接思路
将1688商品列表API与其他数据源对接时,需结合业务场景设计数据流转链路,重点关注数据格式兼容性、接口调用频率控制及数据一致性维护。以下是具体对接思路及关键技术点: 一、核心对接场景与目标 商品数据同步 场景:将1688商品信息…...
解决本地部署 SmolVLM2 大语言模型运行 flash-attn 报错
出现的问题 安装 flash-attn 会一直卡在 build 那一步或者运行报错 解决办法 是因为你安装的 flash-attn 版本没有对应上,所以报错,到 https://github.com/Dao-AILab/flash-attention/releases 下载对应版本,cu、torch、cp 的版本一定要对…...

零基础设计模式——行为型模式 - 责任链模式
第四部分:行为型模式 - 责任链模式 (Chain of Responsibility Pattern) 欢迎来到行为型模式的学习!行为型模式关注对象之间的职责分配、算法封装和对象间的交互。我们将学习的第一个行为型模式是责任链模式。 核心思想:使多个对象都有机会处…...

Kafka入门-生产者
生产者 生产者发送流程: 延迟时间为0ms时,也就意味着每当有数据就会直接发送 异步发送API 异步发送和同步发送的不同在于:异步发送不需要等待结果,同步发送必须等待结果才能进行下一步发送。 普通异步发送 首先导入所需的k…...
C语言中提供的第三方库之哈希表实现
一. 简介 前面一篇文章简单学习了C语言中第三方库(uthash库)提供对哈希表的操作,文章如下: C语言中提供的第三方库uthash常用接口-CSDN博客 本文简单学习一下第三方库 uthash库对哈希表的操作。 二. uthash库哈希表操作示例 u…...

elementUI点击浏览table所选行数据查看文档
项目场景: table按照要求特定的数据变成按钮可以点击 解决方案: <el-table-columnprop"mlname"label"名称"align"center"width"180"><template slot-scope"scope"><el-buttonv-if&qu…...

MyBatis中关于缓存的理解
MyBatis缓存 MyBatis系统当中默认定义两级缓存:一级缓存、二级缓存 默认情况下,只有一级缓存开启(sqlSession级别的缓存)二级缓存需要手动开启配置,需要局域namespace级别的缓存 一级缓存(本地缓存&#…...
Python 高效图像帧提取与视频编码:实战指南
Python 高效图像帧提取与视频编码:实战指南 在音视频处理领域,图像帧提取与视频编码是基础但极具挑战性的任务。Python 结合强大的第三方库(如 OpenCV、FFmpeg、PyAV),可以高效处理视频流,实现快速帧提取、压缩编码等关键功能。本文将深入介绍如何优化这些流程,提高处理…...
微服务通信安全:深入解析mTLS的原理与实践
🔥「炎码工坊」技术弹药已装填! 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、引言:微服务时代的通信安全挑战 随着云原生和微服务架构的普及,服务间的通信安全成为系统设计的核心议题。传统的单体架构中&…...