技术好文:UEFoliage工具拓展

简介: 技术好文:UEFoliage工具拓展

项目从4.24升级到4.26后 foliage的editor ui布局发生了很大的变化 顺带原项目中加的功能也要简单的移植下。


1.Fix:


UE的植被有个Invalid的标志,即Fix左边的这个小图标,这个是ue的自带功能选出所有的不合法的植被。


合法条件为: FoliageInstance的BaseComponent是否能在规定范围(射线检测)内找到,且误差在5cm内,且附着的BaseComponent与FoliageInstance是否在同一个level中(项目中新加)。


通俗的理解 所谓的不合法是指1.该植被没有附着的地面 2.地面与植被处于不同的level 3.离开地面过高 4.陷入地面过低。


1/2会影响关卡拆分移动重组导致植被的位置出错。3/4在表现上不美观。


不合法的植被是怎么来的。1美术同学的操作,比如为了美观移动某个植被到“空中”。2.拆关卡,静态合批拆合批的操作。


新加的Fix功能的目的即整体处理上面的4个问题。 具体代码与FoliageEdMode.cpp的SelectInvalidInstances相对应。分成2部分。


part1


step1 找到离需要修复的FoliageInstance最近的地面


step2 给FoliageInstance一个新的BaseId


step3 设置一个能够满足5cm误差的ZOffset来完成”对冲“


1 bool FEdModeFoliage::FixInstanceToGround(AInstancedFoliageActor InIFA, float AlignMaxAngle, FFoliageInfo& Mesh, int32 InstanceIdx)


