1.UE 八叉树Octree2源码分析
2.UE4:双骨骼IK源码解析
3.UE5 源码结构解读——Unreal Engine 5文件系统详细导览
4.UE5在编辑器快捷键配置上的源码BaseEditorKeyBindings.ini文件源码解读分析
5.游戏引擎随笔 0x20:UE5 Nanite 源码解析之渲染篇:BVH 与 Cluster 的 Culling
6.[UE5.1] StateTree 使用与源码分析(二)
UE 八叉树Octree2源码分析
UE中八叉树Octree2源码分析,本文旨在深入理解UE八叉树的详解具体实现。八叉树概念广泛熟悉,源码但初次接触UE实现时仍需思考。详解UE八叉树简化应用,源码多数直接使用方便。详解放量滞胀预警源码本文针对UE4.至UE5.1版本八叉树源码进行详细解析。源码
UE八叉树主要结构包括:TreeNodes、详解ParentLinks、源码TreeElements、详解FreeList、源码RootNodeContext和MinLeafExtent。详解TreeNodes存储节点信息,源码每个FNode记录当前节点元素数量及子节点Index;ParentLinks记录节点父节点ID;TreeElements存储元素数据;FreeList记录空闲FNode下标;RootNodeContext和MinLeafExtent与八叉树构造相关,详解用于确定节点半径。源码
UE八叉树构造过程依赖AddElement方法,实现在AddElementInternal中。首先判断节点是否为叶子节点。若无子节点且元素数量超过预设阈值,或节点半径小于MinLeafExtent,则创建子节点。否则,直接将元素加入当前节点。若需创建子节点,清空当前节点元素,分配八个子节点,递归处理非叶节点情况。
RemoveElement方法根据ElementId移除元素。首先在TreeElements中移除元素,然后从节点向上遍历,检查元素数量过少的节点,进行塌缩重构,将子节点元素移入当前节点。
UE八叉树查询接口包括FindElement、FindElementsWithBoundsTest等,核心目的是遍历节点和子节点以满足查询条件。UE八叉树用于高效空间数据处理,通过Octree2类声明实现。例如,PrecomputedLightVolume类定义ElementType和OctreeSemantics,便于特定应用使用。
UE八叉树内存管理关键在于TreeElement数组,使用TInlineAllocator或FDefaultAllocator需考虑应用场景。空间数据结构如四叉树、八叉树等在空间划分算法中具有重要应用,优化碰撞检测及实现复杂场景。
UE4:双骨骼IK源码解析
在深入探讨双骨骼IK的源码解析之前,我想对各位表示诚挚的感谢。如果文章中有任何错误,花城农夫源码我期望能获得各位专家的指正。本文章的目的是为初学者提供进一步的理解。 双骨骼IK涉及两根骨骼及其三个关节点的运作,目标为将根骨骼的坐标、目标位置以及关节调整方向作为输入,以逆计算中间关节和骨骼的运动。 理解双骨骼IK的节点和效果是基础。用户需提供红线划出的部分作为输入,包括根骨骼坐标、目标位置和关节调整方向。我们通过不同的参数输入来观察其影响。 双骨骼IK的节点影响包括Effect Location和Joint Target Location。Effect Location改变时,影响着目标位置的调整,Joint Target Location的变动则控制中间关节的方向。 正式开始UE4源码的解析。我们首先访问AnimNode_TwoBoneIK.cpp文件,这里我将重点讲解关键步骤,包括参数定义、判空API等,通过对比UE节点参数,你将能够建立起参数之间的映射。 源码中,我们首先根据当前骨骼关节向上寻找中间关节和根关节,并初始化它们。接下来,核心解算步骤在TwoBoneIK.cpp中。 理解数学原理是关键,这样你就能更好地理解源码的逻辑。以下是用图示解释的步骤:首先,我们分析已知条件并推算出关键信息。 转到源码,这里我们看到骨骼长度的获取,根节点到Effect节点的向量的获取,最小值约束的应用,以及对根节点与中间关节向量的判断。如果向量不合理,使用默认值替换;如果合理,则进行叉乘计算法向量,确定M点偏移向量。 接着,进行三角形判定,确保计算的合理性,不满足时应用最大容忍度限制,随后进行余弦值等操作以获得垂线长度。 若需更深入的了解,我推荐以下资源:双骨骼IK源码 - 搜索结果 - 知乎
Tanzq:Two Bone IK 源码分析
Two Bone IK
UE5 源码结构解读——Unreal Engine 5文件系统详细导览
欢迎加入“虚幻之核:UE5源码全解”,探索Unreal Engine 5(UE5)的shx源码分享深层秘密。作为一款行业领先的游戏引擎,UE5不仅集成了Nanite虚拟化微多边形几何系统和Lumen动态全局光照等革新技术,还提供了一个深度解析专栏,帮助开发者、图形程序员和技术艺术家从源码级别理解其核心构造。
UE5不仅仅是一个游戏引擎,它代表了虚幻技术的巅峰,赋予了创造创新视觉和互动体验的无限可能。我们的专栏将深入探讨这些技术背后的源代码,揭示它们的工作原理,并展示如何在您的项目中实现和优化它们。
每一期专栏都是一个精心设计的知识模块,旨在让读者不仅掌握UE5的功能,更从源码层面掌握其实现细节。从资产流水线到渲染过程,从物理模拟到AI行为树,无论您希望优化当前项目性能,还是探索UE5隐藏的功能和技巧,这里都将为您提供宝贵的资源。
“虚幻之核:UE5源码全解”是您探索虚幻引擎深层秘密的起点,让我们用源码解答虚幻世界中的奥秘。
UE5在编辑器快捷键配置上的BaseEditorKeyBindings.ini文件源码解读分析
Unreal Engine 5(UE5)中,BaseEditorKeyBindings.ini文件是编辑器快捷键配置的核心。它定义了各种功能的快捷键绑定,显著提高了开发者的工作效率。本文深入解析文件结构、代码思路与设计架构,指出其关键点与挑战。
文件中,模块化组织以/Script/UnrealEd.UnrealEdKeyBindings路径标识特定编辑器模块,如曲线编辑器。结构清晰,便于扩展与维护。
每条+KeyBindings配置项定义快捷键与关联命令名,通过键值对形式呈现,如Key="A",bCtrlDown=True,指向编辑器内部操作,如CurveEditor_FitViewVertically。允许用户自定义手势,增强编辑器定制性。
UE5编辑器采用模块化架构,易于快捷键自定义与扩展,但需确保所有绑定协调一致,避免冲突,确保与编辑器其他部分无缝集成。
BaseEditorKeyBindings.ini文件体现了UE5在用户界面与交互设计的深入考虑,通过高度可配置性赋予用户定制编辑器能力。贵高速源码其背后的架构确保了灵活性与扩展性,是UE5成为顶级游戏开发工具的关键。
游戏引擎随笔 0x:UE5 Nanite 源码解析之渲染篇:BVH 与 Cluster 的 Culling
Nanite遵循的设计理念是三角形的绘制数量超过像素数量就是一种浪费。UE5中的Nanite技术在EA版本发布后揭开了面纱,其渲染性能令人惊叹,本文尝试从源码层面解析Nanite的实现技术,详细讲解Nanite的实现细节,以供开发者参考。
Nanite在GPU端流程如下:
1. **Nanite::Streaming**:异步上传Cluster渲染数据,基于上一帧回读的Cluster Page Request数据进行。
2. **Nanite::InitContext**:初始化Culling上下文的GPU相关数据。
3. **Nanite::CullRasterize**:执行剔除与光栅化,包含生成深度目标、执行基础渲染以及生成阴影等步骤。
4. **Nanite::EmitDepthTargets**:根据Visibility Buffer生成深度相关的Buffer,如Scene Depth、Stencil、Velocity、Material Depth等。
5. **Nanite::BasePass**:使用Visibility Buffer和Cluster相关Buffer输出Deferred Rendering所需的G-Buffer。
6. **Nanite Shadows**:生成阴影所需的深度信息,仅包含InitContext和CullRasterize两步。
7. **Nanite::Readback**:回读PersistentCull pass产生的Cluster Page Request数据。
本文重点解析CullRasterize步骤中的PersistentCull pass源码。
为了在GPU上高效执行Culling,Nanite预生成了BVH(Bounding Volume Hierarchy),每个节点最多包含8个子节点,叶节点存储实际的Cluster索引数据。但要在GPU中实现高效的层次遍历且负载均衡并非易事,设计的不合理会导致性能下降、GPU线程闲置。
UE5的Nanite在GPU端实现了一种高效的遍历机制,性能高且负载均衡,GPU在整个过程中几乎满负荷运行。BVH和Cluster数据结构与存储方式都围绕着高效遍历和负载均衡的目标设计。
**关键Buffers数据结构**:
- **CandidateNodesAndClusters**:存储候选BVH Node和Cluster信息的全局Buffer,内存布局包括待处理的Cluster Group总数、所有候选Cluster Packed数据和所有候选BVH Node Packed数据。
- **MainAndPostPassPersistentStates**:存储Culling过程中的状态数据,包括用于写入BVH Node的读写偏移、Cluster读写偏移等。
- **InstanceCull**:执行对象实例级别的可见剔除,将可见的BVH Root Node存储在CandidateNodesAndClusters中。
- **PersistentClusterCull**:充分利用GPU线程,避免空闲,分为Node和Cluster处理两个阶段,通过组内线程同步和多线程并行处理,实现负载均衡。php源码excel
**BVH Node Culling解析**:
1. 每组线程计算需要处理的候选BVH节点,通过原子操作统计有效节点数量,并在处理完成时切换至Cluster Culling。
2. 通过组内线程索引计算节点和子节点的索引,执行子节点的Culling处理,同时通过队列管理新产生的候选节点。
3. 优化候选Cluster存储,减少GPU Buffer写入开销。
**Cluster Culling解析**:
1. 处理存储在队列中的候选Cluster,通过编码和同步机制查找需要处理的Cluster。
2. 执行真正的Culling逻辑,包括可见性判断、硬件或软件光栅化等。
3. 将可见的Cluster写入全局缓冲,根据光栅化类型顺序存储,并在Post Pass中再次执行Culling流程。
解析至此,UE5的Nanite技术通过高效的GPU算法和数据结构实现了强大的渲染性能,使得百万面的高精度模型在老显卡上也能实现流畅运行。UE5团队的设计与工程实现能力令人敬佩,其精神和勇气引领了行业技术的前沿。通过深入源码学习,开发者可以深入了解先进的设计思想和工程实现方法,提升自己的技术实力。
[UE5.1] StateTree 使用与源码分析(二)
深入探讨UE5.1中的StateTree,从初始化到Tick更新数据的流程,以及其背后的源码分析。
一、StateTree的初始化流程:
1.1、筛选未激活的Entity:UMassStateTreeActivationProcessor执行初始化时,首先会筛选出所有没有打上FMassStateTreeActivatedTag标记的Entity。
1.2、遍历并创建上下文:接着,对这些Entity进行遍历,检查StateTreeInstanceList中是否已存在相应的StateTreeInstance。若不存在,则创建FMassStateTreeExecutionContext上下文。
1.3、注入Fragment:将状态树所需Fragment注入,并进行验证。
1.4、启动状态树:通过FMassStateTreeExecutionContext的Start()函数正式开始状态树的运行。
1.5、初始化数据与确定ActivateStates:在FStateTreeExecutionContext::Start()函数中初始化数据,并确定ActivateStates数组,这代表从根节点到激活状态的所有状态。
1.6、检查所有State的Conditions:遍历所有State,检查其条件,若有子节点,则递归检查。
1.7、完成初始化:回到UMassStateTreeActivationProcessor,为已初始化的Entity打上Tag,完成整个初始化过程。
二、状态树的Tick更新:
2.1、获取并判断状态:FStateTreeExecutionContext::Tick()作为外部调用刷新状态树的接口,首先获取当前正在运行的State,并判断整个树是否仍在运行。
2.2、刷新Evaluators:刷新所有State的Evaluators。
2.3、刷新并处理Tasks:刷新ActiveStates中的所有State任务,重点关注TickStatus的逻辑。一旦出现返回EStateTreeRunStatus::Failed的Task,整个Tick结果将失败。如果所有Task中存在非EStateTreeRunStatus::Running状态,则根据状态返回结果。若所有Task都在EStateTreeRunStatus::Running状态中,则Tick结果为Running。
2.4、处理状态完成与切换:如果最终Tick结果不是EStateTreeRunStatus::Running,则执行StateCompleted()函数,调用所有相关Task的StateCompleted函数。同时,检查当前State的所有Transitions,根据设置触发状态切换。
三、使用技巧与注意事项:
3.1、Task的InstanceData可以共享给整个State,根据Category设置决定。
3.2、设置为Output的参数可被外部使用,Task的Output参数仅限当前State内部共享。
3.3、Input参数的右值可引用当前State中的其他Task或Evaluator的Output参数,实现灵活的数据共享。
3.4、Task的执行顺序决定了Output参数的使用时机,确保Task的顺序正确。
UE4源码剖析——异步与并行 中篇 之 Thread
我们知道UE中的异步框架分为TaskGraph与Thread两种,上篇教程我们学习了TaskGraph,它擅长处理有依赖关系的短任务;本篇教程我们将学习Thread,它与TaskGraph相反,它更擅长于处理长任务。而下一篇文章,我们则会承接Thread,去学习一下引擎中一些重要的线程。
Thread擅长处理长任务,从长任务生命周期这个层面来看,我们可以先把长任务分为两类:常驻型长任务与非常驻型长任务。
常驻型长任务侧重于并行,通常用于监听式服务,例如网络传输,使用单独的线程对网络进行监听,每当有网络数据包到达时,线程接收并处理后,不会立即结束,而是重置部分状态,继续监听,等待下一轮数据包。
非常驻型长任务侧重于异步,通常用于数据处理,例如主线程为了提高性能,避免卡顿,会将一些重负载的运算任务分发给分线程处理,可能分批给多条分线程,主线程继续运行其他逻辑。任务处理完成后,将结果返回给主线程,分线程可销毁。
接下来,我们通过两个例子学习Thread的使用。
计算由N到M(N和M为大数字)所有数字的和。使用Thread异步调用,将计算操作交由分线程执行,计算完成后再通知主线程结果,代码实现如下:
逻辑分为两部分:启动分线程计算数字和,使用Async函数,参数为EAsyncExecution::Thread,创建新线程执行。学习Async函数用法,该函数返回TFuture对象,代表未来状态,当前无法获取结果,但在未来某个时刻状态变为Ready,此时可通过TFuture获取结果。
主线程注册回调,等待分线程计算完成,使用TFuture的Then函数,完成时触发注册的回调,也可使用Wait系列函数等待计算完成。
接下来学习常驻型任务使用。
定义玩家血量上限点,当前点,当血量未满时,每0.2秒恢复1点血量。代码实现分为创建生命治疗仪FRunnable对象、重写Run函数、创建FRunnableThread线程、测试恢复功能和释放线程资源。
生命治疗仪创建与测试完整代码如下,可验证生命恢复功能和暂停与恢复。
UE4中的FRunnable与FRunnableThread提供创建常驻型任务所需接口。无论是常驻型还是非常驻型,底层实现相同,都是使用FRunnableThread线程。
FRunnableThread线程结构包含标识符、逻辑功能、效率与性能、辅助调试字段。线程创建与生命周期分为创建FRunnable类对象、创建FRunnableThread对象两步,通过FRunnable的生命周期管理实现线程运行与停止。
UE4线程管理流程包括继承并创建FRunnable类对象、创建FRunnableThread对象,生命治疗仪线程创建代码。
UE4中的几种异步方式底层使用线程实现,学习了线程类型、创建、生命周期、销毁方法,为下篇学习引擎特殊线程打下基础。
UE4源码剖析——Actor蓝图之CDO与SCS
在UE的日常使用中,蓝图(UBlueprint)是我们接触最多的资产类型。每个蓝图在创建时需要选择一个父类,这决定了蓝图的类型,比如Actor蓝图、Component蓝图、Widget蓝图、动作蓝图等。以Actor蓝图为例,本文将深入探讨蓝图的基础架构,并学习如何通过代码读取蓝图资产在蓝图编辑器中的属性值。此外,本文还将重点介绍如何利用SCS框架管理新组件,并在运行时加载这些组件。
在实际开发中,我们经常需要对蓝图进行处理,例如在大型项目中,制定一套资源规范并开发一套资源检测工具。这些工具往往需要遍历特定目录下的蓝图并执行某些条件判断和处理。本文将帮助大家了解如何实现这些功能。
**实战需求**:
1. **例1**:要求所有放置在“Buildings”文件夹下的蓝图必须包含`StaticMeshComponent`组件,且`StaticMesh`字段不能为空。
2. **例2**:要求“Cars”文件夹下的所有蓝图的`SceneComponent`组件移动性必需为`Movable`。
**蓝图的父类与Actor蓝图**:
1. **蓝图的父类**:创建蓝图时,编辑器面板中选择的父类决定蓝图的类型,例如`TestActorChild2`的父类为`TestActorChild1`,而`TestActorChild1`的父类为`TestBlueprintActor`。
2. **Actor蓝图**:若蓝图的父类层级链最顶层是`Actor 类`,则该蓝图为`Actor蓝图`。
**蓝图产生类**:蓝图的`_C`后缀代表蓝图产生类,它用于在编译时生成C++类,包含蓝图中的信息。
**蓝图类(UBlueprint)**:加载蓝图包时,通过`LoadObject`函数获取到的是`UBlueprint`类。
**蓝图骨骼类(SkeletonGeneratedClass)**:以`SKEL_`前缀和`_C`后缀加载,表示蓝图的基础信息,通常在编辑器中修改时会重新生成。
**蓝图产生类(GeneratedClass)**:仅以`_C`为后缀加载,用于在运行时创建蓝图对象。
**前后缀声明**:`UBlueprint.h`中的`GetBlueprintClassNames`函数定义了这些前缀。
**Actor蓝图产生类的实例化与阶段拆分**:
1. **CDO的构建**:`ClassDefaultObject`是每个类的默认对象,用于提供默认属性值和行为。
2. **SCS组件附加**:通过蓝图编辑器的组件面板添加组件,这些组件存储在`SimpleConstructionScript`中,用于在运行时添加组件。
**CDO与SCS**:
- **CDO**:存储默认属性值与行为,节省数据传输和存储,支持配置化。
- **SCS**:简化组件添加过程,通过蓝图编辑器直观操作组件。
**需求回顾与实现**:通过遍历CDO和SCS,判断组件属性值,实现特定条件的检测,如`StaticMeshComponent`的`StaticMesh`字段是否为空。
本文从实际需求出发,全面介绍了蓝图的基本概念、内部分类、构建流程以及如何利用SCS管理组件。希望本文内容能帮助开发者更深入地理解蓝图的工作原理,提高资源管理与组件处理的效率。
UE5 ModelingMode & GeometryScript源码学习(一)
前言
ModelingMode是虚幻引擎5.0后的新增功能,用于直接在引擎中进行3D建模,无需外接工具,实现快速原型设计和特定需求的模型创建。GeometryScript是用于通过编程方式创建和操控3D几何体的系统,支持蓝图或Python脚本,提供灵活控制能力。
本文主要围绕ModelingMode与GeometryScript源码学习展开,涵盖DMC简介、查找感兴趣功能源码、动态网格到静态网格的代码介绍。
起因
在虚幻4中,通过RuntimeMeshComponent或ProceduralMeshComponent组件实现简单模型的程序化生成。动态网格组件(DynamicMeshComponent)在UE5中提供了额外功能,如三角面级别处理、转换为StaticMesh/Volume、烘焙贴图和编辑UV等。
将动态网格对象转换为静态网格对象时,发现官方文档对DMC与PMC对比信息不直接涉及此转换。通过搜索发现,DynamicMesh对象转换为StaticMesh对象的代码位于Source/Runtime/MeshConversion目录下的UE::Modeling::CreateMeshObject函数中。
在UE::Modeling::CreateMeshObject函数内,使用UEditorModelingObjectsCreationAPI对象进行动态网格到静态网格的转换,通过HasMoveVariants()函数接受右值引用参数。UEditorModelingObjectsCreationAPI::CreateMeshObject函数进一步处理转换参数,UE::Modeling::CreateStaticMeshAsset函数负责创建完整的静态网格资产。
总结转换流程,DynamicMesh对象首先收集世界、变换、资产名称和材质信息,通过FCreateMeshObjectParams对象传递给UE::Modeling::CreateMeshObject函数,该函数调用UE::Modeling::CreateStaticMeshAsset函数创建静态网格资产。
转换为静态网格后,程序创建了一个静态网格Actor和组件。此过程涉及静态网格属性设置,最终返回FCreateMeshObjectResult对象表示转换成功。
转换静态网格为Volume、动态网格同样在相关函数中实现。
在Modeling Mode中添加基础形状涉及UInteractiveToolManager::DeactivateToolInternal函数,当接受基础形状时,调用UAddPrimitiveTool::GenerateAsset函数,根据面板选择的输出类型创建模型。
最后,UAddPrimitiveTool::Setup函数创建PreviewMesh对象,UAddPrimitiveTool::UpdatePreviewMesh()函数中通过UAddPrimitiveTool::GenerateMesh生成网格数据填充FDynamicMesh3对象,进而更新到PreviewMesh中。
文章总结了Modeling Mode与GeometryScript源码的学习路径,从动态网格到静态网格的转换、基础形状添加到输出类型对应函数,提供了一条完整的流程概述。