Basic 3D Help Needed -- Top-down Rendering

Started by
3 comments, last by Buckeye 13 years, 6 months ago
I have a great 2D game right now where I am using sprites as spaceships. I want to upgrade my technology and start using 3d Models instead of sprites.

What I want to do is create a 3D world that exists on a plane, and I want to have a top-down camera view like so:

_____________ +x
|
|
|
|
|
|
+y

This will let me use all my existing code for ship movement and projectiles, etc. All I want to do is create a 3D world that mirrors my current 2D world, and I want to draw a model at the correct position and depth on the screen.

Here is my current draw function.
public void Draw(GameTime gameTime)        {            starfield.Draw(cam.Pos, cam.Zoom);            spriteBatch.Begin(SpriteSortMode.FrontToBack,                                 BlendState.NonPremultiplied,                                 null, null, null, null,                                cam.get_transformation(device));            int camx = (int)cam.Pos.X;            int camy = (int)cam.Pos.Y;            //Rectangle blackRect = new Rectangle(-10000, -10000, 100000 + (int)WorldSize.X, 100000 + (int)WorldSize.Y);            //spriteBatch.Draw(MinimapTex, blackRect, Color.Black);            // this view rectangle shifts around with the camera to provide a bit of a parallax feel to the background image            Rectangle viewRectangle = new Rectangle(camx - (screenWidth / 2) - camx / 10, camy - (screenHeight / 2) - camy / 10, screenWidth + 200, screenWidth + 200);            spriteBatch.Draw(backgroundTexture, viewRectangle, null, Color.White, 0, Vector2.Zero, SpriteEffects.None, 0.01f);            viewRectangle = new Rectangle(camx - (screenWidth / 2) - camx / 8, camy - (screenHeight / 2) - camy / 8, screenWidth + 200, screenWidth + 200);            spriteBatch.Draw(debrisfield2Texture, viewRectangle, null, Color.White, 0, Vector2.Zero, SpriteEffects.None, 0.1f);            viewRectangle = new Rectangle(camx - (screenWidth / 2) - camx / 5, camy - (screenHeight / 2) - camy / 5, screenWidth + 200, screenWidth + 200);            spriteBatch.Draw(debrisfieldTexture, viewRectangle, null, Color.White, 0, Vector2.Zero, SpriteEffects.None, 0.1f);                              foreach (Ship ship in ShipList)                {                    DrawShipInfo(spriteBatch, ship);                    ship.Draw(gameTime, spriteBatch);                }                // draw the alpha-blended particles                particleEffectManager.Draw(spriteBatch, "AlphaBlend", cam);                spriteBatch.End();                // draw the additive particles                spriteBatch.Begin(SpriteSortMode.Texture,                                 BlendState.Additive,                                 null, null, null, null,                                 cam.get_transformation(device));                                    particleEffectManager.Draw(spriteBatch, "Additive", cam);                spriteBatch.End();                       debrisField.Draw(cam.Pos, cam.Zoom);        }


So I know that this is a broad question, but what do I need to do to set up a 3D world with a camera that is slaved to my 2D camera? I'm speaking in very general terms.

Here is what I have been trying: I have replaced my regular ship's draw function with this DrawModel:
        private void DrawModel()        {            Vector3 world_Position = new Vector3(device.Viewport.Width / 2, -device.Viewport.Height / 2, 0);            Vector3 cameraPosition = new Vector3(world.GetCam().Pos, 1000);            // Copy any parent transforms.            Matrix[] transforms = new Matrix[xwingModel.Bones.Count];            xwingModel.CopyAbsoluteBoneTransformsTo(transforms);            // Draw the model. A model can have multiple meshes, so loop.            foreach (ModelMesh mesh in xwingModel.Meshes)            {                // This is where the mesh orientation is set, as well                 // as our camera and projection.                foreach (BasicEffect effect in mesh.Effects)                {                    effect.EnableDefaultLighting();                    effect.World = transforms[mesh.ParentBone.Index] *                        Matrix.CreateRotationZ(-this.rotation) * Matrix.CreateScale(.50f)                        * Matrix.CreateTranslation(new Vector3(-Position.X, Position.Y, 400));                    effect.View = Matrix.CreateLookAt(cameraPosition,                        Vector3.Zero, new Vector3(0, -1, 0));                   effect.Projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(45.0f), aspectRatio, 1.0f, 10000.0f);                    //effect.Projection = Matrix.CreateOrthographic(1280, 720, 1, 1000);                }                // Draw the mesh, using the effects set above.                mesh.Draw();            }        }

This function draws a model but it's just not right. I know that I'm not creating my 3D world properly.

So again, the real question here is:

1) How do I initialize a 3D world and set a camera up with a top-down perspective?

2) How do I ensure that my models are drawn onto the same Z-plane as my current 2D ships? If my 2D ship moves 50 pixels, I want to move my 3D ship 50 pixels.

Code examples appreciated.
Advertisement
Some additional information:

My world right now is set up as a 5000x5000 area and the ships can move freely about inside this area. The ships all have a Vector2 "Position".

One of the issues I think I have is that I'm not creating a 3D world that is aware of my 2D world. When I tell a 3D model to draw at a position, it draws in Screen Space and not my world space.

I think that I need to create the world at a higher level that inside my draw code. I'm a real noob with 3D stuff, so again, lengthier explanations are appreciated.
Please, someone show me how to set up an orthogonal projection!
I would start by representing your positions as Vector3 with z=0;
Place your camera somewhere it can look at the XY plane ((0,0,50) for example);
Orient the camera so it is looking down the -z axis;
Set your projection matrix to an ortho projection;


I'm not particularly familiar with C#, but I believe using Matrix.OrthoLH or OrthoOffCenterLH will be your starting point, for which you can google.

Please don't PM me with questions. Post them in the forums for everyone's benefit, and I can embarrass myself publicly.

You don't forget how to play when you grow old; you grow old when you forget how to play.

This topic is closed to new replies.

Advertisement