• 做个小工具显示UE里地形的高度图和权重图


    目标

    做一个小工具来显示UE里 Landscape(启用编辑层)的高度图和权重图。

    要显示高度图和权重图,本身是不难的。不过这里想要不修改引擎源码。所以是在外部(比如项目工程模块,或插件模块)做了事情。

    地形高度图和权重图的数据结构

    可在 LandscapeComponent.h 中观察到数据结构。

    在启用编辑层的情况下,数据在LayersData中,每个编辑层对应一个GUID

    UPROPERTY()
    TMap<FGuid, FLandscapeLayerComponentData> LayersData;
    
    • 1
    • 2

    每个 FLandscapeLayerComponentData包含一个FHeightmapData和一个FWeightmapData

    USTRUCT(NotBlueprintable)
    struct FLandscapeLayerComponentData
    {
    	GENERATED_USTRUCT_BODY()
    
    	UPROPERTY()
    	FHeightmapData HeightmapData;
    
    	UPROPERTY()
    	FWeightmapData WeightmapData;
    
    	bool IsInitialized() const { return HeightmapData.Texture != nullptr || WeightmapData.Textures.Num() > 0;  }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    FHeightmapData包含一个贴图:

    USTRUCT(NotBlueprintable)
    struct FHeightmapData
    {
    	GENERATED_USTRUCT_BODY()
    
    	UPROPERTY()
    	UTexture2D* Texture;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    FWeightmapData包含多个贴图(因为可能有很多权重层):

    USTRUCT(NotBlueprintable)
    struct FWeightmapData
    {
    	GENERATED_USTRUCT_BODY()
    
    	UPROPERTY()
    	TArray<UTexture2D*> Textures;
    	
    	UPROPERTY()
    	TArray<FWeightmapLayerAllocationInfo> LayerAllocations;
    
    	UPROPERTY(Transient)
    	TArray<ULandscapeWeightmapUsage*> TextureUsages;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    小工具

    流程和之前一样,先定义一个UObject。

    为了能在Detail面板看到相关的贴图,这里将原来的结构体换成了新的后缀为 _vis 的结构体,并将UProperty加上VisibleAnywhere。然后,提供一个按钮,也就是FindLandscapeTextures()函数,触发后找到世界中的地形,并将其数据复制过来。(目前,只观察第一个找到的地形的第一个Component)

    代码如下:

    LandscapeTextureWatcher.h

    #pragma once
    
    #include "UObject/Object.h"
    #include "Landscape/Classes/LandscapeComponent.h"
    
    #include "LandscapeTextureWatcher.generated.h"
    
    USTRUCT(NotBlueprintable)
    struct FWeightmapData_vis
    {
    	GENERATED_USTRUCT_BODY()
    
    	UPROPERTY(VisibleAnywhere)
    	TArray<UTexture2D*> Textures;
    	
    	UPROPERTY(VisibleAnywhere)
    	TArray<FWeightmapLayerAllocationInfo> LayerAllocations;
    
    	UPROPERTY(Transient)
    	TArray<ULandscapeWeightmapUsage*> TextureUsages;
    };
    
    USTRUCT(NotBlueprintable)
    struct FHeightmapData_vis
    {
    	GENERATED_USTRUCT_BODY()
    
    	UPROPERTY(VisibleAnywhere)
    	UTexture2D* Texture;
    };
    
    USTRUCT(NotBlueprintable)
    struct FLandscapeLayerComponentData_vis
    {
    	GENERATED_USTRUCT_BODY()
    
    	UPROPERTY(VisibleAnywhere)
    	FHeightmapData_vis HeightmapData;
    
    	UPROPERTY(VisibleAnywhere)
    	FWeightmapData_vis WeightmapData;
    
    	bool IsInitialized() const { return HeightmapData.Texture != nullptr || WeightmapData.Textures.Num() > 0;  }
    };
    
    UCLASS(Blueprintable)
    class ULandscapeTextureWatcher : public UObject
    {
    	GENERATED_UCLASS_BODY()
    public:
    	
    	//按钮,点击后就把地形的纹理数据拿来
    	UFUNCTION(CallInEditor)
    	void FindLandscapeTextures();
    
    	//要观察的地形纹理数据:
    	UPROPERTY(VisibleAnywhere)
    	TMap<FGuid, FLandscapeLayerComponentData_vis> LayersData;
    };
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60

    LandscapeTextureWatcher.cpp

    #include "LandscapeTextureWatcher.h"
    #include "Kismet/GameplayStatics.h"
    #include "Editor.h"
    #include "LandscapeInfo.h"
    #include "Landscape/Classes/Landscape.h"
    
    ULandscapeTextureWatcher::ULandscapeTextureWatcher(const FObjectInitializer& ObjectInitializer)
    	: Super(ObjectInitializer)
    {}
    
    void ULandscapeTextureWatcher::FindLandscapeTextures()
    {
    	//得到World
    	const UWorld* World = GEditor->GetEditorWorldContext().World();
    
    	//找地形:
    	TArray<AActor*> OutActors;
    	UGameplayStatics::GetAllActorsOfClass(World, ALandscape::StaticClass(), OutActors);
    	//没找到则直接返回
    	if (OutActors.Num() == 0)
    		return;
    	//找到则用第一个Landscape:
    	ALandscape* Landscape = (ALandscape*)OutActors[0];
    
    	if (Landscape->LandscapeComponents.Num() == 0)
    		return;
    	//使用第一个Component:
    	ULandscapeComponent* LandscapeComponent = Landscape->LandscapeComponents[0];
    
    	//遍历所有layer,填入数据
    	LandscapeComponent->ForEachLayer([&](const FGuid& LayerGuid, FLandscapeLayerComponentData& LayerData)
    	{
    		FLandscapeLayerComponentData_vis data;
    		data.HeightmapData.Texture = LayerData.HeightmapData.Texture;
    		data.WeightmapData.Textures = LayerData.WeightmapData.Textures;
    		LayersData.Add(LayerGuid, data);
    	});
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    然后,仿照之前第(3)步,显示其Detail面板。

    效果

    开启编辑层功能创建地形,注意只创建一个Component(因为暂时只观察第一个Component)
    创建两个编辑层,并且使用的地形材质有五个权重层。
    结果如下:
    在这里插入图片描述
    虽然上面看到贴图是黑的,但是因为Alpha通道是0,可以直接打开贴图关闭alpha通道看效果。

    高度图:
    在这里插入图片描述

    权重图,可以看出每层各占一个通道:
    在这里插入图片描述

  • 相关阅读:
    ModelBox实战开发:RK3568实现摄像头虚拟背景
    2022/7/20 LocalDateTime将年月日转化为时间戳
    20220726
    JSTL(jsp标准标签库)
    计算机视觉 基于CUDA编程的入门与实践
    Vue的渲染原理
    我用Python写个适合自己游戏的协议测试(接口测试)工具/抓包工具
    【Linux】一万七千字详解 —— 基本指令(二)
    详解:整合SSM
    第三章 关系数据库标准语言SQL
  • 原文地址:https://blog.csdn.net/u013412391/article/details/127416032