Редактирование объекта в UE5

CratorSphere.cpp:

#include "CraterSphere.h"
#include "UObject/ConstructorHelpers.h"
#include "Materials/MaterialInterface.h"
#include "Engine/Engine.h"


ACraterSphere::ACraterSphere()
{
    PrimaryActorTick.bCanEverTick = true;

    // Создание компонента ProceduralMesh
    ProceduralMesh = CreateDefaultSubobject<UProceduralMeshComponent>(TEXT("ProceduralMesh"));
    RootComponent = ProceduralMesh;

    // Устанавливаем поворот на 90 градусов
    SetActorRotation(FRotator(-90.0f, -90.0f, -90.0f));

    // Загружаем материал для планеты
    static ConstructorHelpers::FObjectFinder<UMaterialInterface> Material(TEXT("Material'/Game/Astronomy/M_Planet.M_Planet'"));
    if (Material.Succeeded())
    {
        PlanetMaterial = Material.Object;
    }
}

void ACraterSphere::BeginPlay()
{
    Super::BeginPlay();
    GenerateSphere();
    ApplyMaterial(); // Применяем материал после генерации
}

void ACraterSphere::Tick(float DeltaTime)
{
    Super::Tick(DeltaTime);
}

//  Функция генерации сферы с UV-разверткой
void ACraterSphere::GenerateSphere()
{
    const int32 Resolution = 64;  // Разрешение сетки
    const float Radius = 500.0f;  // Радиус Земли в сантиметрах
    TArray<int32> Triangles;
    TArray<FVector> Normals;
    TArray<FVector2D> UVs;

    StoredVertices.Empty(); // Очищаем перед заполнением

    // Генерация вершин с разверткой UV
    for (int32 Lat = 0; Lat <= Resolution; Lat++)
    {
        float Theta = Lat * PI / Resolution;  // широта
        for (int32 Lon = 0; Lon <= Resolution; Lon++)
        {
            float Phi = Lon * 2 * PI / Resolution;  // долгота
            float X = Radius * FMath::Sin(Theta) * FMath::Cos(Phi);
            float Y = Radius * FMath::Sin(Theta) * FMath::Sin(Phi);
            float Z = Radius * FMath::Cos(Theta);

            float U = Lon / (float)Resolution;  // Долгота
            float V = Lat / (float)Resolution;  // Широта

            StoredVertices.Add(FVector(X, Y, Z));
            Normals.Add(FVector(X, Y, Z).GetSafeNormal());
            UVs.Add(FVector2D(U, V));  // Сферическая развертка
        }
    }

    // Генерация треугольников для сферы
    for (int32 Lat = 0; Lat < Resolution; Lat++)
    {
        for (int32 Lon = 0; Lon < Resolution; Lon++)
        {
            int32 Current = Lat * (Resolution + 1) + Lon;
            int32 Next = Current + Resolution + 1;

            Triangles.Add(Current);
            Triangles.Add(Next);
            Triangles.Add(Current + 1);

            Triangles.Add(Next);
            Triangles.Add(Next + 1);
            Triangles.Add(Current + 1);
        }
    }

    // Создаем меш с переданными вершинами
    ProceduralMesh->CreateMeshSection(0, StoredVertices, Triangles, Normals, UVs, {}, {}, true);

    // Применяем материал к планете
    if (PlanetMaterial)
    {
        ProceduralMesh->SetMaterial(0, PlanetMaterial);
    }
}

//  Применение материала "M_Planet"
void ACraterSphere::ApplyMaterial()
{
    if (PlanetMaterial)
    {
        ProceduralMesh->SetMaterial(0, PlanetMaterial);
    }
    else
    {
        UE_LOG(LogTemp, Warning, TEXT("material M_Planet wasnt able to find."));
    }
}

//  Функция создания кратера
void ACraterSphere::ApplyCrater(FVector CraterPosition, float CraterDiameter, float CraterDepth)
{
    if (StoredVertices.Num() == 0) return; // Проверяем, есть ли вершины

    FVector SphereCenter = FVector(0, 0, 0);  // Центр сферы
    float Radius = 500.0f;

    UE_LOG(LogTemp, Warning, TEXT("Before crater: First vertex = (%f, %f, %f)"),
        StoredVertices[0].X, StoredVertices[0].Y, StoredVertices[0].Z);

    for (FVector& Vertex : StoredVertices)
    {
        float Distance = FVector::Dist(Vertex, CraterPosition);

        // Проверяем, находится ли вершина в зоне кратера
        if (Distance < CraterDiameter / 2.0f)
        {
            // Вычисляем направление от центра сферы к вершине
            FVector Direction = (Vertex - SphereCenter).GetSafeNormal();

            // Смещаем вершину ВДОЛЬ нормали, но ограничиваем изменение
            float DepthFactor = FMath::Clamp(1.0f - (Distance / (CraterDiameter / 2.0f)), 0.0f, 1.0f);
            FVector Offset = Direction * (-CraterDepth * DepthFactor);

            // Убеждаемся, что вершина не уходит за границы сферы
            FVector NewVertex = Vertex + Offset;
            if (FVector::Dist(NewVertex, SphereCenter) < Radius * 0.5f)  // Ограничение смещения
            {
                NewVertex = SphereCenter + Direction * (Radius * 0.5f);
            }

            Vertex = NewVertex;
        }
    }

    UE_LOG(LogTemp, Warning, TEXT("After crater: First vertex = (%f, %f, %f)"),
        StoredVertices[0].X, StoredVertices[0].Y, StoredVertices[0].Z);

    ProceduralMesh->UpdateMeshSection(0, StoredVertices, {}, {}, {}, {});
}

CratorSphere.h:

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "ProceduralMeshComponent.h"
#include "CraterSphere.generated.h"

UCLASS()
class NPK_API ACraterSphere : public AActor
{
    GENERATED_BODY()

public:
    ACraterSphere();

protected:
    virtual void BeginPlay() override;

public:
    virtual void Tick(float DeltaTime) override;

    UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = "Mesh")
    UProceduralMeshComponent* ProceduralMesh;

    UFUNCTION(BlueprintCallable, Category = "Crater")
    void GenerateSphere();

    UFUNCTION(BlueprintCallable, Category = "Crater")
    void ApplyCrater(FVector CraterPosition, float CraterDiameter, float CraterDepth);

private:
    TArray<FVector> StoredVertices; // Храним вершины, чтобы обновлять их позже
    UMaterialInterface* PlanetMaterial; // Материал для планеты

    void ApplyMaterial();
};

по коду должна генерироваться сфера с кратером. Сама сфера генерируется, после передачи данных сферы с кратером просто нету. Вместо генерации кратера, у меня генерируется по новой планета и деформируется крайне плохо ,настолько, что землю выворачивает в обратную сторону. Почему так происходит и как это решить?


Ответы (0 шт):