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 ...
随机推荐
- 可以直接用的“ html转字符串string”方法
//html转字符串 -(NSString *)filterHTMLString:(NSString *)html { NSScanner * scanner = [NSScanner scanner ...
- ios真机中Text组件出现多余边框
问题 ios真机中Text组件出现多余边框(模拟器不会出现,真机会出现该问题). 原因 在ios启动页设置中,预设的尺寸要求与设置中图片尺寸不符合导致屏幕精度计算出现问题(启动屏分辨率错误设置会导致手 ...
- db2 reorgchk
db2 reorgchk 命令是最重要的.也是经常被忽略的 DB2 调整命令之一. db2 reorgchk 命令被忽略是因为它不是一个一次性调整项.由于更新是在 DB2 数据库上执行的,因此关于表的 ...
- elastic-job详解(四):失效转移
elastic-job中最关键的特性之一就是失效转移.配置了失效转移之后,如果在任务执行过程中有一个执行实例挂了,那么之前被分配到这个实例的任务(或者分片)会在下次任务执行之前被重新分配到其他正常节点 ...
- web 和 java 资源
1.自己按照上面的网址和密码自己去下载都那些视频都是vip的视频现在下载免费 7-17JAVA开发搜索引擎自动提示[优效学院向天] 链接:http://pan.baidu.com/s/1bpEkfR ...
- 模拟位置 定位 钉钉打卡 运动轨迹 MD
Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...
- bootstrap-3-上传图片-列表显示
效果 导入的js和css <!-- 最新版本的 Bootstrap 核心 CSS 文件 --> <link rel="stylesheet" href=" ...
- hadoop-网站收藏
Ubuntu14.04安装配置Hadoop2.6.0(完全分布式)与 wordcount实例运行 http://www.linuxidc.com/Linux/2015-01/112029p2.htm ...
- MYSQL常用的性能指标总结和归纳
(1) QPS(每秒Query量)QPS = Questions(or Queries) / uptimemysql> show global status like 'Question%';m ...
- jQuery数据转换与提交
json2.js序列化,即JSON对象转换成String字符串: JSON.stringify({ id: 1, name: 'jsons' }); 反序列化,即String转JSON对象: JSON ...