Free Support Forum -

Correct way of transforming control points to global space

Just looking for clarification or documentation on how mesh vertex data is correctly transformed into global transform?

Is it simply GlobalTransform.TransformMatrix * vertexData?

Does the TransformationMatrix of Transform and GlobalTransform include the transformations from the Geometric scale/rot/translate, and pre and post rotation properties?


Can you please share source file so that we may further investigate to help you out.

This is a general question about the API rather than a specific model.

If I am writing my own importer for another application, and this format is simple compared to Aspose.ThreeD. In this app a node only has translation, rotation and scale. No geometric properties or pre/post rotation.

I need to know the following:

  • how do I correctly transform Geometry.ControlPoints into both local node coordinates
  • same as above but into global scene coordinate

Less about implementation details and more about whether additional transformations are necessary, especially considering the additions of GeometricRotation, GeometricScaling and GeometricTranslation. Also I’m not sure on whether PreRotation and PostRotation are in the Node.Transform.

I have attached an example file, but again that’s not the important bit. I’m looking for the rules and documentation. (100.6 KB)

        scene.RootNode.Accept( node =>
            Mesh mesh = node.GetEntity<Mesh>();

            if ( mesh != null )
                foreach ( int[] meshPolygon in mesh.Polygons )
                    // Polygon in glo
                    var globalPolygonPoints = new Vector3[meshPolygon.Length];

                    for ( int i = 0; i < meshPolygon.Length; i++ )
                        int cIndex = meshPolygon[i];
                        Vector3 controlPoint = new Vector3( mesh.ControlPoints[cIndex] );

                        // Is this correct? 
                        Vector3 globalControlPoint = node.GlobalTransform.TransformMatrix.MultiplyPoint( controlPoint );

                        // Does the above take care of:
                        // node.Transform.PreRotation;
                        // node.Transform.PostRotation;
                        // node.Transform.GeometricRotation;
                        // node.Transform.GeometricScaling;
                        // node.Transform.GeometricTranslation;

                        // Do I need to construct my own goemetric transform matrix??

                        Vector3 gRotation = node.Transform.GeometricRotation;
                        Matrix4 geometricMatrix = ( new TransformBuilder( ComposeOrder.Prepend ) )
                            .Translate( node.Transform.GeometricTranslation )
                            .RotateEulerDegree( gRotation.x, gRotation.y,
                                gRotation.z )
                            .Scale( node.Transform.GeometricScaling ).Matrix;

                        // OR Is this correct? 
                        globalControlPoint = ( node.GlobalTransform.TransformMatrix * geometricMatrix ).MultiplyPoint( controlPoint );

                        globalPolygonPoints[i] = globalControlPoint;
                    // Render my global polygon in native application
                    // e.g. RenderPolygon( globalPolygonPoints );

            return true;
        } );

Given the additions of Geometric properties of a node’s transform, does it make sense to add a read-only property, or extension method to Node to get the transformation matrix required to transform Geometry into global and local space?


I have observed your comments and created investigation ticket with ID THREEDNET-610 either is it possible or not. We will share feedback with you soon.

My apologies, I did just find the following:


Can you please confirm if this resolved your issue?

Hi Adnam

I found my answers in posts of the other thread:

The reason it has this “unexpected” result is that there is a PreRotation attribute defined in the node with value (-90 0 0), you can also find out this value in “Autodesk FBX Converter” tool. So a rotation (90 0 0) with a pre-rotation (-90 0 0) will eventually result into a rotation (0 0 0).

Moreover, The PreRotation and PostRotation is also exposed through Node.Transform. Since Node.GlobalTransform is a lazy evaluated property, it calculates the value only when you need it, and it decomposes the final global transformation matrix into Translation/Rotation/Scale. That is why they are all read-only properties, the Pre/Post rotation become meaningless in the global transformation.

We have added a new method EvaluateGlobalTransform in Node class:

/// <summary>
/// Evaluate the global transform, include the geometric transform or not.
/// </summary>
/// <param name="withGeometricTransform">Whether the geometric transform is needed.</param>
/// <returns></returns>
public Matrix4 EvaluateGlobalTransform(bool withGeometricTransform);

Just wasn’t able to find any documentation.



Its good to know that your issue has been resolved.