Transforming Between Spaces

This is an exercise to help get us acquainted with transforming between different spaces -- object space and world space, nested object spaces, camera space, screen space, etc. We'll start out with just transformations from object space to world space (and nested object spaces), and go from there.

Working Example

We will use as a working example a simple game that displays a part of the solar system -- just the sun, earth, moon, and some stars. You can load a zip file with everything you need right here:

Download the ahove zip file, compile and run the program. You won't see a whole lot -- for some reason all of the objects seem to be displayed in the upper-right corner of the screen. Hmmm....

Part I: Transformation from Object Space to World Space

The reason that we don't see a whole lot is that each object's position is defined in the local space of it's parent. The sun's posision is defined in global space, but the earth's position is defined in sun space, and the moon's position is defined in earth space. When the camera goes to draw the objects on the screen, it asks each object for their world space, which is not yet defined:

    class WorldObject
    {
        public WorldObject Parent { get; set; }
        public Vector2 PositionInParentSpace { get; set; }
        public float RotationInParentSpace { get; set; }

        public Texture2D Texture;
        public Vector2 TextureOrigin;


        public WorldObject(Texture2D texture)
        {
            Texture = texture;
            TextureOrigin = new Vector2(texture.Width, texture.Height) / 2;
            Parent = null;
            PositionInParentSpace = Vector2.Zero;
            RotationInParentSpace = 0.0f;
        }

        public WorldObject(Texture2D texture, WorldObject parent)
        {
            Texture = texture;
            TextureOrigin = new Vector2(texture.Width, texture.Height) / 2;
            Parent = parent;
            PositionInParentSpace = Vector2.Zero;
            RotationInParentSpace = 0.0f;
        }


        public Vector2 PositionInWorldSpace
        {
            get
            {
                // Modify this property so that it returns the position
                // of this object in world space, based on the position
                // in parent space, and the position / rotation of ancestors

                return Vector2.Zero;
            }
            set
            {
                // Modify the Position In Parent Space so that the
                // position in world space matches the value passed in
            }
        }

        public float RotationInWorldSpace
        {
            get
            {
                // Modify this property so that it retursn the rotation
                // of this object in world space, based on the rotation 
                // in parent space, and the rotation of ancestors
                return 0.0f; ;
            }
            set
            {
                // Modify the rotation in Parent Space, so that the
                // position in world space matches the value passed in
            }
        }
    }
  

So, step one is modifying the PositionInWorldSpace and RotatinInWorldSpace properties so that they produce the correct values.

Transformation from Object Space to World Space

How do we transform a location (vector) from object space into wold space? Consider the following diagram, where we have the position of an object in local space (in red), and we want to find the position of that object in world space (in black):

Transform Image

To transform this point from local space to world space, we first need to rotate the point, to find its position in inertial space.

Transform Image

Now we have the position of the object in inertial space:

Transform Image

All we need to do is translate the point to get it in world space

Transform Image

So, to go from local space to global space

Likewise, to go from global space to local space, you just need to do those operations in reverse:

If you need to transform a point from a nested local space into global space:

Transform Image

Part II: Moving and Rotating the Camera

All of the drawing in our example code goes through the camera. As the code is currently, the camera asks for the position of each object in world space, and then draws the object on the screen at that location in screen space. So, if an object is at location [50,70] in world space, it is drawn at position [50,70] in the world.

    class Camera
    {
        public Vector2 Position { get; set; }
        public float Rotation { get; set; }
        public float Zoom { get; set; }

        private SpriteBatch mSpriteBatch;

        public Camera(SpriteBatch sb)
        {
            mSpriteBatch = sb;
            Position = new Vector2(Game1.SCREEN_WIDTH/ 2, Game1.SCREEN_HEIGHT/ 2);
            Rotation = 0.0f;
            Zoom = 1.0f;
        }

        public void Begin()
        {
            mSpriteBatch.Begin();
        }

        public void End()
        {
            mSpriteBatch.End();
        }
        public void Draw(WorldObject obj)
        {


            //Vector2 objPosInScreenSpace = objPosInCameraSpace + new Vector2(Game1.SCREEN_WIDTH / 2, Game1.SCREEN_HEIGHT / 2);


            // TODO#1:  Modify the objPosInScreenSpace to handle moving the camera left/right
            // TODO#2:  Modify the objPosInScreenSpace and objRotationInScreenSpace to handle rotating the camera
            // TODO#3:  Modify the objPosInSreenSpace and texture zoom (parameter in the draw method that has value 1.0f)
            //             to get zoom working correctly

            Vector2 objPosInCameraSpace = obj.PositionInWorldSpace;
            Vector2 objPosInScreenSpace = objPosInCameraSpace;
            float objRotationInScreenSpace = obj.RotationInWorldSpace;

            mSpriteBatch.Draw(obj.Texture, objPosInScreenSpace, null, Color.White, objRotationInScreenSpace, obj.TextureOrigin, 1.0f, SpriteEffects.None, 0);

        }
    }
  
To transform a point into screen space to do our actual drawing, we will need to go through two steps: Transform from world space into camera space, and then transform from camera space into screen space.

Part III: Camera Zoom

To zoom the camera, we need to change both the position of objects in camera space, and also their scale.

Part IV: Dynamic Camera / Camera Effects

If we add an Update method to our camrea, then we can have the camera move dynamically in the world -- everything from smooth camrea motions to camera effects like shaking cameras, wobly cameras, and the like.

Follow Camera

Download the following code to get you started:

Note that this code contains a solution to the placing objects in world space, and rotation / zoon of the camera, from parts I-III above.

Camera Effects

We can add all sorts of fun camera effects now, as well. The Shake method should cause the camera to shake for the number of seconds passed in.