.: Rotating a 3D Model
|
|
| |
In this tutorial we will learn how to display and rotate a 3D model. So using the Source Code from the Latest XNAEngine, we will create a new model class that can be used to display any .x model. So rename the source code folder to 3DModel and start the project, create a new class called ModelClass and add the following code:
|
|
Imports Microsoft.Xna.Framework
Imports Microsoft.Xna.Framework.Graphics
Imports Microsoft.Xna.Framework.Input
Namespace XNA
Public Class ModelClass
#Region "Objects and Variables"
Private ModelFile As Model ' The model object
Public Position As Vector3 = Vector3.One ' The world space position of the model
Public RotationY As Single = 0.0F ' The rotation angle in degrees for the y direction
Public RotationX As Single = 0.0F ' The rotation angle in degrees for the x direction
Public MyWorldRotation As Matrix = Matrix.Identity ' The rotation matrix, set as a unit matrix
Private Transforms As Matrix() ' The matrix used to decide how the model moves
Private AspectRatio As Single ' The aspectratio of the model
Private Projection As Matrix ' The matrix that determines how the world is seen.
Private View As Matrix ' The position and view direction of the camera
#End Region
''' <summary>
''' Initializes the model instance.
''' </summary>
''' <param name="ModelPath ">The full path to content pipeline model file with the xnb extension.</param>
Public Sub Initialize(ByVal ModelPath As String)
'If the file path contains the xnb extension then remove it
If Microsoft.VisualBasic.Right(ModelPath, 4) = ".xnb" Then
ModelPath = Mid(ModelPath, 0, Len(ModelPath) - 4)
End If
Try
'load the model at ModelPath for this instance
ModelFile = XNAEngine.XNAContentManager.Load(Of Model)(ModelPath)
Catch ex As Exception
End Try
'initially configure the various model variables
Transforms = New Matrix(ModelFile.Bones.Count) {}
AspectRatio = XNAEngine.XNAGraphics.GraphicsDevice.Viewport.Width / XNAEngine.XNAGraphics.GraphicsDevice.Viewport.Height
ModelFile.CopyAbsoluteBoneTransformsTo(Transforms)
Projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(45.0F), AspectRatio, 1.0F, 10000.0F)
View = Matrix.CreateLookAt(New Vector3(0.0F, 0.0F, 50.0F), Vector3.Zero, Vector3.Up)
'Set the default lighting flag, doe snot have to be set in every draw loop , so it is set here
For Each mesh As ModelMesh In ModelFile.Meshes
For Each effect As BasicEffect In mesh.Effects
effect.EnableDefaultLighting()
Next
Next
End Sub
''' <summary>
''' Updates the model instance.
''' </summary>
''' <param name="GetKeys ">The current keyboard state as Microsoft.XNA.Framework.Inout.KeyBoardState.</param>
Public Sub Update(ByVal GetKeys As KeyboardState)
'Check for the keys that we use. We don't want the left and right keys to act at the same time,
'so we put them in a IF-ElseIF statement, same with Up and Down
If GetKeys.IsKeyDown(Keys.Left) Then
'Rotate the model left
RotationY -= 1.0F
MyWorldRotation = Matrix.CreateRotationX(MathHelper.ToRadians(RotationX)) * _
Matrix.CreateRotationY(MathHelper.ToRadians(RotationY))
ElseIf GetKeys.IsKeyDown(Keys.Right) Then
'Rotate the model right
RotationY += 1.0F
MyWorldRotation = Matrix.CreateRotationX(MathHelper.ToRadians(RotationX)) * _
Matrix.CreateRotationY(MathHelper.ToRadians(RotationY))
End If
'We do want, left,right and up,down to act at the same time so we put them in different IF statements
If GetKeys.IsKeyDown(Keys.Up) Then
'Rotate the model Up
RotationX += 1.0F
MyWorldRotation = Matrix.CreateRotationX(MathHelper.ToRadians(RotationX)) * _
Matrix.CreateRotationY(MathHelper.ToRadians(RotationY))
ElseIf GetKeys.IsKeyDown(Keys.Down) Then
'Rotate the model Down
RotationX -= 1.0F
MyWorldRotation = Matrix.CreateRotationX(MathHelper.ToRadians(RotationX)) * _
Matrix.CreateRotationY(MathHelper.ToRadians(RotationY))
End If
End Sub
''' <summary>
''' Draws the model instance.
''' </summary>
Public Sub Draw()
' set the matrices that can change with every draw loop.
Projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(45.0F), AspectRatio, 1.0F, 10000.0F)
View = Matrix.CreateLookAt(New Vector3(0.0F, 0.0F, 50.0F), Vector3.Zero, Vector3.Up)
'apply the effects and draw
For Each mesh As ModelMesh In ModelFile.Meshes
For Each effect As BasicEffect In mesh.Effects
effect.View = View
effect.Projection = Projection
effect.World = MyWorldRotation * Transforms(mesh.ParentBone.Index) * Matrix.CreateTranslation(Position)
Next
mesh.Draw()
Next
End Sub
End Class
End Namespace
As always the class is made part of the XNA namespace by using the namespace statement. The objects and variables will be used to position, move and display the model itself. There are three subs that this class uses, the initialize sub takes the path to the model as an argument and then loads the model. The sub then sets the default settings for that model. The update sub takes the current keyboard state as a parameter and if any of the arrow keys are pressed, then the model position is updated accordingly. The draw sub draws the model to the backbuffer, as you can see each mesh in the model is drawn separately after having its effects applied to it.
In the ContentPipeline.Asset Class the AssetList becomes:
Public Shared Sub AssetList()
Asset.AddAssettoContentPipeline("Models\dice.x", Asset.AssetEnum.Model_x)
End Sub
Where dice.x is the original .x model file, located in a folder called models, which is at the same level as the VB Project folder as shown below:

Remember to run the content pipeline to convert the model to an xnb file before you run the 3DModel project.
Now, in the XNAEngine class, we create a new instance of the ModelClass alongside the GraphicsDevicemanager and ContentManager:
Private Dice As New ModelClass ' the dice
In the Initialize Sub the following line has been added:
Dice.Initialize(XNAGameProjectFolder & "\Content\Models\dice") ' Initialize the model and load content
Here the path to the xnb model file is passed into the dice.initialize sub.
In the Update Sub we have added:
Dice.Update(GetKeys)
Where the current keyboard state getkeys is passed into the dice.update sub.
Lastly, in the Draw sub the line below now exists:
Dice.Draw()
This sub as mentioned before draws the dice model to the screen.
Right, that's it, one thing to mention is that in the draw sub the line
XNAGraphics.GraphicsDevice.Clear(ClearOptions.Target, Color.Black, 1.0F, 0)
caused the dice, not to be drawn properly, this error was fixed by changing the above line to
XNAGraphics.GraphicsDevice.Clear(Color.Black)
Now, if you run the game it should look something like this:

and when you press the arrow keys:

I know that in the last tutorial I said I would create a skybox, and I will but I decided that I can't make a skybox until I can move around the game with the mouse and arrow keys, and that I couldn't see the movement around the game until I had an object that I can move around. So now we have a 3D object to move around and I will now work on a 3D Quaternion camera, which, when complete I will upload to the tutorials page , so, until then, Enjoy.
Web site contents © Copyright Alan Phipps 2006, All rights reserved.
Website templates |