Free Web Hosting Provider - Web Hosting - E-commerce - High Speed Internet - Free Web Page
Search the Web

vbProgramming | Tutorials | Direct3D | Introduction to 3D Transformations
    vbProgramming 
Tutorials - 3D Transformations
 
     

vbProgramming Home :: vbProgramming Forums :: Tutorials :: Contact :: Links 

 

 

Let's move stuff in 3D! Start with the basics: Translation and Rotation

Introduction
If you've been following along my Direct3D tutorials you'll know that we loaded a cube in the previous tutorial. Now let's start moving the cube. I highly suggest you download the source code for the previous tutorial (see link at the end of the page) and follow along, because that's just how I've written this tutorial. If you've got a good imagination, then go right ahead and follow this tutorial without .NET open, this might save you time but you won't learn as much.

Let's get started - open up the source code from the previous tutorial

Background Information
We know that there are 3 matrices in Direct3D that the device uses:
World - This matrix contains information about the world, the locations of all objects, etc.
View
- This matrix tells Direct3D the location and orientation of the camera
Projection
- This matrix is basically how you see the world. Think of it as tweaking a camera lens. For example: by increasing the Field of View angle you can see more objects "around" you.

3rd Person Pseudocode
Here's an example of how a 3rd person game might go. Just note you don't need to type in any code (yet)

The character would be moved using the World matrix (ex: if you wanted him to move forward, increase the Z value).
dxDevice.Transform.World = Matrix.Translation(offsetX, offsetY, offsetZ)
In this case, if the character pushed Left then offsetX would have to be decreased by a certain amount. Same goes with OffsetZ. In this case, the offsetY would be the height of the ground (because the character is always on top of the ground).

