A partir de la versión 36.00, UEFN usa el sistema de coordenadas LUF para el editor y todas las transformaciones del módulo /Verse.org. Las transformaciones de los módulos /UnrealEngine.com y /Fortnite.com usan el sistema de coordenadas XYZ.
Presentación del sistema de coordenadas LUF
Las principales herramientas de creación de contenido 3D utilizan un sistema de coordenadas cartesianas (X, Y y Z) para posicionar y rotar objetos. Sin embargo, las interpretaciones específicas de qué ejes (X, Y y Z) representan qué direcciones (como izquierda/derecha, arriba/abajo y adelante/atrás) son diferentes entre herramientas. Además, la forma en que se modelan las rotaciones (lo que se conoce como la lateralidad del sistema de coordenadas) también varía entre las distintas herramientas.
Para alinear mejor a Verse y UEFN con los estándares emergentes en la creación de contenido 3D y otros conjuntos de herramientas destacados, realizaremos cambios fundamentales en la presentación de nuestro sistema de coordenadas.
Primero, en lugar de etiquetar los ejes de coordenadas con X, Y y Z, vamos a introducir nombres de ejes más descriptivos:
Izquierda (Left, L) (era -Y)
Arriba (Up, U) (antes Z)
Adelante (Forward, F)(antes X)
Por lo tanto, el cambio de las XYZ y FRU anteriores a LUF corresponde a un cambio de lateralidad en los ejes de un sistema de coordenadas de perspectiva izquierda (XYZ y FRU) a un sistema de coordenadas de perspectiva derecha (LUF).
En segundo lugar, los colores del artilugio del visor de UEFN cambiaron para alinearse con otros software de creación de contenido 3D:
Izquierda: rojo (en lugar de verde)
Arriba: verde (en lugar de azul)
Delantero:azul (en lugar de rojo)
En tercer lugar, se realizaron muchas mejoras en el módulo /Verse.org/SpatialMath.
Ahora todas las funciones del módulo de matemáticas espaciales de Verse son operaciones de mano derecha. Como resultado, todas las funciones con variantes explícitas de diestros se eliminaron y reemplazaron con versiones que, de manera predeterminada, realizan operaciones a la derecha, y los indicadores de diestros se eliminaron de los nombres de función. Para obtener más información, consulta la sección Lateralidad derecha de esta página a continuación.
Las funciones de rotación que involucran un parámetro de ángulo o return un valor ahora tienen versiones que aceptan o devuelven radianes o grados, y tienen el sufijo
RadianesoGradospara la variante respectiva.Las funciones
RotateBy,UnrotateByy all(:rotation).Apply*se eliminaron en favor de un operador de multiplicación que compone dosrotacionesde izquierda a derecha. Para obtener más información, consulta la sección [Orden de multiplicación de transformación y rotación]() de esta página.RotateVectoryUnrotateVectorse eliminaron en favor de un operador de una multiplicación que rota unvector3por unarotación, en ese orden. Para obtener más información, consulta la sección Cambios en las operaciones matemáticas espaciales de esta página.Se eliminaron TransformVectoryTransformVectorNoScaleen favor de un operador de una multiplicación que transforma unvector3mediante unatransformaciónen el siguiente orden: escala, rotación, traslación. Para obtener más información, consulta la sección Cambios en las operaciones matemáticas espaciales de esta página.
Cuarto, las importaciones predeterminadas de mallas esqueléticas desde FBX ahora usan la opción de alinear los ejes Arriba y Adelante para que todas las mallas esqueléticas importadas miren hacia el eje de adelante.
A qué afecta
Este cambio en el sistema de coordenadas afecta a cualquier persona que use UEFN o transformaciones en el módulo /Verse.org, en particular, a varios aspectos de UEFN y Verse, entre los que se incluyen:
Panel de detalles de UEFN
Visor y artilugio de UEFN
Transformación de Verse
No es necesario que cambies el código o el contenido de tus islas publicadas para que funcionen correctamente con LUF.
Panel de detalles de UEFN
Las transformaciones en el panel de detalles UEFN ahora muestran las coordenadas en términos del sistema LUF.
Visor de UEFN
La asignación entre los ejes y los colores de los artilugios cambió en el visor de UEFN.
Transformaciones de Verse
Las transformaciones del módulo /Verse.org usan el sistema LUF . La transformación del módulo /UnrealEngine.com con el sistema de coordenadas XYZ todavía existe y se usa como transformación predeterminada en los módulos /UnrealEngine.com y /Fortnite.com.
Dado que estos dos módulos contienen tipos de transformar, ten en cuenta lo siguiente:
Si utilizas funciones de API que usan transformaciones de módulos
/Verse.orgy de módulos/UnrealEngine.comen el mismo archivo, los nombres de los tipos deberán calificarse por su ruta para evitar la ambigüedad entre los dos módulos. Esto se muestra en el siguiente fragmento de ejemplo.VerseNombres de tipo calificados por rutausing { /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 utiliza transformaciones del módulo
/Verse.org. Esto significa que Scene Graph ahora solo usa el sistema de coordenadas LUF.El resumen de Verse utiliza identificadores de Verse totalmente calificados para eliminar la ambigüedad entre los tipos de transformación definidos en UnrealEngine.com/Temporary/SpatialMath y Verse.org/SpatialMath .
Para obtener más información sobre el sistema de coordenadas de Unreal Engine, consulta Sistema de coordenadas y espacios en Unreal Engine.
Conversiones de XYZ a LUF
Si estás usando funciones de API ya existentes que se cambiaron a las transformaciones de módulo /Verse.org (LUF), necesitarás convertir tus transformaciones definidas por el usuario /UnrealEngine.com (XYZ) para usar LUF, o bien usar las funciones de conversión FromTransform recién creadas. En esta sección, puedes encontrar varios problemas potenciales de conversión y sus soluciones.
Ambigüedad de tipo constante o variable
Con los cambios recientes en la API de Verse, tanto /UnrealEngine.com/Temporary/SpatialMath como /Verse.org/SpatialMath definen los tipos vector3, rotación y transformación. Como resultado, surgirá ambigüedad de tipo si incluyes ambos dominios en tu archivo de Verse.
Ejemplo de ambigüedad de tipo
El siguiente archivo de Verse importa las rutas de los módulos /UnrealEngine.com/Temporary/SpatialMath y del módulo /Verse.org/SpatialMath, y la clase definida por el usuario usa el tipo no calificado 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.vector3Como resultado, la ambigüedad de tipo provoca un error de compilación si intentas compilar este archivo, ya que el compilador no sabe si compilar MyVectorOne y MyVectorTwo como un tipo /UnrealEngine.com vector3 o como un tipo /Verse.org vector3. El usuario no le dio suficiente información al compilador para que sepa qué tipo se indica.
Para resolver este error de compilación, debes calificar la ruta del tipo de vector3 que usa cada variable. Hay varias formas de calificar la ruta de estas constantes para resolver el error:
Puedes calificar completamente cualquier constante o variable de tipo vector3, como se muestra en el fragmento de código a continuación:
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{}Puedes calificar una constante o variable desde el módulo /Verse.org, como se muestra en el siguiente fragmento de código:
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 submodulePuedes calificar una constante o variable desde el módulo /UnrealEngine.com, como se muestra en el siguiente fragmento de código:
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{}Cambio de tipo de Scene Graph
Si estás usando las API de Scene Graph en tus archivos de Verse y no otras API que usan matemática espacial, puedes cambiar los tipos de matemática espacial en tu código de Verse al cambiar el módulo de matemática espacial que importas con la palabra clave using. Por ejemplo, si tienes el siguiente código:
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{}Puedes cambiarlo a:
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 vector2La única excepción es que cualquier tipo vector2 debe eliminarse o convertirse para usar vector3, ya que el módulo /Verse.org actualmente no define el tipo vector2.
Discrepancia de tipo de función
Otro escenario en el que es posible que debas calificar los tipos de ruta o convertir el código es cuando:
Una función que se llama o una variable asignada esperan un tipo del módulo
/UnrealEngine.com, pero reciben un tipo del módulo/Verse.org.Una función que se llama o una variable asignada esperan un tipo del módulo
/Verse.org, pero reciben un tipo del módulo/UnrealEngine.com.
Ejemplo de discrepancia de tipo de función
Los siguientes dos archivos de Verse existen en el mismo proyecto. FileOne.verse define una función para imprimir una transformación desde el módulo /UnrealEngine.com/Temporary/SpatialMath . FileTwo.verse define una transformación constante del módulo /Verse.org/SpatialMath y una función para imprimir este valor que llama a la función desde 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.Esto da como resultado un error de compilación debido a que los tipos de transformación se refieren a dos tipos diferentes, definidos en módulos distintos.
Para corregir este error de compilación, debes convertir el tipo de transformación al tipo correcto desde el módulo apropiado. Edita el código en FileTwo.verse para usar la función FromTransform, que convierte una transformación de /Verse.org/SpatialMath en una transformación de /UnrealEngine.com/Temporary/SpatialMath.
Para obtener una lista completa de las funciones de conversión disponibles, consulta la siguiente sección.
# 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 moduleConversión de los tipos de vector, rotación y transformación
El módulo /UnrealEngine.com ofrece varias funciones de conversión nuevas para convertir entre los tipos potencialmente ambiguos definidos en el módulo /UnrealEngine.com y el módulo /Verse.org.
De la matemática espacial de Unreal Engine a la matemática espacial de 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
De la matemática espacial de Verse a la matemática espacial de 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
Funciones y operaciones matemáticas espaciales de Verse
Mano derecha
Ahora todas las funciones del módulo de matemáticas espaciales de Verse son operaciones de mano derecha. Como resultado, todas las funciones con variantes explícitas de lateralidad se eliminaron y reemplazaron con versiones que, de forma predeterminada, son operaciones con la mano derecha, y los indicadores de lateralidad se eliminaron de los nombres de función. Todas las operaciones donde hay una elección de lateralidad, como la multiplicación de un vector3 por una rotación o la multiplicación de un vector3 por una transformación, son operaciones de mano derecha.
Por ejemplo, el siguiente código ilustra que construir una rotación de 90 grados positivos alrededor del eje hacia arriba y aplicar esta rotación a un vector unitario hacia adelante da como resultado un vector unitario hacia la izquierda:
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}
Orden de multiplicación de transformar y rotación
Puedes pensar en las rotaciones como representadas internamente por una matriz. Cuando se aplica una rotación R a un vector v, se aplican en el orden de multiplicación del vector fila. Es decir, el vector v es un vector de fila y cuando se rota un vector, se aplica la multiplicación por la derecha para obtener el resultado, v' = v * R. Aquí, el vector resultante v' es un nuevo vector de fila. Esto funciona de manera similar para aplicar una transformada T a un vector v, v' = v * T y el vector resultante v' es otro vector fila.
El orden importa cuando se aplican rotaciones y transformaciones a vectores. Sostén un objeto, como un libro, en la mano con la parte superior hacia arriba y la parte delantera/portada hacia ti. Al aplicar una rotación positiva de 90 grados hacia la derecha sobre el eje de avance, la parte superior del libro ahora queda hacia la derecha. A continuación, se aplica una rotación de 90 grados sobre el eje Izquierdo, lo que da como resultado que la parte frontal del teléfono quede hacia arriba y la parte superior del libro quede hacia la derecha.
Ahora, aplica las mismas rotaciones en el orden inverso. Aplica una rotación de 90 grados sobre el eje Izquierdo, lo que da como resultado que la parte superior del libro mire hacia adelante y la parte frontal del libro hacia arriba. A continuación, la aplicación de una rotación de 90 grados sobre el eje de avance da como resultado que la parte superior del libro mire hacia adelante y la parte frontal del libro mire hacia la derecha. Esta no es la misma orientación que aplicar las rotaciones en el otro orden, lo que ilustra que el orden de las rotaciones es importante.
Teniendo esto en cuenta, si deseas aplicar dos rotaciones R y R' a un vector v, debes tener cuidado de aplicarlas en el orden que deseas. Si deseas aplicar la rotación R antes de la rotación R', entonces el orden correcto es v' = v * R * R'.
El mismo principio se aplica a las propias rotaciones. Si tienes una rotación R y deseas aplicar una prerrotación PreR a R, que tiene lugar antes de la rotación R, y una posrotación PostR que tiene lugar después de la rotación R, esto se hace en el orden PreR * R * PostR. Del mismo modo, si deseas aplicar una PreT previa a la transformación y una PostT posterior a la transformación a una transformada T, hazlo en el orden PreT * T * PostT. Posteriormente, aplicar estos a un vector v para lograr un nuevo vector v' se hace como se indica arriba, v' = v * PreR * R * PostR o v' = v * PreT * T * PostT.
La asociatividad de transformaciones y rotaciones también es importante. Si deseas aplicar varias operaciones en un vector en la misma línea de código de Verse, como una transformación, seguida de una rotación, la asociación de las operaciones es importante. Por ejemplo, podrías intentar lo siguiente:
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 # compilesEsto compila bien ya que implícitamente asocia operaciones como:
ResultantVector:vector3 = (ForwardVector * ForwardToLeftUpOne) * UpToForward # compiles
Pero si explícitamente intentas asociar de manera diferente como:
ResultantVector:vector3 = ForwardVector * (ForwardToLeftUpOne * UpToForward) # error, no operator'*'(:transform,:rotation)
Esto resultado en un error. Para evitar estos errores, asocia explícitamente tu primera operación entre un vector y una transformación o un vector y una rotación.
ResultantVector:vector3 = (ForwardVector * ForwardToLeftUpOne) * UpToForward # explicitly associated
Cambios en las operaciones matemáticas espaciales
Rotación y multiplicación de rotación
RotateBy y UnrotateBy se eliminan y se reemplazan con un operador de multiplicación para dos rotaciones.
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 handednessPara invertir una rotación ("anular la rotación"), primero invierte la rotación y, luego, multiplica las rotaciones. Para recuperar la rotación UpToForward de UpToLeft, invierte la rotación ForwardToLeft y aplícala a la derecha de la rotación UpToLeft. A continuación se muestra cómo se logra esto paso a paso.
# 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 handednessVector3 y multiplicación de rotaciones
De manera similar, Rotate y Unrotate se eliminan y reemplazan con un operador de multiplicación para un vector3 girado a la derecha por una rotación.
ForwardVector:vector3 = vector3{Forward:=1.0}
ForwardToLeft:rotation = MakeRotationFromEulerDegrees(0.0, 90.0, 0.0)
LeftVector:vector3 = ForwardVector * ForwardToLeft # Rotate, correcting for handednessPara invertir una rotación (anular la rotación), primero invierte la rotación y, luego, multiplica la rotación por el vector. Para recuperar el ForwardVector de LeftVector, invierte la rotación ForwardToLeft y aplícala a la derecha del 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 handednessVector3 y multiplicación por transformada
TransformVector y TransformVectorNoScale se eliminan y reemplazan con un operador de multiplicación para un vector3 transformado a la derecha por una transformación.
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 # TransformVectorPara realizar una transformación sin escalado, TransformVectorNoScale, deja el valor de escala predeterminado en la transform que construyas.
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