Coding for Mobile Platforms

Random thoughts, sometimes relevant to mobile programming.

  • Mobile Coder

  • Subscribe to Mobile Coder and receive notifications of new posts by email.

    Join 183 other followers

Making a 3D Level using Blender

Posted by error454 on 07/14/2010


Since I am a horrible artist, I figured that it would be much easier to model than to draw.  For this reason I decided to do my first game in 3D.  My game uses a fixed camera view, the camera sits in one place and never moves (except possibly for special effects like camera shake).

Basics

Here is my first level prototype, it doesn’t get much more simple than this.

This 1st-grade style level started raising interesting questions that I didn’t have answers to

  • If I want to spawn an enemy, how do I find a specific location on the level surface?
  • How can I zoom my camera in so that the level fills the screen?
  • How do I zoom the camera in so that you can’t see the enemy spawn location?
  • How do I define areas in the level that are special zones, like a Safe Zone where enemies might congregate as part of their AI?

The solution I came up with was to build the level using dummy objects to mark important locations as well as provide a reference for the camera location.

Notice here that there are 3 green cubes, these are dummy objects that won’t be drawn in the game world.  The 3 dummy objects shown here are, starting at the left

  • PlayerStart
  • SafeZone
  • EnemySpawn

Here you can see the CamerHelper object, notice how the enemy spawn location is located beyond the bounds of the camera helper.

Naming Objects

Before getting to the code, it is important to name each of my helper objects so that I can find them in the game.

I do this in Blender in the Links and Materials section as shown below, you can see that the Cube.003 object has the name PlayerStart.  You change this just by highlighting and typing the desired name.

Name your objects!

After naming each helper object, I am finally ready to export my level.

I had a lot of teething issues when I started to export FBX files.  I learned a couple rules that are easy to explain by looking at the export dialog.  Before I start, I should mention that I always delete the camera and the light in Blender scenes.

  1. Be sure to select “Scene “Objects” to export all the objects in your scene
  2. Be sure to Un-Check the Rot X90 button otherwise your model will be rotated by 90 degrees.
  3. That’s it.

Drawing the level

When I first attempted to draw my level, it looked… wrong.  All my meshes were being drawn on top of each other?!?  The reason this happened is because I was ignoring bones.  What the heck is a bone?  Isn’t that used when you are animating characters?  I hadn’t drawn any bones in my level, so why are they being used?
Well as it turns out, FBX files such as mine, where you have groups of meshes in the scene, use bones.  A bone is used to describe where a mesh is in the world in relation to a parent mesh.  Kind of like describing where your elbow is in relation to your head (the parent, even though the head bone isn’t connected to the elbow bone directly…).  This bone stuff needs to be accounted for when drawing the level.  My drawing code looked like this once I fixed it:
        /// <summary>
        /// Draws the specified level, omitting helper objects.
        /// </summary>
        /// <param name="level">The level object you wish to draw</param>
        void DrawLevel(Level level)
        {
            ///Here I am defining a matrix to hold all of the bone transforms.
            ///A bone transform is simply a Matrix transform that describes
            /// how 1 bone is positioned in 3d space relative to the parent
            /// bone.
            Matrix[] transforms = new Matrix[level.model.Bones.Count];

            ///Next, I get all the bone transforms that are in my model
            /// and I copy them to the transforms Matrix defined above.
            level.model.CopyAbsoluteBoneTransformsTo(transforms);

            ///Lets loop through all the meshes in this level
            foreach (ModelMesh mesh in level.model.Meshes)
            {
                ///Don't draw helper objects, so omit anything
                ///named:
                /// CameraHelper
                /// PlayerStart
                /// EnemyStart
                /// SafeZone
                if (mesh.Name != "CameraHelper"
                    && mesh.Name != "PlayerStart"
                    && mesh.Name != "EnemyStart"
                    && mesh.Name != "SafeZone")
                {
                    ///If we got here it's because the mesh isn't
                    ///one of our helper objects.  So go ahead and draw it
                    foreach (BasicEffect effect in mesh.Effects)
                    {
                        effect.EnableDefaultLighting();
                        effect.PreferPerPixelLighting = true;

                        ///This is where the bones come in, we are setting
                        ///the effect's World Matrix to the ParentBone of the
                        ///current mesh.
                        effect.World = transforms[mesh.ParentBone.Index];

                        ///Set the proper matrices to view what our camera
                        ///is looking at
                        effect.View = camera.View;
                        effect.Projection = camera.Projection;
                    }
                    mesh.Draw();
                }
            }
        }

Don’t be impressed, I didn’t pull this out of my head, I learned it at creators.xna.com.  Once I blindly followed the source, I began to ask my self questions:

Self, what is the parentbone index, what does it represent in the game world?

Well, that is a stupid question, you see ParentBone.Index is just an index that returns the ParentBone.  So the question should be "What is ParentBone"?  ParentBone is the top level bone that this mesh is attached to, it describes how the current mesh is positioned relative to the parent mesh.  
Ok, so you're telling me it's the secret sauce that makes my Blender models look the way I intended them.

Self, why don’t I have to do this for all my meshes?

Ok, didn’t you learn this in gradeschool?  The reason you don’t have to do it for your other meshes is because your models were so simple, they were a single mesh and centered at (0,0,0).

Self, why do we assign transforms[mesh.ParentBone.Index] to the World Matrix?

Good question, the 3 matrices of the 3d world are

  1. World – This matrix describes the location and orientation of a mesh in the 3d world.  So if your hero is standing at the end of the platform and is rotated to look at the screen, well, this is the matrix that explains that to your GPU.
  2. View – This describes the same thing as the World matrix only it is for your camera.
  3. Perspective – This describes how the camera’s perspective looks, think of it like changing the lens in your camera or zooming in with the camera.  There is a difference between zooming the camera and simply moving the camera closer to an object – your field of view changes when you zoom, it doesn’t when you move the camera.
So to answer the question, when we do
effect.World = transforms[mesh.ParentBone.Index];
We are assigning the ParentBone (which is simply the top-level bone) transform to the World matrix.  We do this because the World matrix describes where in the world our object is.  The transform matrix  is a matrix that when applied to our mesh, will affect the Position and Rotation of the mesh.  By doing so, we will have positioned and rotated the mesh to the same position/rotation in the game world that we so carefully setup in our Blender scene when designing the level.
About these ads

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s

 
Follow

Get every new post delivered to your Inbox.

Join 183 other followers

%d bloggers like this: