Contact

 
Google
Web www.alanphipps.com

 
   
 
   
www.alanphipps.com

.: Displaying a 3D Texture

 
 

 

 

Hope you all had a good christmas and new year, now shall we get back to XNA Development. For this series we will start with the source code from the XNA Engine. Now, I have noticed the method for using textures in 3D is a little different than it was in the 2D series, at first it appeared quite frustrating but with a little patience it became clearer. So, copy the source code folder and rename the copy to 3DTexture, open the project and create a new class called TextureClass. Add the following code to this class:

 

Imports Microsoft.Xna.Framework
Imports Microsoft.Xna.Framework.Graphics

Namespace XNA

As always we need the Import and Namespace statements at the top of the file and the End NameSpace at the bottom of the file

 

#Region "Objects and Variables"

Public customEffect As Effect 'In XNA, all primitives must have an effect applied to them
Public vertices As VertexPositionTexture() ' There are a number of different vertex formats, we will use
'VertexPositionTexture array because we want to apply a texture and not a solid colour.

Public viewMatrix As Matrix ' Used to position the player's view
Public projectionMatrix As Matrix ' 'Used to calculate the player's view
Public vertexBuffer1 As VertexBuffer ' The vertices will be stored in the vertex buffer, before being
'streamed to the graphics device

Public TextureFile As Texture2D 'Used to hold the texture

#End Region

The various objects that will be used to display the texture. A texture needs 3D coordinates, these are held as vertices in the vertexbuffer, the vertexpositiontexture describes the kind of vertex used, basically the options are solid colour or texture, the texture object holds the actual texture and the an effect must be applied to all primitives (triangles) in XNA. The matrices are used to position the players view, but we won't be going in too deep on matrices in this tutorial.

Next will will add a couple of functions:

#Region "Subs and Functions"

'Configure the vertices for the texture
Public Sub SetUpVertices()

vertices = New VertexPositionTexture(4) {}

'Every Vertex has an x and y coordinate, however, the part of the texture that you want to display
'on top of that vertex are sometimes called the u and v coordinates. In XNA though, they are referred
'to as TextureCoordinate.X and TextureCoordinate.Y as shown below.

vertices(0).Position = New Vector3(-10.0F, 10.0F, 0.0F)
vertices(0).TextureCoordinate.X = 0
vertices(0).TextureCoordinate.Y = 0

vertices(1).Position = New Vector3(10.0F, 10.0F, 0.0F)
vertices(1).TextureCoordinate.X = 1
vertices(1).TextureCoordinate.Y = 0

vertices(2).Position = New Vector3(10.0F, -10.0F, 0.0F)
vertices(2).TextureCoordinate.X = 1
vertices(2).TextureCoordinate.Y = 1

vertices(3).Position = New Vector3(-10.0F, -10.0F, 0.0F)
vertices(3).TextureCoordinate.X = 0
vertices(3).TextureCoordinate.Y = 1

End Sub

'Configure the initial camera view
Public Sub SetUpCamera()

'Set the camera at position 0,0,40 - make it look at 0,0,0 and set "UP" as 0,1,0
viewMatrix = Matrix.CreateLookAt(New Vector3(0, 0, 40), New Vector3(0, 0, 0), New Vector3(0, 1, 0))
'Set the camera's view angle to 90 degrees, set the aspect ratio to game window width
'divided by game window height, then tell the game that any object that is closer to the camera than
'1.0f will not be drawn and any object further away than 50.0f will also, not be drawn

projectionMatrix = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, _
Game1.Window.ClientBounds.Width / Game1.Window.ClientBounds.Height, 1.0F, 50.0F)

'configure a few effect parameters
customEffect.Parameters("xView").SetValue(viewMatrix)
customEffect.Parameters("xProjection").SetValue(projectionMatrix)
customEffect.Parameters("xWorld").SetValue(Matrix.Identity)

End Sub

#End Region

SetUpVertices() assigns values to each vertex in the VertexPositionTexture array. A new vector3 is just a point in 3D space defined by X,Y,Z coordinates, although in this tutorial, Z=0, it is still a 3D coordinate. Vector3's take float (floating point or decimal) values and hence 10.0F means, convert 10.0 to a float and use that value. Now, an important point is how XNA draws vertices. Our vertices make a square, where the top-left vertex is drawn first and then the rest are drawn in a clockwise fashion. If we were to change the vertex order in the sub SetupVertices() from 0,1,2,3 to 0,3,2,1 then our square would be drawn in an anti-clockwise direction, when you run the game nothing will be displayed, this is because the texture is now drawn on the other side of the square, facing away from us. We can check this by repositioning our camera to the other side of the square, by changing the value of viewMatrix in SetupCamera() from 0,0,40 to 0,0,-40. This basically rotates the viewing position around the Y axis, we are now on the other side of our square and facing the opposite direction, and as if by magic we can see the texture again.

Another important point is the number of vertices we have used to draw our square. Computer graphics are drawn using triangles, if you have enough triangles and if they are small enough you can create any shape, in our case we have used two triangles to create a square. Each triangle has three corners, hence we would use six vertices for our square, but when you look at the code we have only used 4. As any game developer will tell you, the battle between quality and performance is never-ending, more triangles allows better quality but decreases performance and vice-versa. So that we can keep the number of triangles down we will not the declare two vertices that have the same position, rather we will declare one vertex and allow both triangles to use it.

