Aollero/building impostor texture (#6379)
* Impostor texture SceneCapture component * SceneComponment distance issue solved with ortho camera * Dynamic Scene Component Creation * Procedural material duplication for new building * Generate Impostor Geometry * Impostor texture SceneCapture component * SceneComponment distance issue solved with ortho camera * Dynamic Scene Component Creation * Procedural material duplication for new building * Generate Impostor Geometry * Style updated * Update ProceduralBuildingUtilities.h * Ubuntu error fixed --------- Co-authored-by: aollero <aollero@cvc.uab.cat>
This commit is contained in:
parent
a9819fa289
commit
89a4cf29fc
|
@ -4,16 +4,88 @@
|
|||
#include "ProceduralBuildingUtilities.h"
|
||||
|
||||
#include "AssetRegistryModule.h"
|
||||
#include "Components/SceneCaptureComponent2D.h"
|
||||
#include "Components/StaticMeshComponent.h"
|
||||
#include "Engine/TextureRenderTarget2D.h"
|
||||
#include "FileHelpers.h"
|
||||
#include "GameFramework/Actor.h"
|
||||
#include "IMeshMergeUtilities.h"
|
||||
#include "Materials/MaterialInstanceConstant.h"
|
||||
#include "MeshMergeModule.h"
|
||||
#include "ProceduralMeshComponent.h"
|
||||
#include "UObject/Class.h"
|
||||
#include "UObject/UObjectGlobals.h"
|
||||
|
||||
void AProceduralBuildingUtilities::GenerateImpostor()
|
||||
void AProceduralBuildingUtilities::GenerateImpostorTexture(const FVector& BuildingSize)
|
||||
{
|
||||
// Not implemented yet.
|
||||
USceneCaptureComponent2D* Camera = NewObject<USceneCaptureComponent2D>(
|
||||
this, USceneCaptureComponent2D::StaticClass(), TEXT("ViewProjectionCaptureComponent"));
|
||||
|
||||
Camera->AttachToComponent(
|
||||
GetRootComponent(),
|
||||
FAttachmentTransformRules::SnapToTargetNotIncludingScale,
|
||||
FName("ViewProjectionCaptureComponentName"));
|
||||
AddInstanceComponent(Camera);
|
||||
Camera->OnComponentCreated();
|
||||
Camera->RegisterComponent();
|
||||
|
||||
check(Camera!=nullptr);
|
||||
|
||||
Camera->ProjectionType = ECameraProjectionMode::Orthographic;
|
||||
Camera->PrimitiveRenderMode = ESceneCapturePrimitiveRenderMode::PRM_UseShowOnlyList;
|
||||
Camera->CaptureSource = ESceneCaptureSource::SCS_BaseColor;
|
||||
|
||||
if(Camera->ShowOnlyActors.Num() == 0)
|
||||
{
|
||||
Camera->ShowOnlyActors.Add(this);
|
||||
}
|
||||
|
||||
SetTargetTextureToSceneCaptureComponent(Camera);
|
||||
|
||||
check(Camera->TextureTarget != nullptr);
|
||||
|
||||
// FRONT View
|
||||
RenderImpostorView(Camera, BuildingSize, EBuildingCameraView::FRONT);
|
||||
// LEFT View
|
||||
RenderImpostorView(Camera, BuildingSize, EBuildingCameraView::LEFT);
|
||||
// BACK View
|
||||
RenderImpostorView(Camera, BuildingSize, EBuildingCameraView::BACK);
|
||||
// RIGHT View
|
||||
RenderImpostorView(Camera, BuildingSize, EBuildingCameraView::RIGHT);
|
||||
|
||||
Camera->DestroyComponent();
|
||||
}
|
||||
|
||||
UProceduralMeshComponent* AProceduralBuildingUtilities::GenerateImpostorGeometry(const FVector& BuildingSize)
|
||||
{
|
||||
// Spawn procedural mesh actor / component
|
||||
UProceduralMeshComponent* Mesh = NewObject<UProceduralMeshComponent>(
|
||||
this, UProceduralMeshComponent::StaticClass(), TEXT("LOD Impostor Mesh"));
|
||||
|
||||
Mesh->AttachToComponent(
|
||||
GetRootComponent(),
|
||||
FAttachmentTransformRules::SnapToTargetNotIncludingScale,
|
||||
FName("LOD Impostor Mesh"));
|
||||
AddInstanceComponent(Mesh);
|
||||
Mesh->OnComponentCreated();
|
||||
Mesh->RegisterComponent();
|
||||
|
||||
check(Mesh != nullptr)
|
||||
|
||||
// FRONT View
|
||||
CreateBuildingImpostorGeometryForView(Mesh, BuildingSize, EBuildingCameraView::FRONT);
|
||||
// LEFT View
|
||||
CreateBuildingImpostorGeometryForView(Mesh, BuildingSize, EBuildingCameraView::LEFT);
|
||||
// BACK View
|
||||
CreateBuildingImpostorGeometryForView(Mesh, BuildingSize, EBuildingCameraView::BACK);
|
||||
// RIGHT View
|
||||
CreateBuildingImpostorGeometryForView(Mesh, BuildingSize, EBuildingCameraView::RIGHT);
|
||||
|
||||
return Mesh;
|
||||
|
||||
// Cook new mesh to a static mesh
|
||||
|
||||
// Assign as LOD or store on disk for manual import
|
||||
}
|
||||
|
||||
void AProceduralBuildingUtilities::CookProceduralBuildingToMesh(const FString& DestinationPath, const FString& FileName)
|
||||
|
@ -40,6 +112,7 @@ void AProceduralBuildingUtilities::CookProceduralBuildingToMesh(const FString& D
|
|||
|
||||
FString PackageName = DestinationPath + FileName;
|
||||
UPackage* NewPackage = CreatePackage(*PackageName);
|
||||
check(NewPackage);
|
||||
|
||||
const IMeshMergeUtilities& MeshUtilities = FModuleManager::Get().LoadModuleChecked<IMeshMergeModule>("MeshMergeUtilities").GetUtilities();
|
||||
MeshUtilities.MergeComponentsToStaticMesh(
|
||||
|
@ -64,3 +137,292 @@ void AProceduralBuildingUtilities::CookProceduralBuildingToMesh(const FString& D
|
|||
true,
|
||||
SAVE_NoError);
|
||||
}
|
||||
|
||||
void AProceduralBuildingUtilities::CookProceduralMeshToMesh(
|
||||
UProceduralMeshComponent* Mesh,
|
||||
const FString& DestinationPath,
|
||||
const FString& FileName)
|
||||
{
|
||||
FMeshDescription MeshDescription = BuildMeshDescription(Mesh);
|
||||
|
||||
FString PackageName = DestinationPath + FileName;
|
||||
UPackage* NewPackage = CreatePackage(*PackageName);
|
||||
check(NewPackage);
|
||||
|
||||
UStaticMesh* StaticMesh = NewObject<UStaticMesh>(NewPackage, *FileName, RF_Public | RF_Standalone);
|
||||
StaticMesh->InitResources();
|
||||
StaticMesh->LightingGuid = FGuid::NewGuid();
|
||||
|
||||
FStaticMeshSourceModel& SrcModel = StaticMesh->AddSourceModel();
|
||||
SrcModel.BuildSettings.bRecomputeNormals = false;
|
||||
SrcModel.BuildSettings.bRecomputeTangents = false;
|
||||
SrcModel.BuildSettings.bRemoveDegenerates = false;
|
||||
SrcModel.BuildSettings.bUseHighPrecisionTangentBasis = false;
|
||||
SrcModel.BuildSettings.bUseFullPrecisionUVs = false;
|
||||
SrcModel.BuildSettings.bGenerateLightmapUVs = true;
|
||||
SrcModel.BuildSettings.SrcLightmapIndex = 0;
|
||||
SrcModel.BuildSettings.DstLightmapIndex = 1;
|
||||
StaticMesh->CreateMeshDescription(0, MoveTemp(MeshDescription));
|
||||
StaticMesh->CommitMeshDescription(0);
|
||||
|
||||
if (!Mesh->bUseComplexAsSimpleCollision )
|
||||
{
|
||||
StaticMesh->CreateBodySetup();
|
||||
UBodySetup* NewBodySetup = StaticMesh->BodySetup;
|
||||
NewBodySetup->BodySetupGuid = FGuid::NewGuid();
|
||||
NewBodySetup->AggGeom.ConvexElems = Mesh->ProcMeshBodySetup->AggGeom.ConvexElems;
|
||||
NewBodySetup->bGenerateMirroredCollision = false;
|
||||
NewBodySetup->bDoubleSidedGeometry = true;
|
||||
NewBodySetup->CollisionTraceFlag = CTF_UseDefault;
|
||||
NewBodySetup->CreatePhysicsMeshes();
|
||||
}
|
||||
|
||||
TSet<UMaterialInterface*> UniqueMaterials;
|
||||
const int32 NumSections = Mesh->GetNumSections();
|
||||
for (int32 SectionIdx = 0; SectionIdx < NumSections; SectionIdx++)
|
||||
{
|
||||
FProcMeshSection *ProcSection =
|
||||
Mesh->GetProcMeshSection(SectionIdx);
|
||||
UMaterialInterface *Material = Mesh->GetMaterial(SectionIdx);
|
||||
UniqueMaterials.Add(Material);
|
||||
}
|
||||
|
||||
for (auto* Material : UniqueMaterials)
|
||||
{
|
||||
StaticMesh->StaticMaterials.Add(FStaticMaterial(Material));
|
||||
}
|
||||
|
||||
StaticMesh->ImportVersion = EImportStaticMeshVersion::LastVersion;
|
||||
StaticMesh->Build(false);
|
||||
StaticMesh->PostEditChange();
|
||||
FAssetRegistryModule::AssetCreated(StaticMesh);
|
||||
|
||||
UPackage::SavePackage(NewPackage,
|
||||
StaticMesh,
|
||||
EObjectFlags::RF_Public | EObjectFlags::RF_Standalone,
|
||||
*FileName,
|
||||
GError,
|
||||
nullptr,
|
||||
true,
|
||||
true,
|
||||
SAVE_NoError);
|
||||
}
|
||||
|
||||
UMaterialInstanceConstant* AProceduralBuildingUtilities::GenerateBuildingMaterialAsset(
|
||||
const FString& DuplicateParentPath,
|
||||
const FString& DestinationPath,
|
||||
const FString& FileName)
|
||||
{
|
||||
const FString BaseMaterialSearchPath = DuplicateParentPath;
|
||||
const FString PackageName = DestinationPath + FileName;
|
||||
|
||||
UMaterialInstanceConstant* ParentMaterial = LoadObject<UMaterialInstanceConstant>(nullptr, *BaseMaterialSearchPath);
|
||||
|
||||
check(ParentMaterial != nullptr);
|
||||
|
||||
UPackage* NewPackage = CreatePackage(*PackageName);
|
||||
FObjectDuplicationParameters Parameters(ParentMaterial, NewPackage);
|
||||
Parameters.DestName = FName(FileName);
|
||||
Parameters.DestClass = ParentMaterial->GetClass();
|
||||
Parameters.DuplicateMode = EDuplicateMode::Normal;
|
||||
Parameters.PortFlags = PPF_Duplicate;
|
||||
|
||||
UMaterialInstanceConstant* DuplicatedMaterial = CastChecked<UMaterialInstanceConstant>(StaticDuplicateObjectEx(Parameters));
|
||||
|
||||
const FString PackageFileName = FPackageName::LongPackageNameToFilename(
|
||||
PackageName,
|
||||
".uasset");
|
||||
UPackage::SavePackage(NewPackage, DuplicatedMaterial, EObjectFlags::RF_Public | EObjectFlags::RF_Standalone,
|
||||
*PackageFileName, GError, nullptr, true, true, SAVE_NoError);
|
||||
|
||||
return DuplicatedMaterial;
|
||||
}
|
||||
|
||||
void AProceduralBuildingUtilities::RenderImpostorView(
|
||||
USceneCaptureComponent2D* Camera,
|
||||
const FVector BuildingSize,
|
||||
const EBuildingCameraView View)
|
||||
{
|
||||
MoveCameraToViewPosition(Camera, BuildingSize, View);
|
||||
Camera->CaptureScene();
|
||||
UTextureRenderTarget2D* CameraRT = Camera->TextureTarget;
|
||||
UTexture2D* ViewTexture = CameraRT->ConstructTexture2D(GetWorld(), FString("View_").Append(FString::FromInt(View)), EObjectFlags::RF_NoFlags );
|
||||
BakeSceneCaptureRTToTextureAtlas(ViewTexture, View);
|
||||
}
|
||||
|
||||
void AProceduralBuildingUtilities::MoveCameraToViewPosition(
|
||||
USceneCaptureComponent2D* Camera,
|
||||
const FVector BuildingSize,
|
||||
const EBuildingCameraView View)
|
||||
{
|
||||
const float BuildingHeight = BuildingSize.Z;
|
||||
float ViewAngle = 0.f;
|
||||
float BuildingWidth = 0.f;
|
||||
float BuildingDepth = 0.f;
|
||||
|
||||
GetWidthDepthFromView(BuildingSize, View, BuildingWidth, BuildingDepth, ViewAngle);
|
||||
|
||||
/* ORTHO */
|
||||
float ViewOrthoWidth = FMath::Max(BuildingWidth, BuildingHeight);
|
||||
Camera->OrthoWidth = ViewOrthoWidth;
|
||||
|
||||
float CameraDistance = 0.5f * BuildingDepth + 1000.f;
|
||||
|
||||
FVector NewCameraLocation(
|
||||
CameraDistance * FMath::Cos(FMath::DegreesToRadians(ViewAngle)),
|
||||
CameraDistance * FMath::Sin(FMath::DegreesToRadians(ViewAngle)),
|
||||
BuildingSize.Z / 2.0f);
|
||||
|
||||
FRotator NewCameraRotation(0.0f, ViewAngle + 180.f, 0.0f);
|
||||
|
||||
Camera->SetRelativeLocationAndRotation(NewCameraLocation, NewCameraRotation, false, nullptr, ETeleportType::None);
|
||||
}
|
||||
|
||||
void AProceduralBuildingUtilities::CreateBuildingImpostorGeometryForView(
|
||||
UProceduralMeshComponent* Mesh,
|
||||
const FVector& BuildingSize,
|
||||
const EBuildingCameraView View)
|
||||
{
|
||||
// Create vertices based on Building Size
|
||||
TArray<FVector> Vertices;
|
||||
TArray<int32> Triangles;
|
||||
|
||||
const float BuildingHeight = BuildingSize.Z;
|
||||
float BuildingWidth = 0.f;
|
||||
float BuildingDepth = 0.f;
|
||||
float ViewAngle = 0.f;
|
||||
|
||||
GetWidthDepthFromView(BuildingSize, View, BuildingWidth, BuildingDepth, ViewAngle);
|
||||
|
||||
FVector RotationAxis(0.0f, 0.0f, 1.0f);
|
||||
FVector OriginOffset(- 0.5f * BuildingDepth, - 0.5f * BuildingWidth, 0.0f);
|
||||
|
||||
// Vertices are created in local space, then offsetted to compensate origin and finally rotating
|
||||
// according to the ViewAngle
|
||||
Vertices.Add((FVector(0.0f, 0.0f, 0.0f) + OriginOffset).RotateAngleAxis(ViewAngle, RotationAxis));
|
||||
Vertices.Add((FVector(0.0f, 0.0f, BuildingHeight) + OriginOffset).RotateAngleAxis(ViewAngle, RotationAxis));
|
||||
Vertices.Add((FVector(0.0f, BuildingWidth, 0.0f) + OriginOffset).RotateAngleAxis(ViewAngle, RotationAxis));
|
||||
Vertices.Add((FVector(0.0f, BuildingWidth, BuildingHeight) + OriginOffset).RotateAngleAxis(ViewAngle, RotationAxis));
|
||||
|
||||
Triangles.Add(0); Triangles.Add(2); Triangles.Add(1);
|
||||
Triangles.Add(2); Triangles.Add(3); Triangles.Add(1);
|
||||
|
||||
TArray<FVector2D> UVs;
|
||||
CalculateViewGeometryUVs(BuildingWidth, BuildingHeight, View, UVs);
|
||||
|
||||
TArray<FVector> Normals;
|
||||
Normals.Init(FVector(-1.0f, 0.0f, 0.0f).RotateAngleAxis(ViewAngle, RotationAxis), Vertices.Num());
|
||||
|
||||
TArray<FLinearColor> Colors;
|
||||
Colors.Init(FLinearColor(0.0f, 0.0f, 0.0f, 1.0f), Vertices.Num());
|
||||
|
||||
TArray<FProcMeshTangent> Tangents;
|
||||
// Tangents.Init(FProcMeshTangent(-1.0f, -1.0f, -1.0f).RotateAngleAxis(ViewAngle, RotationAxis), Vertices.Num());
|
||||
Tangents.Init(FProcMeshTangent(FVector(0.0f, 1.0f, 0.0f).RotateAngleAxis(ViewAngle, RotationAxis), false), Vertices.Num());
|
||||
|
||||
Mesh->CreateMeshSection_LinearColor((int32)View, Vertices, Triangles, Normals, UVs, Colors, Tangents, false);
|
||||
}
|
||||
|
||||
void AProceduralBuildingUtilities::GetWidthDepthFromView(
|
||||
const FVector& BuildingSize,
|
||||
const EBuildingCameraView View,
|
||||
float& OutWidth,
|
||||
float& OutDepth,
|
||||
float& OutViewAngle)
|
||||
{
|
||||
switch(View)
|
||||
{
|
||||
case EBuildingCameraView::FRONT:
|
||||
OutViewAngle = 0.0f;
|
||||
OutWidth = FMath::Abs(BuildingSize.Y);
|
||||
OutDepth = FMath::Abs(BuildingSize.X);
|
||||
break;
|
||||
|
||||
case EBuildingCameraView::LEFT:
|
||||
OutViewAngle = 90.0f;
|
||||
OutWidth = FMath::Abs(BuildingSize.X);
|
||||
OutDepth = FMath::Abs(BuildingSize.Y);
|
||||
break;
|
||||
|
||||
case EBuildingCameraView::BACK:
|
||||
OutViewAngle = 180.0f;
|
||||
OutWidth = FMath::Abs(BuildingSize.Y);
|
||||
OutDepth = FMath::Abs(BuildingSize.X);
|
||||
break;
|
||||
|
||||
case EBuildingCameraView::RIGHT:
|
||||
OutViewAngle = 270.0f;
|
||||
OutWidth = FMath::Abs(BuildingSize.X);
|
||||
OutDepth = FMath::Abs(BuildingSize.Y);
|
||||
break;
|
||||
|
||||
default:
|
||||
OutViewAngle = 0.0f;
|
||||
OutWidth = 0.0f;
|
||||
OutDepth = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
void AProceduralBuildingUtilities::CalculateViewGeometryUVs(
|
||||
const float BuildingWidth,
|
||||
const float BuildingHeight,
|
||||
const EBuildingCameraView View,
|
||||
TArray<FVector2D>& OutUVs)
|
||||
{
|
||||
// Calculate UVs from 0 to 1
|
||||
// ------------
|
||||
// | uv1 uv3 |
|
||||
// | uv0 uv2 |
|
||||
// ------------
|
||||
|
||||
FVector2D OriginOffset;
|
||||
switch(View)
|
||||
{
|
||||
case EBuildingCameraView::FRONT:
|
||||
OriginOffset = FVector2D(0.3f, 0.3f);
|
||||
break;
|
||||
|
||||
case EBuildingCameraView::LEFT:
|
||||
OriginOffset = FVector2D(0.3f, 0.4f);
|
||||
break;
|
||||
|
||||
case EBuildingCameraView::BACK:
|
||||
OriginOffset = FVector2D(0.4f, 0.3f);
|
||||
break;
|
||||
|
||||
case EBuildingCameraView::RIGHT:
|
||||
OriginOffset = FVector2D(0.4f, 0.4f);
|
||||
break;
|
||||
|
||||
default:
|
||||
OriginOffset = FVector2D(0.0f, 0.0f);
|
||||
}
|
||||
|
||||
float WidthRatio = BuildingWidth / BuildingHeight;
|
||||
float HeightRatio = BuildingHeight / BuildingWidth;
|
||||
|
||||
FVector2D X0, X1, X2, X3;
|
||||
|
||||
if(WidthRatio < 1.0f)
|
||||
{
|
||||
// Fit Vertically
|
||||
X0 = FVector2D(0.05f - 0.05f * WidthRatio, 0.1f) + OriginOffset;
|
||||
X1 = FVector2D(0.05f - 0.05f * WidthRatio, 0.0f) + OriginOffset;
|
||||
X2 = FVector2D(0.05f + 0.05f * WidthRatio, 0.1f) + OriginOffset;
|
||||
X3 = FVector2D(0.05f + 0.05f * WidthRatio, 0.0f) + OriginOffset;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fit Horizontally
|
||||
X0 = FVector2D(0.0f, 0.05f + 0.05f * HeightRatio) + OriginOffset;
|
||||
X1 = FVector2D(0.0f, 0.05f - 0.05f * HeightRatio) + OriginOffset;
|
||||
X2 = FVector2D(0.1f, 0.05f + 0.05f * HeightRatio) + OriginOffset;
|
||||
X3 = FVector2D(0.1f, 0.05f - 0.05f * HeightRatio) + OriginOffset;
|
||||
}
|
||||
|
||||
// Fix offset to fit in view quadrant
|
||||
OutUVs.Add(X0);
|
||||
OutUVs.Add(X1);
|
||||
OutUVs.Add(X2);
|
||||
OutUVs.Add(X3);
|
||||
}
|
||||
|
|
|
@ -6,7 +6,17 @@
|
|||
#include "EditorUtilityActor.h"
|
||||
#include "ProceduralBuildingUtilities.generated.h"
|
||||
|
||||
struct FIntRect;
|
||||
class USceneCaptureComponent2D;
|
||||
class UTexture2D;
|
||||
|
||||
UENUM(BlueprintType)
|
||||
enum EBuildingCameraView
|
||||
{
|
||||
FRONT,
|
||||
LEFT,
|
||||
BACK,
|
||||
RIGHT
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -17,10 +27,49 @@ class CARLATOOLS_API AProceduralBuildingUtilities : public AEditorUtilityActor
|
|||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
UFUNCTION(BlueprintImplementableEvent, Category="Procedural Building Utilities")
|
||||
void BakeSceneCaptureRTToTextureAtlas(UTexture2D* SceneCaptureRT, EBuildingCameraView TargetView);
|
||||
|
||||
UFUNCTION(BlueprintImplementableEvent, Category="Procedural Building Utilities")
|
||||
void SetTargetTextureToSceneCaptureComponent(USceneCaptureComponent2D* SceneCaptureComponent);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category="Procedural Building Utilities")
|
||||
void GenerateImpostor();
|
||||
void GenerateImpostorTexture(const FVector& BuildingSize);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category="Procedural Building Utilities")
|
||||
class UProceduralMeshComponent* GenerateImpostorGeometry(const FVector& BuildingSize);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category="Procedural Building Utilities")
|
||||
void CookProceduralBuildingToMesh(const FString& DestinationPath, const FString& FileName);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category="Procedural Building Utilities")
|
||||
void CookProceduralMeshToMesh(class UProceduralMeshComponent* Mesh, const FString& DestinationPath, const FString& FileName);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category="Procedural Building Utilities")
|
||||
class UMaterialInstanceConstant* GenerateBuildingMaterialAsset(
|
||||
const FString& DuplicateParentPath,
|
||||
const FString& DestinationPath,
|
||||
const FString& FileName);
|
||||
|
||||
private:
|
||||
void RenderImpostorView(USceneCaptureComponent2D* Camera, const FVector BuildingSize, const EBuildingCameraView View);
|
||||
void MoveCameraToViewPosition(USceneCaptureComponent2D* Camera, const FVector BuildingSize, const EBuildingCameraView View);
|
||||
|
||||
void CreateBuildingImpostorGeometryForView(
|
||||
class UProceduralMeshComponent* Mesh,
|
||||
const FVector& BuildingSize,
|
||||
const EBuildingCameraView View);
|
||||
|
||||
void GetWidthDepthFromView(
|
||||
const FVector& BuildingSize,
|
||||
const EBuildingCameraView View,
|
||||
float& OutWidth, float& OutDepth,
|
||||
float& OutViewAngle);
|
||||
|
||||
void CalculateViewGeometryUVs(
|
||||
const float BuildingWidth,
|
||||
const float BuildingHeight,
|
||||
const EBuildingCameraView View,
|
||||
TArray<FVector2D>& OutUVs);
|
||||
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue