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 ...
随机推荐
- vue给methods中的方法传入当前点击行的值
<template> <!-- 在template中,只能存在一个根组件 --> <div class="event"> <ul> ...
- 【OpenCV】访问Mat中的每个像素值
其中注意i,j的位置,写错了好几次.第二个for循环中的if语句用异或来判断图像中哪些像素点发生了改变.
- Hass.io: add-on Configurator
{ "username": "admin", "password": "admin", "cert ...
- [P1516]青蛙的约会 (扩展欧几里得/中国剩余定理?)
每日做智推~ 一看就是一道数学题. 再看是一道公约数的题目. 标签是中国孙子定理. 题解是扩展欧几里得 (笑) 一开始没看数据范围 只有50分 开一个longlong就可以了 #include< ...
- redis:order set有序集合类型的操作(有序集合)
1. order set有序集合类型的操作(有序集合) 有序集合是在无序集合的基础上加了一个排序的依据,这个排序依据叫score,因此声明一个集合为有序集合的时候要加上score(作为排序的依据) 1 ...
- 增加tomcat的运行速度
1.增加tomcat的运行速度
- phpt5支付宝登陆支付接口解析
先看效果图 下面的源码来源网络,自己对照修改. 放入一个插件库中,方便管理 创建支付类 1.发起支付 public function init() { $order_id = $_REQUEST['o ...
- CSS 小技巧(不定时更新)
1.Web 文本中的省略号 在Web开发中,对于一种情况很常见.那就是,文本太长,而放置文本的容器不够长,而我们又不想让文本换行,所以,我们想使用省略号来解决这个问题.在今天HTML的标准中并没有相关 ...
- iOS 渐变提示。错误弹出提示 几秒自动消失
//事例 CGRect alertFarm = CGRectMake(,,,); [self noticeAlert:_bgView withNoticeStr:@"登录成功" w ...
- zigw 和 nanoWatch, libudev.so 和 XMR 挖矿程序查杀记录
最近这两天以来,服务器一致声音很响.本来以为有同事在运行大的程序,结果后来发现持续很长时间都是这样,并没有停的样子.后来查了一下,发现有几个可疑进程导致,干掉之后,果然服务器静悄悄了. 但是,问题并没 ...