A partir de la versión 36:00, UEFN utiliza 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 utilizan 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 colocar y girar los objetos. Sin embargo, las interpretaciones específicas de qué ejes (X, Y y Z) representan qué direcciones (como izquierda/derecha, arriba/abajo y delante/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 Verse y UEFN con los estándares emergentes en la creación de contenido 3D y otros conjuntos de herramientas destacados, vamos a hacer 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 (antes era Y)
Arriba (antes Z)
Delante (antes X)
El cambio de XYZ y FRU anteriores a LUF corresponde, por tanto, a un cambio de lateralidad en los ejes de un sistema de coordenadas zurdo (XYZ y FRU) a un sistema de coordenadas diestro (LUF).
En segundo lugar, se han cambiado los colores del gizmo del visor de UEFN para alinearse con los de otro software de creación de contenido 3D:
Izquierda: rojo (antes era verde)
Arriba: verde (antes era azul)
Delante: azul (antes era rojo)
En tercer lugar, se han realizado muchas mejoras en el módulo /Verse.org/SpatialMath :
Todas las funciones del módulo de matemáticas espaciales de Verse son ahora operaciones hacia la derecha. Como resultado, se han eliminado todas las funciones con variantes explícitas diestras y se han sustituido por versiones que realizan de forma predeterminada operaciones a la derecha, y se han eliminado los indicadores diestros de los nombres de las funciones. Para obtener más información, consulta la sección Orientación a la derecha de esta página a continuación.
Las funciones de rotación que implican un parámetro de ángulo o devuelven un valor ahora tienen versiones que aceptan o devuelven radianes o grados, y tienen el sufijo
RadianesoGradospara la variante respectiva.Las funciones
RotateBy,UnrotateByy todas las funciones(:rotation).Apply*se han eliminado 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.Se han eliminado
RotateVectoryUnrotateVectoren favor de un operador de multiplicación que gira 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 han eliminado
TransformVectoryTransformVectorNoScaleen favor de un operador de 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.
En cuarto lugar, las importaciones predeterminadas de mallas esqueléticas desde FBX ahora utilizan la opción de alinear los ejes Arriba y Delante para que todas las mallas esqueléticas importadas se orienten hacia el eje de adelante.
A qué afecta esto
Este cambio del sistema de coordenadas afecta a cualquiera que utilice UEFN o transformaciones en el módulo /Verse.org, en concreto, a varios aspectos de UEFN y Verse, entre ellos:
Panel Detalles de UEFN
Visor y gizmo de UEFN
Transformación de Verse
No es necesario cambiar el código o el contenido de tus islas publicadas para que funcionen correctamente con LUF.
Panel Detalles de UEFN
Las transformaciones del panel Detalles de 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 gizmos ha cambiado en el visor de UEFN.
Transformaciones de Verse
Las transformaciones del módulo /Verse.org utilizan el sistema LUF. La transformación del módulo /UnrealEngine.com que utiliza el sistema de coordenadas XYZ sigue existiendo, y se utiliza como transformación predeterminada en los módulos /UnrealEngine.com y /Fortnite.com.
Como ambos módulos contienen tipos de transformación, ten en cuenta lo siguiente:
Si vas a hacer uso de funciones de la API que requieren transformaciones del módulo
/Verse.orgy del módulo/UnrealEngine.comen el mismo archivo, califica los nombres de los tipos por su ruta para evitar ambigüedades entre los dos módulos. Esto se muestra en el fragmento de ejemplo siguiente.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 ahora Scene Graph solo utiliza el sistema de coordenadas LUF.El compendio de Verse utiliza identificadores de Verse totalmente calificados para eliminar la ambigüedad entre los tipos de transformación definidos en los módulos UnrealEngine.com/Temporary/SpatialMath y Verse.org/SpatialMath .
Para saber más sobre el sistema de coordenadas de Unreal Engine, consulta Sistema de coordenadas y espacios en Unreal Engine.
Conversión de XYZ a LUF
Si vas a utilizar alguna función de la API que haya cambiado a las transformaciones del módulo de /Verse.org, tendrás que convertir sus transformaciones de /UnrealEngine.com definidas por el usuario (XYZ) para que utilicen LUF, o bien utilizar 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, rotation y transform. Como resultado, surgirá ambigüedad de tipos si incluyes ambos dominios en tu archivo de Verse.
Ejemplo de ambigüedad de tipos
El siguiente archivo de Verse importa tanto la ruta del módulo /UnrealEngine.com/Temporary/SpatialMath como la ruta del módulo Verse.org/SpatialMath y la clase definida por el usuario utiliza 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 del tipos 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 /Verse.org vector3. El usuario no ha dado al compilador suficiente información para que sepa qué tipo está indicado.
Para resolver este error de compilación, debes cumplir los requisitos de la ruta del tipo vector3 que utiliza cada variable. Hay varias formas de calificar la ruta de estas constantes para resolver el error:
Puedes cumplir los requisitos de cualquier constante o variable de tipo vector3, como se muestra en el fragmento de código siguiente.
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 cumplir los requisitos de una constante o variable desde el módulo /Verse.org, tal y como se muestra en el fragmento de código siguiente:
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 cumplir los requisitos de una constante o variable desde el módulo /UnrealEngine.com, tal y como se muestra en el fragmento de código siguiente:
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 del tipo de Scene Graph
Si utilizas las API de Scene Graph en tus archivos de Verse y no utilizas otras API que recurran a matemáticas espaciales, puedes cambiar los tipos de matemáticas espaciales en tu código Verse cambiando el módulo de matemáticas espaciales 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 los tipos vector2 deben eliminarse o convertirse para utilizar vector3, ya que el módulo de /Verse.org no define actualmente el tipo vector2.
Discrepancia en el tipo de función
Otra situación en la que puede que tengas que calificar la ruta de los tipos, o convertir el código, es cuando:
Una función llamada o una variable asignada espera un tipo del módulo de
/UnrealEngine.com, pero se le proporciona un tipo del módulo de/Verse.org.Una función llamada o una variable asignada esperan un tipo del módulo
/Verse.org, pero se les proporciona un tipo del módulo/UnrealEngine.com.
Ejemplo de discrepancia en el tipo de función
Los dos archivos de Verse siguientes 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 produce un error de compilación debido a que los tipos de transformación hacen referencia a dos tipos diferentes definidos en módulos diferentes.
Para corregir este error de compilación, debes convertir el tipo transform al tipo correcto desde el módulo apropiado. Edita el código de FileTwo.verse para utilizar la función FromTransform, que convierte un tipo de transformación de /Verse.org/SpatialMath en un tipo de 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 vector, rotation y transform
El módulo /UnrealEngine.com proporciona 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 las matemáticas espaciales de Unreal Engine a las matemáticas espaciales 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 las matemáticas espaciales de Verse a las matemáticas espaciales 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
Operaciones y funciones matemáticas espaciales de Verse
Orientación a la derecha
Todas las funciones del módulo de matemáticas espaciales de Verse son ahora operaciones hacia la derecha. Como resultado, se han eliminado todas las funciones con variantes explícitas de lateralidad y se han sustituido por versiones que realizan operaciones con la mano derecha de forma predeterminada, y se han eliminado los indicadores de lateralidad de los nombres de las funciones. Todas las operaciones en las que 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 hacia la derecha.
Por ejemplo, el siguiente código ilustra que construir una rotación de 90 grados positivos sobre el eje Arriba y aplicar esta rotación a un vector unitario Delante da como resultado un vector unitario 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 transformación 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 orden de multiplicación del vector fila. Es decir, el vector v es un vector fila y cuando se gira 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 fila. Esto funciona de forma similar para aplicar una transformación T a un vector v, v' = v * T y el vector resultante v' es otro vector fila.
El orden importa al aplicar rotaciones y transformaciones a vectores. Sostén un objeto, como un libro, en la mano con la tapa hacia arriba y la parte delantera/portada hacia ti. Al aplicar una rotación positiva de 90 grados hacia la derecha sobre el eje Delante, la parte superior del libro ahora mira hacia la derecha. A continuación, al aplicar una rotación de 90 grados sobre el eje Izquierda, la parte frontal del teléfono queda hacia arriba y la parte superior del libro mira hacia la derecha.
Ahora, aplica las mismas rotaciones en el orden inverso. Aplica una rotación de 90 grados sobre el eje Izquierda que tenga como resultado la parte superior del libro mirando hacia delante y la parte delantera hacia arriba. A continuación, al aplicar una rotación de 90 grados sobre el eje Delante, la parte superior del libro mira hacia delante y la parte delantera del libro mira 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 importa.
Teniendo esto en cuenta, si quieres aplicar dos rotaciones R y R' a un vector v, debes tener cuidado de aplicarlas en el orden que desees. Si quieres aplicar la rotación R antes de la rotación R', el orden correcto es v' = v * R * R'.
El mismo principio se aplica a las propias rotaciones. Si tienes una rotación R y quieres 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 quieres aplicar una pretransformación PreT y una postransformación PostT a una T, hazlo en el orden PreT * T * PostT. Posteriormente, aplicarlos a un vector v para conseguir un nuevo vector v' se hace como arriba, v' = v * PreR * R * PostR o v' = v * PreT * T * PostT.
La asociatividad de transformaciones y rotaciones también es importante. Si quieres aplicar varias operaciones sobre un vector en la misma línea de código Verse, como una transformación seguida de una rotación, la asociación de las operaciones es importante. Por ejemplo, puedes probar:
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 asocia implícitamente operaciones como:
ResultantVector:vector3 = (ForwardVector * ForwardToLeftUpOne) * UpToForward # compiles
Pero si intentas asociarla explícitamente de forma diferente como:
ResultantVector:vector3 = ForwardVector * (ForwardToLeftUpOne * UpToForward) # error, no operator'*'(:transform,:rotation)
Esto produce 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 rotaciones
Se eliminan RotateBy y UnrotateBy y se sustituyen por 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 consigue 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
Del mismo modo, Rotate y Unrotate se eliminan y se sustituyen por 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 multiplícala por el vector. Para recuperar el ForwardVector de LeftVector, invierte la rotación ForwardToLeft y aplícala por la derecha al 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 de transformaciones
TransformVector y TransformVectorNoScale se eliminan y se sustituyen por 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 cambiar la escala, TransformVectorNoScale, deja el valor de escala predeterminado en la transformación 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