Now that we are done with the TextureClass we will move onto the XNAEngine class:

A new TextureClass Object is declared beside the content manager:

Private XNATexture As New TextureClass ' The textureclass object

The initialize sub becomes:

'Initializes the XNAGame class instance, runs once when game starts
Protected Overrides Sub Initialize()
XNATexture.SetUpVertices()
Sound.InitializeEngine()
MyBase.Initialize()
'MyBase.Initialize runs LoadGraphicsContent, so SetUpCamera() must come after, so that the effect and
'texture objects have been assigned

XNATexture.SetUpCamera()
End Sub

 

The following line has been added to the LoadGraphicsContent() Sub


customEffect = XNAContentManager.Load(Of Effect)(XNAGameProjectFolder & "Content\Effects\effects")

This loads the compiled effect.xnb file.

 

The Draw Sub has also been changed:

'Renders any Backbuffer draw data to the screen
Protected Overrides Sub Draw(ByVal gameTime As GameTime)
XNAGraphics.GraphicsDevice.Clear(Color.Black)
'Add Game Logic Here

'Create a matrix and assign it to the Identity Matrix
Dim worldMatrix As Matrix = Matrix.Identity
'If you open the effects.fx file (not the effects.xnb file) with notepad you will find that "xWorld", "xTexture" are variables used
'by the effect. The effects file also contains 4 separate techniques for applying the effect.
'In this case we will use the "Textured" technique.

XNATexture.customEffect.Parameters("xWorld").SetValue(worldMatrix) 'Apply the Identity matrix as a parameter of the effect
XNATexture.customEffect.Parameters("xTexture").SetValue(XNATexture.TextureFile) 'Apply the texture object as a parameter of the effect
XNATexture.customEffect.CurrentTechnique = XNATexture.customEffect.Techniques("Textured")

'Once all parameters have been set, we will begin the actual drawing process. In XNA all primitives
'must have an effect applied to them.

XNATexture.customEffect.Begin()
'For each pass in the total number of passes made in the Textured technique
For Each temppass As EffectPass In XNATexture.customEffect.CurrentTechnique.Passes
'Begin this pass
temppass.Begin()

'associate the vertexdeclaration with our graphics device
XNAGraphics.GraphicsDevice.VertexDeclaration = New VertexDeclaration(XNAGraphics.GraphicsDevice, _
VertexPositionTexture.VertexElements)
'and then draw the primitives in the TriangleList style.
XNAGraphics.GraphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleFan, vertices, 0, 2)

'End the pass
temppass.End()
Next
'End the effect
XNATexture.customEffect.End()

MyBase.Draw(gameTime)
End Sub

It seems a complicated way to draw vertices but this is the way we have to do it, and we will trust that the XNA team know what they are doing. Now, as shown, all vertices have effects applied to them and then we loop through the collection of passes in the effect and DrawUserPrimitives, there are about 6 styles with which we can draw primitives, in our case we use the PrimitiveType.Trianglefan, but feel free to try the rest to see what they do. Thanks to Riemer for the effects file and excellent tutorials.

Now, remember to add the effects.fx file to the ContentPipeline.asset class's AssetList() Sub:

'Any Asset to be added to the content pipeline should be listed in this sub,
'using the AddAssettoContentPipeline Sub, example:
'Asset.AddAssettoContentPipeline("Images\Texture.png", Asset.AssetEnum.Texture_Sprite32bpp)

Public Shared Sub AssetList()
Asset.AddAssettoContentPipeline("Textures\skyfront.jpg", AssetEnum.Texture_ModelDXTmipmapped)
Asset.AddAssettoContentPipeline("Effects\effects.fx", AssetEnum.Effect_fx)
End Sub

As you can see I have updated the contentpipeline so that it supports fx files, remember to run the content pipeline before running our game, as shown below, so that the xnb files are created. In the contentpipeline.asset code I have change the value of AssetOutputFolder from ".\" to "content\", this means that a separate folder called content will be created to hold the xnb files rather than them being created in the same folder as the assets, feel free to change this back if you want.

XNA in VB.NET - Content Pipeline

 

Right, that's it, if you run the game you should get something like this:

XNA in VB.NET - 3D Texture

Just one other thing before I go, If you run the game and get the following error:

XNA in VB.NET - The method call is invalid

"The method call is invalid" is caused because your graphics card does not fully support Shader 2.0 and hence XNA. I have used the following method to fix this error but it is only temporary, I will be upgrading my graphics card soon.

Open the effects.fx file and change all occurrences of

if (xEnableLighting)
Output.LightingFactor = dot(Normal, -xLightDirection);

to

// if (xEnableLighting)
// Output.LightingFactor = dot(Normal, -xLightDirection);

This basically makes this code a comment rather than actual code. Now, recompile the fx file using the contentpipeline and the error should be fixed. In the next tutorial I will be be making a skybox with six textures, and when its done I will upload it to the tutorials page. So until then, enjoy.

 

3DTexture Source Code - 1,883Kb
Next Tutorial - Rotating a 3D Model

     
 
 
     

 

Web site contents © Copyright Alan Phipps 2006, All rights reserved.
Website templates
   
 
 

 

__PayPal

PayPal - Any Amount is Welcome
 
Please Donate to the Nvidia Geforce Go 7950 GTX Fund, All donations welcome. Thanks.

 

XNA in C#

 
 

 

Games at Amazon