2 {


3 UWorld InWorld = GetWorld();


4


5 FCollisionQueryParams QueryParams(SCENE_QUERY_STAT(FoliageGroundCheck), true);


6 QueryParams.bReturnFaceIndex = false;


7 FCollisionShape SphereShape;


8 SphereShape.SetSphere(0.f);


9 TArray Hits; Hits.Reserve(16);


10 FHitResult HitResult;


11


12 FFoliageInstance& Instance = Mesh.Instances【InstanceIdx】;


13


14 FVector InstanceTraceRange = Instance.GetInstanceWorldTransform().TransformVector(FVector(0.f, 0.f, FOLIAGE_INVALID_TEST_TRACE));


15 FVector Start = Instance.Location + InstanceTraceRange;


16 FVector End = Instance.Location - InstanceTraceRange;


17


18 InWorld->SweepMultiByObjectType(Hits, Start, End, FQuat::Identity, FCollisionObjectQueryParams(ECC_WorldStatic), SphereShape, QueryParams);


19


20 // Find nearest hit


21 float TempDistance = InstanceTraceRange.Size();


22 for (const FHitResult& Hit : Hits)


23 {


24 float HitDistance = (Hit.Location - Instance.Location).Size();


25 if (HitDistance [span style="color: rgba(0, 0, 0, 1)"> TempDistance)


26 {


27 TempDistance = HitDistance;


28 HitResult = Hit;


29 }


30 }


31


32 if (HitResult.bBlockingHit)


33 {


34 UPrimitiveComponent HitComponent = HitResult.Component.Get();


35


36 // Find BSP brush


37 UModelComponent ModelComponent = Cast(HitComponent);


38 if (ModelComponent)


39 {


40 ABrush BrushActor = ModelComponent->GetModel()->FindBrush(HitResult.Location);


41 if (BrushActor)


42 {


43 HitComponent = BrushActor->GetBrushComponent();


44 }


45 }


46


47 // Set new base


48 auto NewBaseId = InIFA->InstanceBaseCache.AddInstanceBaseId(Mesh.ShouldAttachToBaseComponent() ? HitComponent : nullptr);


49 Mesh.RemoveFromBaseHash(InstanceIdx);


50 Instance.BaseId = NewBaseId;


51 if (Instance.BaseId == FFoliageInstanceBaseCache::InvalidBaseId)


52 {


53 Instance.BaseComponent = nullptr;


54 }


55 Mesh.AddToBaseHash(InstanceIdx);


56


57 // Set new ZOffset


58 float InstanceZUpOffsetFixLimitThreshold = CVarOffGroundZUpOffsetThreshold.GetValueOnGameThread();


59 float InstanceZDownOffsetFixLimitThreshold = CVarOffGroundZDownOffsetThreshold.GetValueOnGameThread();


60 float InstanceOffGroundLocalThreshold = CVarOffGroundTreshold.GetValueOnGameThread();


61 float InstanceWorldTreshold = Instance.GetInstanceWorldTransform().TransformVector(FVector(0.f, 0.f, InstanceOffGroundLocalThreshold)).Size();


62 float InstanceWorldZUpOffsetFixLimitThreshold = Instance.GetInstanceWorldTransform().TransformVector(FVector(0.f, 0.f, InstanceZUpOffsetFixLimitThreshold)).Size();


63 float InstanceWorldZDownOffsetFixLimitThreshold = Instance.GetInstanceWorldTransform().TransformVector(FVector(0.f, 0.f, InstanceZDownOffsetFixLimitThreshold)).Size();


64


65 FVector InstanceWorldZOffset = Instance.GetInstanceWorldTransform().TransformVector(FVector(0.f, 0.f, Instance.ZOffset));


66 FVector OffsetToGround = Instance.Location - (HitResult.Location + InstanceWorldZOffset);


67 bool bIsUpOffset = OffsetToGround.Z > 0 ? true : false;


68 float DistanceToGround = OffsetToGround.Size();


69


70 if (OffsetToGround.Z >= 0)


71 {


72 if (DistanceToGround > InstanceWorldZUpOffsetFixLimitThreshold)


73 {


74 return false;


75 }


76 if ((DistanceToGround - InstanceWorldTreshold) > KINDA_SMALL_NUMBER)


77 {


78 check(InstanceWorldZUpOffsetFixLimitThreshold > KINDA_SMALL_NUMBER);


79 float ScaleRateLocalToWorld = InstanceZUpOffsetFixLimitThreshold / InstanceWorldZUpOffsetFixLimitThreshold;


80 Instance.ZOffset += DistanceToGround ScaleRateLocalToWorld;


81 }


82 }


83 else


84 {


85 if (DistanceToGround > InstanceWorldZDownOffsetFixLimitThreshold)


86 {


87 return false;


88 }


89 if ((DistanceToGround - InstanceWorldTreshold) > KINDA_SMALL_NUMBER)


90 {


91 check(InstanceWorldZDownOffsetFixLimitThreshold > KINDA_SMALL_NUMBER);


92 float ScaleRateLocalToWorld = InstanceZDownOffsetFixLimitThreshold / InstanceWorldZDownOffsetFixLimitThreshold;


93 Instance.ZOffset -= DistanceToGround ScaleRateLocalToWorld;


94 }


95 }


96 return true;


97 }


98 return false;


99 }


View Code


part2


step1 将植被移到合理的关卡中


1 void FEdModeFoliage::MoveSelectInstancesToCorrectLevel(UWorld InWorld)


2 {


3 GEditor->BeginTransaction(NSLOCTEXT("UnrealEd", "FoliageModeTransaction:MoveSelectInstancesToCorrectLevel", "Move Foliage To Correct Level"));


4 {


5


6 const int32 NumLevels = InWorld->GetNumLevels();


7 for (int32 LevelIdx = 0; LevelIdx < NumLevels; ++LevelIdx)


8 {


9 ULevel Level = InWorld->GetLevel(LevelIdx);


10 AInstancedFoliageActor IFA = AInstancedFoliageActor::GetInstancedFoliageActorForLevel(Level);


11 if (IFA)


12 {


13 bool bFoundSelection = false;


14


15 for (auto& MeshPair : IFA->FoliageInfos)


16 {


17 FFoliageInfo& FoliageInfo = MeshPair.Value;


18


19 if (FoliageInfo.SelectedIndices.Array().Num() > 0)


//代码参考:https://weibo.com/u/7930362378

20 {


21 // Mark actor once we found selection


22 if (!bFoundSelection)


23 {


24 IFA->Modify();


25 bFoundSelection = true;


26 }


27 int InstanceIndex = 0;


28 while (InstanceIndex [span style="color: rgba(0, 0, 0, 1)"> FoliageInfo.Instances.Num())


29 {


30 if (!FixInstanceToCorrectLevel(IFA, MeshPair.Key->AlignMaxAngle, FoliageInfo, InstanceIndex))


31 {


32 InstanceIndex++;


33 }


34 }


35 }


36 }


37 }


38 }


39 }


40 GEditor->EndTransaction();


41 }


View Code


1 bool FEdModeFoliage::FixInstanceToCorrectLevel(AInstancedFoliageActor InIFA, float AlignMaxAngle, FFoliageInfo& Mesh, int32 InstanceIdx)


2 {


3 UWorld InWorld = GetWorld();


4


5 FCollisionQueryParams QueryParams(SCENE_QUERY_STAT(FoliageGroundCheck), true);


6 QueryParams.bReturnFaceIndex = false;


7 FCollisionShape SphereShape;


8 SphereShape.SetSphere(0.f);


9 TArray Hits; Hits.Reserve(16);


10 FHitResult HitResult;


11


12 FFoliageInstance& Instance = Mesh.Instances【InstanceIdx】;


13


14 FVector InstanceTraceRange = Instance.GetInstanceWorldTransform().TransformVector(FVector(0.f, 0.f, FOLIAGE_INVALID_TEST_TRACE));


15 FVector Start = Instance.Location + InstanceTraceRange;


16 FVector End = Instance.Location - InstanceTraceRange;


17


18 InWorld->SweepMultiByObjectType(Hits, Start, End, FQuat::Identity, FCollisionObjectQueryParams(ECC_WorldStatic), SphereShape, QueryParams);


19


20 // Find nearest hit


21 float TempDistance = InstanceTraceRange.Size();


22 for (const FHitResult& Hit : Hits)


23 {


24 float HitDistance = (Hit.Location - Instance.Location).Size();


25 if (HitDistance [span style="color: rgba(0, 0, 0, 1)"> TempDistance)


26 {


27 TempDistance = HitDistance;


28 HitResult = Hit;


29 }


30 }


31


32 if (HitResult.bBlockingHit)


33 {


34 UPrimitiveComponent HitComponent = HitResult.Component.Get();


35


36 if (HitComponent->GetComponentLevel() != InIFA->GetLevel())


37 {


38 TSet InInstanceSet;


39 InInstanceSet.Emplace(InstanceIdx);


40 for (auto& Pair : InIFA->FoliageInfos)


41 {


42 if (&Pair.Value.Get() == &Mesh)


43 {


44 UFoliageType* FoliageType = Pair.Key;


45 InIFA->MoveInstancesToLevel(HitComponent->GetComponentLevel(), InInstanceSet, &Mesh, FoliageType);


46 return true;


47 }


48 }


49 }


50 <span style="color: rg

相关文章
|
编解码 Windows
UE-windows包蓝图分辨率设置
windows包蓝图分辨率设置
|
7月前
|
机器学习/深度学习 计算机视觉
RT-DETR改进策略【卷积层】| 引入注意力卷积模块RFAConv,关注感受野空间特征 助力RT-DETR精度提升
RT-DETR改进策略【卷积层】| 引入注意力卷积模块RFAConv,关注感受野空间特征 助力RT-DETR精度提升
193 10
RT-DETR改进策略【卷积层】| 引入注意力卷积模块RFAConv,关注感受野空间特征 助力RT-DETR精度提升
|
小程序 开发者
微信小程序报错[ app.json 文件内容错误] app.json: app.json 未找到,一招解决
微信小程序报错[ app.json 文件内容错误] app.json: app.json 未找到,一招解决
4597 0
微信小程序报错[ app.json 文件内容错误] app.json: app.json 未找到,一招解决
|
存储 关系型数据库 MySQL
浅谈Elasticsearch的入门与实践
本文主要围绕ES核心特性:分布式存储特性和分析检索能力,介绍了概念、原理与实践案例,希望让读者快速理解ES的核心特性与应用场景。
531 13
|
9月前
|
SQL 存储 关系型数据库
Mysql并发控制和日志
通过深入理解和应用 MySQL 的并发控制和日志管理技术,您可以显著提升数据库系统的效率和稳定性。
345 10
|
Shell
删除右键“在 Visual Studio 中打开”选项
删除右键“在 Visual Studio 中打开”选项
2280 0
|
11月前
|
安全 Windows
Windows系统实现exe服务注册的方法都有哪些?
【10月更文挑战第5天】Windows系统实现exe服务注册的方法都有哪些?
1399 0
|
机器学习/深度学习 数据采集 人工智能
什么是AI?如何使用AI?本文告诉你
人工智能(AI)是借助计算机技术来模拟与实现人类智慧的一项科技。它涵盖了从感知到语言理解等多方面的能力。AI可划分为弱AI、强AI及超AI三类,当前主要集中在弱AI的应用上,如语音助手和图像识别。为了高效运用AI,首先需清晰目标,再选取合适的工具,同时保证数据质量,不断优化模型,并注重伦理考量,最终实现人机协同作业,充分发挥各自优势。
4104 2
|
运维 负载均衡 监控
slb学习教程
【9月更文挑战第1天】
313 1
|
Linux 编译器 C语言
Linux 中 EXPORT_SYMBOL宏详解
Linux 中 EXPORT_SYMBOL宏详解