Начиная с версии 36.00, в UEFN используется система координат LUF, в самом редакторе и для всех преобразований модуля /Verse.org. Для преобразований модулей /UnrealEngine.com и /Fortnite.com используется система координат XYZ.
Знакомство с системой координат LUF
Все основные инструменты для создания трёхмерного контента используют систему декартовых координат (X, Y и Z) для размещения и вращения объектов. Однако конкретная интерпретация того, какие направления (например, влево/вправо, вверх/вниз и вперёд/назад) представляют оси (X, Y и Z), для разных инструментов различаются. Кроме того, способ моделирования вращений, известный как направленность направленность системы координат, также различается в зависимости от инструмента.
Чтобы привести Verse и UEFN в соответствие с новыми стандартами создания трёхмерного контента и другими популярными наборами инструментов, мы вносим кардинальные изменения в представление системы координат.
Во-первых, вместо маркировки осей координатами X, Y и Z мы вводим более описательные названия осей:
Влево (ранее Y);
Вверх (ранее Z);
Вперёд (ранее X).
Таким образом, переход с предыдущих XYZ и FRU на LUF соответствует смене направленности по осям с левосторонней системы координат (XYZ и FRU) на правостороннюю (LUF).
Во-вторых, цвета графического ориентира окна просмотра UEFN были изменены, чтобы их можно было использовать в другом программном обеспечении для создания трёхмерного контента:
Влево: красный (был зелёный);
Вверх: зелёный ( был синим );
Вперёд:синий ( был красный).
В-третьих, модуль /Verse.org/SpatialMath претерпел значительные изменения.
Все функции модуля пространственных вычислений Verse теперь являются правосторонними операциями. Как следствие, все функции с вариантами с явно указанным правосторонним направлением были удалены и заменены версиями, которые по умолчанию являются правосторонними, а из названий функций удалены указатели направленности вправо. Для получения дополнительной информации см. раздел Правосторонняя направленность ниже на этой странице.
Теперь у функций вращения, которые включают в себя угловой параметр или возвращаемое значение, есть версии, которые принимает или возвращают радиусы или градусы, и имеют суффикс
RadiansилиDegreesдля соответствующего варианта.RotateBy,UnrotateByи все функции(:rotation).Apply*были удалены и заменены оператором умножения, который объединяет дваповоротаслева направо. Для получения дополнительной информации см. раздел «Порядок умножения преобразований и вращений» на этой странице.RotateVectorиUnrotateVectorбыли удалены и заменены оператором умножения, который поворачиваетvector3на значениеrotationв указанном порядке. Дополнительную информацию см. в разделе Изменения пространственных математических операций на этой странице.TransformVectorиTransformVectorNoScaleзаменены на оператор умножения, который преобразуетvector3с помощью значенияtransformв следующем порядке: масштаб, вращение, перенос. Дополнительную информацию см. в разделе Изменения пространственных математических операций на этой странице.
В-четвёртых, при импорте скелетных сеток из FBX теперь используется настройка для выравнивания осей, направленных вверх и вперёд, чтобы все импортированные скелетные сетки были обращены по оси вперёд.
На что это влияет
Это изменение системы координат влияет на всё, что использует UEFN или преобразования в модуле /Verse.org. В частности, на несколько аспектов UEFN и Verse, в том числе:
панель «Сведения» UEFN;
окно просмотра и графический ориентир UEFN;
преобразование Verse.
Для корректной работы опубликованных островов с LUF изменять код или контент не требуется.
Панель «Сведения» UEFN
Преобразования на панели «Сведения» UEFN теперь отображают координаты в системе LUF.
Окно просмотра UEFN
В окне просмотра UEFN изменились цвета осей графического ориентира.
Преобразования Verse
В преобразованиях модуля /Verse.org используется система LUF . Преобразование модуля /UnrealEngine.com, использующее систему координат XYZ, по-прежнему существует и используется в качестве преобразования по умолчанию в модулях /UnrealEngine.com и /Fortnite.com.
Поскольку оба этих модуля содержат типы преобразования, имейте в виду следующее.
Если вы используете функции API, задействующие преобразования модуля
/Verse.orgи модуля/UnrealEngine.comв одном файле, названия типов должны указаны в пути к ним, чтобы избежать путаницы между модулями. Этот процесс показан в примере фрагмента кода ниже.VerseИмена типов, определяемые путёмusing { /UnrealEngine.com/Temporary/SpatialMath } using { /Verse.org/SpatialMath } my_class := class: MyUnrealEngineVector:(/UnrealEngine.com/Temporary/SpatialMath:)vector3 = (/UnrealEngine.com/Temporary/SpatialMath:)vector3{} MyVerseVector:(/Verse.org/SpatialMath:)vector3 = (/Verse.org/SpatialMath:)vector3{}Scene Graph использует преобразования модуля
/Verse.org.Это значит, что Scene Graph теперь использует только систему координат LUF.В дайджесте Verse используются полностью определённые идентификаторы Verse для устранения неоднозначности между типами преобразования, заданными в модулях UnrealEngine.com/Temporary/SpatialMath и Verse.org/SpatialMath .
Более подробную информацию о системе координат Unreal Engine можно найти в разделе Система координат и пространства в Unreal Engine.
Конвертация из XYZ в LUF
Если вы используете существующие функции API, которые переключились на преобразования модуля /Verse.org (LUF), вам необходимо преобразовать заданные пользователем преобразования /UnrealEngine.com (XYZ) для использования LUF или использовать новые функции преобразования FromTransform. В этом разделе приведён ряд возможных проблем, возникающих при преобразовании, и варианты их устранения.
Неоднозначность типа константы или переменной
В связи с недавними изменениями в API Verse и /UnrealEngine.com/Temporary/SpatialMath, и /Verse.org/SpatialMath определяют типы vector3, rotation и transform. В результате, если вы включите оба домена в свой файл Verse, возникнет неоднозначность типов.
Пример неоднозначности типа
Следующий файл Verse импортирует пути модулей /UnrealEngine.com/Temporary/SpatialMath и /Verse.org/SpatialMath, а определённый пользователем класс использует неопределённый тип vector3:
using { /UnrealEngine.com/Temporary/SpatialMath }
using { /Verse.org/SpatialMath }
my_class := class:
MyVectorOne:vector3 = vector3{}
#Compile Error: Identifier vector3 could be one of many types: UnrealEngine.com.Temporary.SpatialMath.vector3 or Verse.org.SpatialMath.vector3
MyVectorTwo:vector3 = vector3{}
#Compile Error: Identifier vector3 could be one of many types: UnrealEngine.com.Temporary.SpatialMath.vector3 or Verse.org.SpatialMath.vector3В результате неоднозначность типа вызовет ошибку компиляции при попытке скомпилировать этот файл, поскольку компилятор не «знает», нужно ли компилировать MyVectorOne и MyVectorTwo как тип /UnrealEngine.com vector3 или как тип /Verse.org vector3. Пользователь не передал компилятору достаточно информации, чтобы он смог определить заданный тип.
Чтобы устранить эту ошибку компиляции, необходимо указать путь к типу vector3, используемому каждой переменной. Существует несколько различных способов определения пути этих констант для устранения ошибки:
Вы можете полностью определить любую константу или переменную типа vector3, как показано в фрагменте кода ниже:
using { /UnrealEngine.com/Temporary/SpatialMath }
using { /Verse.org/SpatialMath }
my_class := class:
MyVectorOne:(/UnrealEngine.com/Temporary/SpatialMath:)vector3 = (/UnrealEngine.com/Temporary/SpatialMath:)vector3{}
MyVectorTwo:(/Verse.org/SpatialMath:)vector3 = (/Verse.org/SpatialMath:)vector3{}Вы можете определить константу или переменную из модуля /Verse.org, как показано во фрагменте кода ниже:
using { /UnrealEngine.com/Temporary/SpatialMath }
using { /Verse.org } # Change the module path to avoid import ambiguity
my_class := class:
MyVectorOne:vector3 = vector3{}
MyVectorTwo:SpatialMath.vector3 = SpatialMath.vector3{} # Specify the submoduleВы можете определить константу или переменную из модуля /UnrealEngine.com, как показано во фрагменте кода ниже:
using { /UnrealEngine.com/Temporary } # Change the module path to avoid import ambiguity
using { /Verse.org/SpatialMath }
my_class := class:
MyVectorOne:SpatialMath.vector3 = SpatialMath.vector3{} # Specify the submodule
MyVectorTwo:vector3 = vector3{}Изменение типа Scene Graph
Если вы используете API Scene Graph в своих файлах Verse и не используете другие API с пространственными вычислениями, вы можете изменить типы пространственных вычислений в коде Verse, изменив импортируемый модуль пространственных вычислений с помощью ключевого слова using. Например, если у вас есть следующий код:
using { /UnrealEngine.com/Temporary/SpatialMath }
my_component := class<final_super>(component):
@editable # This change will work regardless of this field being editable or not
MyVector3:vector3 = vector3{}
MyVector2:vector2 = vector2{}Вы можете изменить его так:
using { /Verse.org/SpatialMath } # Changed the module path
my_component := class<final_super>(component):
@editable # This change will work regardless of this field being editable or not
MyVector:vector3 = vector3{} # All transform types now use /Verse.org/SpatialMath
# MyVector2:vector2 = vector2{} Removed since /Verse.org/SpatialMath does not define a vector2Единственное исключение — любые типы vector2 должны быть удалены или преобразованы для использования vector3, поскольку модуль /Verse.org в настоящее время не определяет тип vector2.
Несоответствие типа функции
Вам также может потребоваться указать тип в пути или преобразовать свой код в следующих случаях:
вызываемая функция или присвоенная переменная ожидает тип из модуля
/UnrealEngine.com, а получает тип из модуля/Verse.org;вызываемая функция или присвоенная переменная ожидает тип из модуля
/Verse.org, а получает тип из модуля/UnrealEngine.com.
Пример несоответствия типа функции
В одном проекте существуют два файла Verse. FileOne.verse определяет функцию вывода информации о преобразовании из модуля /UnrealEngine.com/Temporary/SpatialMath . FileTwo.verse определяет преобразование константы из модуля /Verse.org/SpatialMath и функцию для вывода этого значения, которое вызывает функцию из FileOne.verse.
using { /UnrealEngine.com/Temporary/SpatialMath }
PrintTransform(T:transform):void=
Print("T: {T}")using { /Verse.org/SpatialMath }
my_class := class:
T:transform = transform{}
DoPrint():void=
PrintTransform(T) # Compile error: This function parameter expects a value of type (/UnrealEngine.com/Temporary/SpatialMath:)transform, but this argument is an incompatible value of type (/Verse.org/SpatialMath:)transform.Это приводит к ошибке компиляции из-за ссылки на два разных типа преобразования, определённых в разных модулях.
Чтобы исправить эту ошибку компиляции, необходимо конвертировать тип преобразования в правильный тип преобразования из соответствующего модуля. Измените код в FileTwo.verse, чтобы использовать функцию FromTransform, которая конвертирует преобразование из /Verse.org/SpatialMath в преобразование из /UnrealEngine.com/Temporary/SpatialMath.
Полный список доступных функций преобразования см. в следующем разделе.
# Include /UnrealEngine.com to access conversion functions
using { /UnrealEngine.com }
using { /Verse.org/SpatialMath }
my_class := class:
T:transform = transform{}
DoPrint():void=
PrintTransform(Temporary.SpatialMath.FromTransform(T)) # Compile error fixed after converting transform to the correct type from the proper moduleПреобразование типов vector, rotation и transform
Модуль /UnrealEngine.com предоставляет несколько новых функций преобразования для конвертации потенциально неоднозначных типов, определяемых в модуле /UnrealEngine.com и модуле /Verse.org.
От пространственных вычислений Unreal Engine к пространственным вычислениям Verse
# Util function for converting a `vector3` from /UnrealEngine.com/Temporary/SpatialMath to a `vector3` from /Verse.org/SpatialMath.
FromVector3<public>(InVector3:(/UnrealEngine.com/Temporary/SpatialMath:)vector3)<reads>:(/Verse.org/SpatialMath:)vector3
# Util function for converting a `rotation` from /UnrealEngine.com/Temporary/SpatialMath to a `rotation` from /Verse.org/SpatialMath
FromRotation<public>(InRotation:(/UnrealEngine.com/Temporary/SpatialMath:)rotation)<reads>:(/Verse.org/SpatialMath:)rotation
# Util function for converting a `transform` from /UnrealEngine.com/Temporary/SpatialMath to a `transform` from /Verse.org/SpatialMath.
FromTransform<public>(InTransform:(/UnrealEngine.com/Temporary/SpatialMath:)transform)<reads>:(/Verse.org/SpatialMath:)transform
От пространственных вычислений Verse к пространственным вычислениям Unreal Engine
# Util function for converting a `vector3` from /Verse.org/SpatialMath to a `vector3` from /UnrealEngine.com/Temporary/SpatialMath.
FromVector3<public>(InVector3:(/Verse.org/SpatialMath:)vector3)<reads>:(/UnrealEngine.com/Temporary/SpatialMath:)vector3
# Util function for converting a `rotation` from /Verse.org/SpatialMath to a `rotation` from /UnrealEngine.com/Temporary/SpatialMath.
FromRotation<public>(InRotation:(/Verse.org/SpatialMath:)rotation)<reads>:(/UnrealEngine.com/Temporary/SpatialMath:)rotation
# Util function for converting a `transform` from /Verse.org/SpatialMath to a `transform` from /UnrealEngine.com/Temporary/SpatialMath.
FromTransform<public>(InTransform:(/Verse.org/SpatialMath:)transform)<reads>:(/UnrealEngine.com/Temporary/SpatialMath:)transform
Пространственные математические операции и функции Verse
Правосторонняя направленность
Все функции модуля пространственных вычислений Verse теперь являются правосторонними операциями. В результате все функции с вариантами с явно указанной направленностью были удалены и заменены версиями, которые по умолчанию являются правосторонними, а из названий функций удалены указатели направленности. Все операции с той или иной направленностью, такие как умножение vector3 на rotation или умножение vector3 на transform, являются правосторонними.
Например, в следующем коде показано, что положительный поворот на 90 градусов вокруг оси, направленной вверх, и применение этого поворота к единице вектора «вперёд» приводит к результату в единице «влево»:
ForwardToLeft:rotation = MakeRotationFromEulerDegrees(0.0, 90.0, 0.0)
ForwardVector:vector3 = vector3{Forward := 1.0}
ResultantVector:vector3 = ForwardVector * ForwardToLeft # Apply rotation on the right of the multiplication operator
Print("{ResultantVector}") # {Forward = 0.000000, Left = 1.000000, Up = 0.000000} = {Forward = 1.000000, Left = 0.000000, Up = 0.000000} * {Axis = {Forward = 0.000000, Left = 0.000000, Up = 1.000000}, Angle = 90.000000}
Порядок умножения преобразования и вращения
Вращение можно представить в виде внутренней матрицы. Когда вращение R применяется к вектору v, они применяются в порядке умножения вектора-строки. То есть вектор v является вектором-строкой, и при повороте вектора для получения результата применяется умножение справа: v' = v * R. В данном примере полученный вектор v' является новым вектором-строкой. Это работает аналогично для применения transform T к vector v, v' = v * T, а полученный вектор v' является ещё одним вектором-строкой.
При применении вращений и преобразований к векторам имеет значение порядок. Возьмите в руки объект, например, книгу, так, чтобы верхняя грань была направлена вверх, а передняя часть/обложка — к вам. Положительный поворот вправо на 90 градусов вокруг оси вперёд приведёт к тому, что верх книги будет повёрнут вправо. Затем, если повернуть книгу на 90 градусов вокруг оси «влево», её передняя часть будет направлена вверх, а верхняя — вправо.
Теперь примените те же вращения в обратном порядке. Поверните книгу на 90 градусов вокруг оси «влево», чтобы её верхняя часть была направлена вперёд, а передняя часть — вверх. Затем, если повернуть её на 90 градусов вокруг оси «вперёд», получится, что верхняя часть будет обращена вперёд, а передняя часть — вправо. Если изменить порядок вращения, ориентация будет другой, что говорит о значимости порядка вращения.
Помните об этом: если вы хотите применить два вращения R и R' к вектору v, вы должны применить их в нужном порядке. Если требуется применить вращение R перед вращением R', то правильный порядок будет таким: v' = v * R * R'.
Этот же принцип применим и к самим вращениям. Если у вас есть вращение R и вы хотите применить к нему предварительное вращение PreR, которое выполняется перед вращением R, а также последующее вращение PostR, которое выполняется после R, то они выполняются в следующем порядке: PreR * R * PostR. Аналогичным образом, если требуется применить предварительное преобразование PreT и последующее преобразование PostT к преобразованию T, то они выполняются в следующем порядке: PreT * T * PostT. Затем можно применить их к вектору v для получения нового вектора v', как указано выше: v' = v * PreR * R * PostR или v' = v * PreT * T * PostT.
Также важна ассоциативность преобразований и поворотов. Если требуется применить несколько операций к вектору в одной строке кода Verse, например выполнить преобразование, за которым следует поворот, имеет значение ассоциативность операций. Например, вы можете попробовать следующее:
ForwardVector:vector3 = vector3{Forward := 1.0}
ForwardToLeftUpOne:transform = transform:
Translation := vector3{Up := 1.0}
Rotation := MakeRotationFromEulerDegrees(0.0, 90.0, 0.0)
UpToForward:rotation = MakeRotationFromEulerDegrees(90.0, 0.0, 0.0)
ResultantVector:vector3 = ForwardVector * ForwardToLeftUpOne * UpToForward # compilesЭтот код отлично компилируется, поскольку неявно связывает операции следующим образом:
ResultantVector:vector3 = (ForwardVector * ForwardToLeftUpOne) * UpToForward # compiles
Но если вы явно попытаетесь ассоциировать другой код, например:
ResultantVector:vector3 = ForwardVector * (ForwardToLeftUpOne * UpToForward) # error, no operator'*'(:transform,:rotation)
Это приведёт к ошибке. Чтобы избежать этих ошибок, явно ассоциируйте свою первую операцию между вектором и преобразованием или вектором и вращением.
ResultantVector:vector3 = (ForwardVector * ForwardToLeftUpOne) * UpToForward # explicitly associated
Изменения в пространственных математических операциях
Умножение вращений
RotateBy и UnrotateBy удалены и заменены оператором умножения для вращений в обе стороны.
ForwardToLeft:rotation = MakeRotationFromEulerDegrees(0.0, 90.0, 0.0)
UpToForward:rotation = MakeRotationFromEulerDegrees(90.0, 0.0, 0.0)
UpToLeft:rotation = UpToForward * ForwardToLeft # RotateBy, correcting for handednessЧтобы изменить вращение на обратное («отменить вращение»), сначала инвертируйте вращение, а затем умножьте его. Чтобы получить вращение UpToForward из UpToLeft, инвертируйте вращение ForwardToLeft и примените его справа к вращению UpToLeft. Ниже пошагово показано, как это сделать.
# The following comments show the steps involved to reach the desired result.
# This involves multiplication on the right by the inverse, associativity, existence and definition of inverse rotation, and existence and definition of identity rotation
# Pseudocode Steps:
# UpToLeft * ForwardToLeft.Invert() = (UpToForward * ForwardToLeft) * ForwardToLeft.Invert() # multiply on the right by the same expression on both sides of the equality operator
# UpToLeft * ForwardToLeft.Invert() = UpToForward * (ForwardToLeft * ForwardToLeft.Invert()) # reassociate
# UpToLeft * ForwardToLeft.Invert() = UpToForward * IdentityRotation() # rotation * inverse = identity
# UpToLeft * ForwardToLeft.Invert() = UpToForward # rotation * identity = rotation
UpToForwardAgain:rotation = UpToLeft * ForwardToLeft.Invert() # UnrotateBy, correcting for handednessУмножение Vector3 и вращения
Аналогичным образом, операторы Rotate и Unrotate удаляются и заменяются оператором умножения vector3 с вращением вправо на rotation.
ForwardVector:vector3 = vector3{Forward:=1.0}
ForwardToLeft:rotation = MakeRotationFromEulerDegrees(0.0, 90.0, 0.0)
LeftVector:vector3 = ForwardVector * ForwardToLeft # Rotate, correcting for handednessЧтобы изменить вращение на обратное, сначала инвертируйте вращение, а затем умножьте его на вектор. Чтобы получить ForwardVector из LeftVector, инвертируйте поворот ForwardToLeft и примените его справа к LeftVector.
# The steps involved in achieving this calculation are very similar to the steps shown above for obtaining the correct expression for unrotating by a rotation
ForwardVectorAgain:vector3 = LeftVector * ForwardToLeft.Invert() # Unrotate, correcting for handednessУмножение Vector3 и преобразования
TransformVector и TransformVectorNoScale удалены и заменены оператором умножения vector3с преобразованием вправо на преобразование.
DoubleLengthForwardToLeftTranslateUp := transform:
Translation := vector3{Left := 0.0, Up := 1.0, Forward := 0.0}
Rotation := MakeRotationFromEulerDegrees(0.0, 90.0, 0.0)
Scale := vector3{Left := 2.0, Up := 2.0, Forward := 2.0}
ForwardVector:vector3 = vector3{Forward:=1.0}
ResultantVector:vector3 = ForwardVector * DoubleLengthForwardToLeftTranslateUp # TransformVectorЧтобы выполнить преобразование без масштабирования, TransformVectorNoScale, оставьте для создаваемого transform значение scale по умолчанию.
ForwardToLeftTranslateUpNoScale := transform:
Translation := vector3{Left := 0.0, Up := 1.0, Forward := 0.0}
Rotation := MakeRotationFromEulerDegrees(0.0, 90.0, 0.0)
ForwardVector:vector3 = vector3{Forward:=1.0}
ResultantVector:vector3 = ForwardVector * ForwardToLeftTranslateUpNoScale # TransformVectorNoScale