Houdini技术体系 基础管线(四) :Houdini驱动的UE4植被系统 下篇
背景

- 开发效率方面,这个方案并不支持UE4的Foliage Mode Editor:
- 每个植被区域都被Bake成BP的形式,场景美术规划阶段就需要格外小心防止区域之间穿插造成植被之间的叠加
- 当出现比较大的改动需求时,一个BP的范围发生改动就会造成大量BP重新生成的连锁反映。
- 就像地形生成一样,完全的自动化并不现实,美术需要能通过UE4传统手绘方式来进行修改植被的方式。
- 一个区域的BP植被需要重新生成时,还要重新绘制一遍之前的生成区域,这个过程除非预先保存,否则很难完全重现上次绘制的区域。
- 运行效率优化方面,同一类的Instance并不能放到一个InstancedStaticMeshComponent 这样必定会造成一定程度的性能损耗

- Houdini Input要增加FoliageType的选项,生成实例的对象不再是用Statice Mesh,而是UE4的Foliage Type
- Houdini Output直接输出植被实例不再Bake到BP里,而是直接Add到UE4的Foliage System的Foliage Instance里
Houdini Input对FoliageType的选项支持

namespace EHoudiniAssetInputType
{
enum Enum
{
GeometryInput = 0,
AssetInput,
CurveInput,
LandscapeInput,
FoliageTypeInput, // Add foliage type input
WorldInput
};
}
InParam.ChoiceIndex == EHoudiniAssetInputType::GeometryInput
for ( int32 Ix = 0; Ix < NumInputs; Ix++ )
{
UObject* InputObject = InParam.GetInputObject( Ix );
//Helper_CreateGeometryWidget( InParam, Ix, InputObject, AssetThumbnailPool, VerticalBox );
Helper_CreateFoliageWidget(InParam, Ix, InputObject, AssetThumbnailPool, VerticalBox);
}
SNew( SAssetDropTarget )
.OnIsAssetAcceptableForDrop( SAssetDropTarget::FIsAssetAcceptableForDrop::CreateLambda(
[]( const UObject* InObject ) {
return InObject && InObject->IsA< /*UStaticMesh*/ UFoliageType >();

if (UFoliageType_InstancedStaticMesh * InputFoliageType = Cast<UFoliageType_InstancedStaticMesh>(InputObjects[InputIdx]))
{
UStaticMesh* InputStaticMesh = InputFoliageType->GetStaticMesh();
// Creating an Input Node for Static Mesh Data
if (!HapiCreateInputNodeForStaticMesh(InputStaticMesh, MeshAssetNodeId, OutCreatedNodeIds, nullptr, bExportAllLODs, bExportSockets))
{
HOUDINI_LOG_WARNING(TEXT("Error creating input index %d on %d"), InputIdx, ConnectedAssetId);
}
SelectInputFoliageTypeArray.Add(InputFoliageType);
}

Houdini Output与Foliage Editor的关联
- Houdini输出的Entity Point Cloud所对应的Instance可以直接Add到UE4的Foliage System里。
- 美术可以通过绘制区域来对已经生成部分再次做过程化生成,或者直接利用FoliageEdit手绘的方式来进行迭代调整。
- 手绘调整部分和Houdini自动化生成部分可以分Layer保存,可以根据情况选择自动生成部分是否影响到手工调整部分。
#if WITH_EDITOR
if ( FHoudiniEngineUtils::IsHoudiniNodeValid( AssetId ) )
{
// Create necessary instance inputs.
CreateInstanceInputs( FoundInstancers ); // Create necessary curves.
CreateCurves( FoundCurves ); // Create necessary landscapes
CreateAllLandscapes( FoundVolumes );
}
#endif
for ( const FHoudiniGeoPartObject& GeoPart : Instancers )
{
HoudiniAssetInstanceInput->CreateInstanceInput();
}
UWorld* World = GEditor->GetEditorWorldContext().World();
ULevel* TargetLevel = World->GetCurrentLevel(); AInstancedFoliageActor* IFA = AInstancedFoliageActor::GetInstancedFoliageActorForLevel(TargetLevel, true);
FFoliageMeshInfo* MeshInfo;
UFoliageType* FoliageSettings = IFA->AddFoliageType(FoliageType, &MeshInfo); GLevelEditorModeTools().ActivateMode(FBuiltinEditorModes::EM_Foliage);
FEdModeFoliage* FoliageEditMode = (FEdModeFoliage*)GLevelEditorModeTools().GetActiveMode(FBuiltinEditorModes::EM_Foliage); for (int32 InstanceIdx = 0; InstanceIdx < InstancerPartTransforms.Num(); ++InstanceIdx)
{
FTransform InstanceTransform; FHoudiniEngineUtils::TranslateHapiTransform(InstancerPartTransforms[InstanceIdx], InstanceTransform);
FFoliageInstance Inst;
Inst.Location = InstanceTransform.GetLocation();
Inst.Rotation = InstanceTransform.GetRotation().Rotator();
MeshInfo->AddInstance(IFA, FoliageSettings, Inst, nullptr, true);
}

ULandscapeComponent* SelectLandscapeComponent = FHoudiniLandscapeUtils::SelectLandscapeComponentArray[Index];
int32 MinX = MAX_int32;
int32 MinY = MAX_int32;
int32 MaxX = -MAX_int32;
SelectLandscapeComponent->GetComponentExtent(MinX, MinY, MaxX, MaxY); ULandscapeInfo* LandscapeInfo = SelectLandscapeComponent->GetLandscapeProxy()->GetLandscapeInfo();
for (int32 X = MinX; X <= MaxX; X++)
{
for (int32 Y = MinY; Y <= MaxY; Y++)
{
float RegionSelect = LandscapeInfo->SelectedRegion.FindRef(FIntPoint(X, Y));
if (RegionSelect > 0)
{
SelectRegionNum++;
FBoxSphereBounds ComponentBounds =
SelectLandscapeComponent->CalcBounds(SelectLandscapeComponent->GetComponentTransform()); FBox CachedLocalBox;
CachedLocalBox.Min = FVector(X, Y, 0);
CachedLocalBox.Max = FVector(X+1, Y+1, 0);
CachedLocalBox.IsValid = 1;
FBox MyBounds = CachedLocalBox.TransformBy(SelectLandscapeComponent->GetLandscapeProxy()->
GetLandscapeActor()->GetActorTransform());
MyBounds.Max.Z = ComponentBounds.GetBox().Max.Z ;
MyBounds.Min.Z = ComponentBounds.GetBox().Min.Z ;
FBoxSphereBounds RegionBounds = FBoxSphereBounds(MyBounds);
auto TempInstances = MeshInfo->InstanceHash->GetInstancesOverlappingBox(RegionBounds.GetBox());
for (int32 Idx : TempInstances)
{
if(InInstancesToRemove.Find(Idx) == INDEX_NONE)
InInstancesToRemove.Add(Idx);
}
}
}
}
MeshInfo->RemoveInstances(IFA, InInstancesToRemove, true);


TMap<UFoliageType*, FFoliageMeshInfo*> InstancesFoliageType = IFA->GetAllInstancesFoliageType(); for (auto& MeshPair : InstancesFoliageType)
{
FFoliageMeshInfo* MeshInfo = MeshPair.Value;
UFoliageType* FoliageSettings = MeshPair.Key;
}
GrassType的对应


总结


Houdini技术体系 基础管线(四) :Houdini驱动的UE4植被系统 下篇的更多相关文章
- Houdini技术体系 基础管线(三) :UE4 Landscape Component的多选支持 下篇
背景 上篇中,我们介绍了如何修改Houdini Enigne来设置单个Landscape Compnent的Height和Layer的数据,但原生Houdini Engine并不支持多选Compone ...
- Houdini技术体系 基础管线(三) :UE4以选择区域的方式对地形做生成和更新 上篇
背景 前一节里,解决了Houdini地形无缝导入到UE4的流程问题.但这种方法也有它的局限性,在实际游戏项目里,LA和LD还是偏向在游戏引擎编辑器里工作,他们的一些设计也会影响到地形的信息,那 ...
- Houdini技术体系 基础管线(四) :Houdini驱动的UE4植被系统 上篇
背景 之前在<Houdini技术体系 过程化地形系统(一):Far Cry5的植被系统分析>一文中已经对AAA游戏中过程化植被的需求有了一定的定义,后续工作就是如何用Houdini开发功能 ...
- Houdini技术体系 基础管线(一) : Houdini与Houdini Engine的安装
Houdini 下载与安装 在官网 https://www.sidefx.com/download/ 下载最新的Production Build 版本,当前是16.5版本,需要注册帐号 PS:公司内网 ...
- Houdini技术体系 基础管线(二) :Heightfiled与UE4的无缝导入以及对World Composition的支持
Authored by TraceYang 前言 传统的制作做比较真实大世界3D关卡地形时,通常的采用的方式是把HeightMap和SplatMap(Layer Mask)导入到引擎的地形系统里 ...
- Houdini技术体系 过程化地形系统(一):Far Cry5的植被系统分析
背景 在大世界游戏里,植被(biome)是自然环境非常重要的组成部分,虽然UE4里的也有比较不错的地形+植被系统,但相比国外AAA级游戏的效果,还是有不少的差距,简介如下: UE4的植被分为( ...
- 01-java技术体系基础
java体系基础 理论 编程语言: 系统级: C, C++, go, erlang ... 应用级: C#, Java, Python, Perl, Ruby, php 虚拟机: jvm(java虚拟 ...
- Houdini技术体系大纲
Houdini for UE4 Pipeline的系列教程,前言等想好再写吧
- 测试需要了解的技术之基础篇四__UI自动化测试体系
UI自动化测试体系 1.Andriod 自动化测试:Appium 环境安装与架构介绍.Appium Desktop用例录制.Appium测试用例流程.元素定位方法 IA/AID/XPATH/UISel ...
随机推荐
- [联赛可能考到]图论相关算法——COGS——联赛试题预测
COGS图论相关算法 最小生成树 Kruskal+ufs int ufs(int x) { return f[x] == x ? x : f[x] = ufs(f[x]); } int Kruskal ...
- [SP10628]Count on a tree
Description: 给定一颗n个点的树,有m个询问,求任意两点路径上点权第k小的点 Hint: \(n,m<=1e5\) Solution: 比较水 以每个点到根节点的数的前缀和建主席树 ...
- linux 常用命令解压压缩
tar -zxvf filename.tar.gz // 解包 tar -xvf filename.tar // 解包 tar -zcvf filename.tar.gz target // 制作ta ...
- java基础知识总结--继承和接口
什么是继承?什么是接口?他们之间的区别和联系是什么? 什么是继承? 继承是使用已存在的类的定义作为基础建立新类的技术,新类的定义可以增加新的数据或新的功能,也可以用父类的功能.多个类中存在相同属性和行 ...
- 转 asp.net mvc 身份验证中返回绝对路径的ReturnUrl
原文:http://www.cnblogs.com/hyl8218/archive/2011/11/22/2259116.html 从HttpUnauthorizedResult的源码可以看出,Htt ...
- ARMv8学习 —— SP_EL0和SP_ELx
在AArch64状态下,SP对应的物理寄存器有如下四个(某一时刻只能对应下面其中一个): SP_EL0和SP_EL1 SP_EL2 SP_EL3 如何使用呢? 1.如果程序运行在EL0,那么使用的是S ...
- Python调试打印错误信息
try: ..... except Exception, e: print 'repr(e):\t', repr(e)
- java 根据系统日期获取前一天、后一天时间(根据初始日期推算出期望(向前/向后)日期)
1.情景展示 java 根据系统当前日期获取前一天日期.后一天日期,或者根据初始日期推算出期望(向前/向后)日期. 2.解决方案 导包 import java.text.ParseExcepti ...
- [oracle] Oracle存储过程里操作BLOB的字节数据的办法,例如写入32位整数
作者: zyl910 一.缘由 BLOB是指二进制大对象,也就是英文Binary Large Object的缩写. 在很多时候,我们是通过其他编程语言(如Java)访问BLOB的字节数据,进行字节级的 ...
- VTK使用矢量数据弯曲几何体
vtkWarpVector is a filter that modifies point coordinates by moving points along vector times the sc ...