Редактирование объекта в 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();
};
по коду должна генерироваться сфера с кратером. Сама сфера генерируется, после передачи данных сферы с кратером просто нету. Вместо генерации кратера, у меня генерируется по новой планета и деформируется крайне плохо ,настолько, что землю выворачивает в обратную сторону. Почему так происходит и как это решить?