1. This forum is obsolete and read-only. Feel free to contact us at support.keenswh.com

[Tutorial] How to do Vector Transformations with World Matricies

Discussion in 'Programming Guides and Tools' started by Whiplash141, Feb 7, 2018.

Thread Status:
This last post in this thread was made more than 31 days old.
  1. Whiplash141

    Whiplash141 Junior Engineer

    Messages:
    964
    Howdy!

    At a Glance

    • World matrices map a vector from an entity's local space to the world space
    • Vectors in Space Engineers are considered row major when doing operations with matrices
    Intro

    Vector transformations are a bit difficult to understand, so I figured I'd put together a little guide to help y'all use this incredibly helpful tool in your programs :)

    World vs. Body Coordinate Frames
    The important coordinate frames that I will speak of come in 2 varieties:
    World and Body.

    A World frame is a coordinate system that stays stationary. The origin does not move, nor do the X ,Y, or Z axes. This is often called the "ground frame" in Earth based engineering applications. The GPS in-game uses the world frame for example.

    A Body frame is a coordinate system that is affixed to a particular body within the world frame. The origin of this body frame is free to translate in the world frame, and the local x, y, and z axes of the body frame can rotate relative to the stationary World frame.

    [​IMG]

    Direction Vectors vs. Position Vectors
    Now let's clarify the difference between position vectors and direction vectors.

    A position vector defines a point in space that is measured from the origin of the coordinate system.
    A direction vector defines a specific direction. (Velocity and acceleration vectors are examples of this)

    Example:
    [​IMG]

    In this example, Position A and B are position vectors in the world frame. Direction AB is a direction vector in the world frame that specifies the direction towards B from A.

    To get this direction vector we simply subtract!
    <Direction> = <End position> - <Start position>

    Thus:
    Direction AB = Position B - Position A

    Composition of a World Matrix
    A Space Engineers world matrix maps a vector from a block's body space to world space.
    (CubeGrids have world matrices as well!)

    [​IMG]

    The first 3 rows of the World Matrix specify the orientation of the body's direction vectors in world space. The 4th row specifies the location of the body frame within the world frame.
    (The 0's and the 1 in the last column are simply placeholders since Vrage's matrices need to be 4x4)

    We can use this information to easily convert between body and world frames!

    Transformations!!!
    Now you may be asking "What the heck is a Transformation"?

    Sounds pretty scary and complex, right? Nope!

    In Space Engineers, a transformation is simply a matrix-vector multiplication!

    Vector transformations allow you to do cool things like convert a world velocity to a block relative local velocity!

    [​IMG]
    (Note that the math above is for direction vectors)

    In general we:
    • Use Vector3D.TransformNormal() for direction vectors (velocity, acceleration, relative positions)
    • Use Vector3D.Transform() for position vectors (but not world to body position transforms)
    Body Direction to World Direction
    For direction vectors we use Vector3D.TransformNormal() and the world matrix.
    Code:
    Vector3D bodyDirection = new Vector3D(1,2,3);
    IMyTerminalBlock referenceBlock = SomeFunctionToAssignThisBlock();
    
    //convert the local vector to a world direction vector
    Vector3D worldDirection = Vector3D.TransformNormal(bodyDirection, referenceBlock.WorldMatrix);
    
    World Direction to Body Direction
    To go from world direction to body directions, we use Vector3D.TransformNormal() and Transpose the world matrix.
    Code:
    Vector3D worldDirection = new Vector3D(69,69,69); //giggle
    IMyTerminalBlock referenceBlock = SomeFunctionToAssignThisBlock();
    
    //Convert worldDirection into a local direction
    Vector3D bodyVector = Vector3D.TransformNormal(worldDirection, MatrixD.Transpose(referenceBlock.WorldMatrix)); //note that we transpose to go from world -> body
    
    Body Position to World Position
    To transform a body position to a world position, we use Vector3D.Transform() and the world matrix.
    Code:
    Vector3D bodyPosition = new Vector3D(1,2,3);
    IMyTerminalBlock referenceBlock = SomeFunctionToAssignThisBlock();
    
    Vector3D worldPosition = Vector3D.Transform(bodyPosition, referenceBlock.WorldMatrix); //note no longer TransformNormal
    
    Note how we used Transform instead of TransformNormal because this was a position vector.

    World Position to Body Position
    This is a special case!

    In order to avoid performance heavy math, we change the world position vector into a world direction vector before our transform. This allows us to avoid using a matrix inversion (avoid these for better performance in your codes).

    In this method we use Vector3D.TransformNormal() and a Transposed world matrix.
    Code:
    Vector3D worldPosition = new Vector3D(69,69,69); //giggle
    IMyTerminalBlock referenceBlock = SomeFunctionToAssignThisBlock();
    
    Vector3D referenceWorldPosition = referenceBlock.WorldMatrix.Translation; //block.WorldMatrix.Translation is the same as block.GetPosition() btw
    
    //Convert worldPosition into a world direction
    Vector3D worldDirection = worldPosition - referenceWorldPosition ; //this is a vector starting at the reference block pointing at your desired position
    
    //Convert worldDirection into a local direction
    Vector3D bodyPosition = Vector3D.TransformNormal(worldDirection, MatrixD.Transpose(referenceBlock.WorldMatrix)); //note that we transpose to go from world -> body
    

    Afterword
    I hope that this helps! If y'all have any questions/uncertainties, don't be afraid to ask!
     
    Last edited: Jun 8, 2020
    • Informative Informative x 3
    • Like Like x 2
    • Friendly Friendly x 1
  2. Neyna

    Neyna Trainee Engineer

    Messages:
    9
    About transforming world vector to Block local vector, why are you multiplying by the transposed matrix and not the inversed matrix? This matrix does not seems orthgonal so that M(-1)=M(T).

    Is there some simplification about direction vector i dont know about? I spent a few hours trying to understand but i dont get it.

    This matrix should be composed of a rotation, scale and translation if it's the matrix used in directX to place the object in the world.
    [ rot rot rot translationX]
    [ rot rot rot translationY]
    [ rot rot rot translationZ]
    [ 0 0 0 1]
    and scale is a diagonal matrix with scale factor in the diagonal.

    Points have a 4th coordonate equals to 1 and direction to 0 so translation does not matter for directions.
    (rotation matrices are orthogonal so transpose = inverse but not scale, inverse of scale is 1/scale diagonal matrix)

    Does Keen use Homogeneous coordinates in their vector library?

    I really dont see why you use transpose instead of inverse.

    You would be very kind if you could enlight me :)
     
    Last edited: Jun 3, 2018
  3. Whiplash141

    Whiplash141 Junior Engineer

    Messages:
    964
    When we are rotating direction (not position) vectors, we only care about the orientation part of the matrix (the part boxed in green in my pictures above). The translation does not influence a direction transform at all. The orientation part of the matrix is a rotation matrix. Because this orientation matrix is orthagonal the transpose is equal to the inverse. This allows us to simplify the inversion into a transpose (which is much faster).
     
  4. Neyna

    Neyna Trainee Engineer

    Messages:
    9
    Ok now i get it, thank you very much :)
     
    • Friendly Friendly x 1
  5. Carlosmaid

    Carlosmaid Apprentice Engineer

    Messages:
    177
    Thanks for doing this! It's something that i was practically not known and your explanations clarified it :)
     
    • Friendly Friendly x 1
  6. Uncheat

    Uncheat Trainee Engineer

    Messages:
    12
    Thanks for the thread!
    But what is about the performance hit?
    Can below one be faster?
    Code:
    static public Vector3D TransformCustom(Vector3D Vec, MatrixD OrientationMatrix)
    			{
    				return new Vector3D(Vec.Dot(OrientationMatrix.Right), Vec.Dot(OrientationMatrix.Up), Vec.Dot(OrientationMatrix.Backward));
    			}
    And to convert from world orientation to local use:
    Code:
    //a
    Vector3D LocVec = TransformCustom(WorldVec, block.WorldMatrix);
    And back from local to the world:
    Code:
    //b
    Vector3D WorldVecCheck = TransformCustom(LocVec, MatrixD.Transpose(block.WorldMatrix))
    Or if Vector3D.TransformNormal is faster than 3 dot operations + Matri:woot:.Transpose can do next to get back from local to the world:
    Code:
    //c
    Vector3D WorldVecCheck2 = Vector3D.TransformNormal(LocVec, block.WorldMatrix);
    Looks like a + c is faster than a + b or any uses Matri:woot:.Transpose(block.WorldMatrix)
    Or Matri:woot:.Transpose() does the same that Vector3D TransformCustom() does exept first works with matrix?


    Code:
    //RESULT IS TRUE
    Echo ( "From world: " + ( LocVec == Vector3D.TransformNormal(WorldVec, MatrixD.Transpose(block.WorldMatrix)) ) );
    
    Echo ( "From local: " + ( WorldVec= = WorldVecCheck ) );
    Echo ( "From local 2: " + ( WorldVec= = WorldVecCheck2 ) );
    What is the best perfomance friendly choice?

    So after I wrote above I found in sources:
    So it's the Dot() and keep in mind I used it 3 times in one transform so it's 3 multiply and 2 sum operations, so it'll be 9mult and 6sum total in TransformCustom:

    This is Transpose just replace without calculations(faster? Or depends on servers memory?) :
    And this is TransformNormal that looks like the same perfomance heavy as TransformCustom mean 9 multiply and 6 sum:

    Conclusion:
    Transpose() is not nesserary
    Best choice for orientation transformation:
    world->loc is handmade TransformCustom()
    and
    loc->world is ingame Vector3D.TransformNormal()

    Thanks for your time.
    The ready code is below:
     
    Last edited: Sep 26, 2018
  7. Whiplash141

    Whiplash141 Junior Engineer

    Messages:
    964
    Those are literally the same thing.

    Addition and multiplication are incredibly fast operations.

    Also, transpose is practically free. It simple rearranges elements of a matrix. No math is performed. Trying to "optimize" this is unnecessary. Doing it manually also adds the chance of user error.

    I strongly disagree. While you can do it manually, I will not suggest that others do that. The above guide is based on verified build in methods. There is no need to literally rewrite the same math into custom methods.

    NO. This is a game convention. Changing this will cascade into issues later on in code that use these conventions. That is a terrible idea as it breaks the right hand rule convention by making the forward vector point backwards.

    Conclusion:

    • Don't change the sign of vector elements when transforming.
    • Addition and multiplication are very fast operations and you shouldn't worry about optimizing them out.
    • As such, the impact of the methods described in the guide have incredibly low performance overhead.
    • Your method essentially does the same thing as the above guide
     
    Last edited: Sep 29, 2018
  8. Uncheat

    Uncheat Trainee Engineer

    Messages:
    12
    Good to know
    Thx for the answer :)
     
    • Friendly Friendly x 1
Thread Status:
This last post in this thread was made more than 31 days old.