Unreal порт для Zelda Wall MergeC++

Программы на C++. Форум разработчиков
Ответить
Anonymous
 Unreal порт для Zelda Wall Merge

Сообщение Anonymous »

Описание проблемы
Я следовал руководству по движку Unity, чтобы создать функцию слияния стен из zelda в движке Unreal, и я реализовал алгоритм, как описано в руководстве.
Система работает правильно, когда угол между двумя гранями стен составляет ровно 90°, но перестает работать, когда угол равен любому другому (например, 120°, 135° и т. д.).
Признаки:
  • Вращение выходит за пределы или за пределы целевой стены.
  • Отлично работает для углов 90 градусов.
Я подозреваю, что проблема связана с расчетами расстояния до поворота, поскольку я предполагаю, что угол равен 90 градусов, но я не уверен, как отрегулировать его для произвольных углов.

Минимальный воспроизводимый пример

Код: Выделить всё

    struct FMeshPoint
{
FVector Position;
FVector Normal;
};

TArray MeshPoints;
TArray CornerPoints;

float OffsetMargin = 0.1f;
float StepSize = 50.f;
int32 MaxSteps = 150;

void FindNext(const FVector& StartPoint, const FVector& StartNormal)
{
// Store current point
MeshPoints.Add({ StartPoint, StartNormal });

// Detect corner when surface normal changes
if (MeshPoints.Num() > 1)
{
const FVector PrevNormal = MeshPoints.Last(1).Normal;

// Threshold works for 90° corners, fails for others
if (PrevNormal.Dot(StartNormal) < 0.98f)
{
CornerPoints.Add({ StartPoint, StartNormal });
}
}

if (MeshPoints.Num() >= MaxSteps)
return;

// Tangent along the wall
const FVector Tangent = FVector::CrossProduct(StartNormal, FVector::UpVector).GetSafeNormal();

// Offset slightly off the wall to avoid self-hit
const FVector TraceStart = StartPoint + StartNormal * OffsetMargin;
const FVector TraceEnd = TraceStart + Tangent * StepSize;

FHitResult Hit;
const bool bHit = GetWorld()->LineTraceSingleByChannel(
Hit,
TraceStart,
TraceEnd,
ECC_WorldStatic
);

if (bHit)
{
FindNext(Hit.ImpactPoint, Hit.ImpactNormal);
}
}

void WallMove(float AxisValue, float DeltaTime)
{
const FVector Desired =
AxisValue > 0 ? Target.Position : Origin.Position;

ActorPosition = FMath::VInterpConstantTo(ActorPosition, Desired, DeltaTime, FMath::Abs(AxisValue) * 200.f);

const float DistFromOrigin = FVector::Distance(ActorPosition, Origin.Position);

const float TotalDist = FVector::Distance(Origin.Position, Target.Position);

if (DistFromOrigin < DistanceToTurn || DistFromOrigin > TotalDist - DistanceToTurn)
{
StartRotation(AxisValue > 0);
}
}

void StartRotation(bool bRight)
{
RotationLerp = 0.f;
CurrentNormal = CurrentNormal.GetSafeNormal();
TargetNormal  = Target.Normal.GetSafeNormal();

PivotPoint = ComputePivotPoint(Origin.Position, Target.Position, CurrentNormal, DistanceToTurn);
}

void CornerRotate(float AxisValue, float DeltaTime)
{
RotationLerp = FMath::Clamp( RotationLerp + AxisValue * DeltaTime * RotationSpeed, 0.f, 1.f);

// Works for 90°, breaks for arbitrary angles
const FVector BlendedNormal = FMath::Lerp(CurrentNormal, TargetNormal, RotationLerp).GetSafeNormal();

// Actor is rotated around PivotPoint
ActorPosition = PivotPoint + (ActorPosition - PivotPoint) .RotateAngleAxis( FMath::RadiansToDegrees( FMath::Acos( FVector::DotProduct(CurrentNormal, BlendedNormal) ) ), FVector::UpVector);
}

FVector ComputePivotPoint( const FVector& CornerPos, const FVector& NextCorner, const FVector& Normal, float Offset)
{
const FVector WallDir = (NextCorner - CornerPos).GetSafeNormal();

const FVector LineAStart = CornerPos + WallDir * Offset;

const FVector LineADir = Normal;

const FVector LineBStart = CornerPos + Normal * Offset;

const FVector LineBDir = WallDir;

FVector Intersection;
LineLineIntersection( Intersection, LineAStart, LineADir, LineBStart, LineBDir );

return Intersection;
}

bool LineLineIntersection( FVector& OutIntersection, const FVector& P1, const FVector& D1, const FVector& P2, const FVector&  D2)
{
const FVector R = P2 - P1;
const FVector C = FVector::CrossProduct(D1, D2);

const float Denom = C.SizeSquared();

if (Denom < KINDA_SMALL_NUMBER)
return false;

const float T = FVector::DotProduct( FVector::CrossProduct(R, D2), C ) / Denom;

OutIntersection = P1 + D1 * T;
return true;
}
Вопрос
Этот алгоритм отлично работает для углов в 90 градусов, но не работает для произвольных углов. Я подозреваю, что проблема в расчете расстояния до поворота, который предполагает угол 90 градусов. Как я могу настроить алгоритм для обработки произвольных углов между гранями стен?
Буду признателен за любую помощь или понимание.

Дополнительный контекст
  • Версия Unreal Engine: 5.7.3


Подробнее здесь: https://stackoverflow.com/questions/798 ... wall-merge
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C++»