The camera would be moved using the View matrix, and would look at the character at all times (the CameraTarget value of the LookAtLH view matrix would be set to the character's position), and the camera would be a certain distance away from the sprite.
dxDevice.Transform.View = Matrix.LookAtLH(cameraPosition, characterPosition, New Vector3(0,1,0))
Pretty much self explanatory, but we'll talk about calculating the cameraPosition (which is based on the characterPosition) in a different tutorial. The "New Vector3(0,1,0)" just symbolizes that Y is the 'up' direction (See note below).

Note: Most 3D Modeling programs use Z as the 'up' direction. You'll notice this when all 2d objects are located on the XY plane, and anything 3D has a "Z" value. Most DirectXers use Y as the Up direction. So if you were planning on moving a character back and forth, you'd adjust the Z value. If you were planning on going left and right, you'd adjust the X value. If you were planning on jumping, you'd adjust the Y value.

The typical projection matrix looks like this:
dxDevice.Transform.Projection = Matrix.PerspectiveFovLH(Math.PI / 4, DP.Width / DP.Height, 1.0F, 300.0F)
This was discussed in detail in a different tutorial. Just note the arguments in order: Field of view, aspect ratio, zNear, zFar. DP is the DisplayMode object.

1st Person Grounded Pseudocode
First person is slightly more confusing than 3rd person, but in a way it's a little simpler. Here we're discussing first person "grounded" (meaning the character is always on the ground).

In a first person game, YOU are the camera. The camera position is the character position. The camera target is determined by the left/right/up/down movements you make on your mouse (we'll discuss this later, some trig is required for this).

Basically what you want to do is translate the the world.
dxDevice.Transform.World = Matrix.Translation(offsetX, offsetY, offsetZ)
For the view you figure out the forward direction (which requires trig, as mentioned before, and will be discussed later)
dxDevice.Transform.View = Matrix.LookAtLH(characterPosition, APointInFrontOfTheCharacter, new Vector3(0,1,0))  'Pseudocode
And the projection is the same thing
D3Ddev.Transform.Projection = Matrix.PerspectiveFovLH(Math.PI / 4, DP.Width / DP.Height, 1.0F, 300.0F)



1st Person Free-Fly Pseudocode
Free-Fly is a bit more confusing :).

In free fly, you move the mouse up down left right, but you can move wherever you want. If you move the mouse up so that the camera is facing 45 degrees up, and push "up" on your keyboard (or "W" or whatever key you assigned), then the character will be moving 45-degrees forward.

Basically what you're doing here is adjusting your position based on the direction you're facing (we'll call this the Forward direction). What you want to do is, based on the left-right angle and the up-down angle you want to calculate the direction you face (this is the hard part), and move in that direction.

This will definitely be discussed in-depth in a elsewhere, as this topic requires a bit of math. Also the CameraUp won't always be (0,1,0) because we'll be able to do a "backflip" and make it (0,-1,0)....and other values as well!

Einstein's Theory of Relativity
What you'll need is the universal constant:
Lambda, and you'll need to make your world-view calculations based on this constant, remembering that the universe is ever expandi---

Nah. Just tried to scare you a bit.

You know when you're in a car, and the car next to you goes forward but you feel like you're moving backwards? You'll need a grasp of that concept.

The point I'm trying to get across is that you can't really design a camera class without having anything to reference to. Say you were making a 3rd person camera class, and the only object on the screen was the character....since the camera always follows the character and both the camera and the character move forward at the same time, you won't feel like you're moving at all.  Now if you were walking on the ground, then you would feel as though you're actually moving forward.

We'll need a reference object: a platform.
-------------
Click Here to download platform.x and roadtexture
.jpg and save them into your Bin folder (We're still using the previous tutorial's source code)*
*I modeled the platform (which is why it looks messed up), and the roadtexture.jpg came from a Microsoft sample.
*I also modeled the box that we used in the previous tutorial. You can't really mess up a box, so I did well on that.... but I did mess it up. I hate to say this, but I accidentally made the left edge of the box at (0,0,0) instead of the center of the box being at (0,0,0). So as you'll see in this tutorial, the box will look like it's shifted to the right a bit.
-------------

Let's just mess around with code for some time before we get to the real stuff :).

-Private Platform As clsMesh ' In Gameclass globals
-Platform = New clsMesh(D3Ddev, "platform.x", "roadtexture.jpg") 'Instantiate this right after you instantiate Car in Initialize()
-Platform.Render() 'Render this right after you do Car.Render in RenderScene()

In the previous tutorial I do believe I added a "bonus" for this tutorial that manipulated the world using the YawPitchAndRoll Matrix:
"D3Ddev.Transform.World = Matrix.Multiply(D3Ddev.Transform.World, Matrix.RotationYawPitchRoll(Math.PI / 10000, Math.PI / 10000, Math.PI / 10000))"
Delete that line for now, we don't need it now.

Run the code, you should see a box on top of the platform.

Removing the Pixilated-ness
As you can tell, the texture is stretched to fit the platform's size, so the texture looks pixelated.

In the Initialize sub, where you set up the device, type in the following lines:

D3Ddev.SamplerState(0).MinFilter = TextureFilter.Point
D3Ddev.SamplerState(0).MagFilter = TextureFilter.Linear

How does this work? I'm not sure exactly, but I can give you a general idea. MinFilter is the filtering which Direct3D uses when a texture is close to you. Setting it to Point gives you distinct clarity. MagFilter is the oppposite, when a texture is far from you. Setting it to Linear would "blend" the adjacent pixels with each other, but setting it to Point would make each pixel stand out, making it pixilated. The only way I figured this out was by experimentation. Try it out,

I felt that these 2 lines of code deserved to be in a separate section .... because they're might come in handy :).

Getting a feel for the 3D World: Simple 3rd Person Camera (Without Trig)
This section is very light - we'll just mess around getting around in the world for now before we delve into trignometry.

In GameClass globals, declare 

Public CharacterPosition As Vector3
Public CameraPosition As New Vector3(0,3,-5) 'We just want a good starting position for the camera

We'll make a very basic 3rd person camera.

Let's pseudocode!
-Pushing up/down/left/right will adjust CharacterPosition
-Pushing w/s/a/d will adjust the CameraPosition (I told you, this is a very basic camera class, we won't be doing "following" yet)
-There will be no rotation (Again, basic camera class)
-Because the camera is 3rd person, the camera target value in LookAtLH will be CharacterPosition
-The platform will stay in the same place ... obviously :). So before we render the platform we'll set the world to Identity

 Easy enough.

Form1's keydown should look like this:
 

        Select Case e.KeyCode
            'Up Down Left Right move the character position
            'W S A D move the camera position
            'Escape quits
            Case Keys.Up
                Game.CharacterPosition.Z += 0.05
            Case Keys.Down
                Game.CharacterPosition.Z -= 0.05
            Case Keys.Left
                Game.CharacterPosition.X -= 0.05
            Case Keys.Right
                Game.CharacterPosition.X += 0.05
            Case Keys.W
                Game.CameraPosition.Z += 0.05
            Case Keys.S
                Game.CameraPosition.Z -= 0.05
            Case Keys.A
                Game.CameraPosition.X -= 0.05
            Case Keys.D
                Game.CameraPosition.X += 0.05
            Case Keys.Escape
                Game.GameOver = True
        End Select


Self explanatory :).

There should be a line in Gameclass.Initailize() that looks like this:
D3Ddev.Transform.View = Matrix.LookAtLH(...........) 'Arguments culled out

Just replace it with:
D3Ddev.Transform.View = Matrix.LookAtLH(CameraPosition, CharacterPosition, New Vector3(0, 1, 0))

Now in the RenderScene() sub, right after BeginScene(), type in the same line:
D3Ddev.Transform.View = Matrix.LookAtLH(CameraPosition, CharacterPosition, New Vector3(0, 1, 0))


Right before Car.Render():
D3Ddev.Transform.World = Matrix.Translation(CharacterPosition)

Right before Platform.Render():
D3Ddev.Transform.World = Matrix.Identity 'Because the platform doesn't move, the car does!

Well? Run it,

First press Up: You'll notice that the character moves forward, and the camera stays in the same place and angles up so that it keeps looking at the character
Same thing goes for left, right, and down.

Now press W. You'll notice that the camera moves forward, angling down to keep looking at the character.

Now for Quirks!
Now press A. You'll almost get the impression that the camera is rotating around the character. It's not. All it's doing is going straight left, but still looking at the character. Keep on holding A.... the platform will start to fade away but, the platform will get distorted and you'll see these little jagged edges everywhere. I heard that you need to enable AA/AF to get rid of these "jaggies" but I suppose that's for another tutorial (as I don't know how to do this yet)

Another quirk:
Restart the application (just to start fresh), and press W. You'll notice that the character is kept on the center of the screen (actually, the left edge is, because as I said before I messed up modeling the box :P). Keep holding W.... WOAH the camera flips over the box. Why?  Because it went past the box, but it still has to look at the box, hence the flipping over.

Making the Camera Automatically Follow the Box
This is rather easy, because our "Game" doesn't handle rotation yet..

What we're basically going to do is get the Z position of the camera. Again, this is very simple.

Add this into GameClass:
   
Public DistanceFromSprite as Single = 5
    Private Sub CalculateCameraPosition(ByVal DistanceFromCharacter As Single)
        CameraPosition.Z = CharacterPosition.Z - DistanceFromCharacter
    End Sub

CalculateCameraPosition(DistanceFromSprite) right before Platform.Render()

Form1_Keydown should look like this now:

        Select Case e.KeyCode
            'Up Down Left Right move the character position
            'W S A D move the camera position
            '+ or - is to adjust camera distance from sprite
            'Escape quits
            Case Keys.Up
                Game.CharacterPosition.Z += 0.05
            Case Keys.Down
                Game.CharacterPosition.Z -= 0.05
            Case Keys.Left
                Game.CharacterPosition.X -= 0.05
            Case Keys.Right
                Game.CharacterPosition.X += 0.05
            Case Keys.W
                Game.CameraPosition.Y += 0.05
            Case Keys.S
                Game.CameraPosition.Y -= 0.05
            Case Keys.A
                Game.CameraPosition.X -= 0.05
            Case Keys.D
                Game.CameraPosition.X += 0.05
            Case Keys.Add
                Game.DistanceFromSprite -= .1
            Case Keys.Subtract
                Game.DistanceFromSprite += .1
            Case Keys.Escape
                Game.GameOver = True
        End Select

There you go. Run it, enjoy.
There's a few quirks in there (especially when you push Left and Right and the camera doesn't move forward) - but we'll fix all this in a "proper" 3rd person camera tutorial (this is just an example, and just a place to get you started).

What Next?
This tutorial was basically the first of several 3D Transformation tutorials.
In the next tutorial we'll discuss Trigonometry, and from then on I'll provide you with examples and samples of 1st and 3rd person classes.

There will definitely be a DirectInput tutorial soon, because what's a good 3D game without mouse input and proper keyboard input? I loathe and detest the regular windows keyboard input, especially with that annoying pause when you hold down a key at first.

For those of you who absolutely hate waiting, I've released source code for a 3rd person camera in vbProgramming forums. Please see the Mathematics section, there will a post called FPS Camera (I just now realized I posted a 3rd person camera when he asked for a first person camera....haha).

Final Word(s)
Bye.

The Source Code for this tutorial is located here:

You can also locate this by logging in to vbProgramming Forums and going to:
Tutorials > Tutorial Source Code > Source Code