After being a die-hard VB6 guy, moving to VB.NET was about as thrilling as moving into a room with a million snakes, wasps and angry fat ladies. But I eventually bit the bullet and made the move. And I must say, it is quite nice. All of my personal development (development not done for Evil Corporations), deals with gaming. I have a large-scale project that I've been working on for quite a long time and will probably take the rest of my life to finish. Through my journey, I have made little test apps here and there. One of them is my Modeler application. This little application allows me to view X Files... move my camera around, etc... It was an application used to get me started in the world of DX9 and VB.NET. To understand this code, you will need a somewhat thorough understanding of VB.NET. First off, I referenced the DirectX libraries. To do this, right click on "References" in the Solution Explorer window and select "Add Reference". I chose Microsoft.DirectX, Microsoft.Direct3D and Microsoft.Direct3DX. These were the references I chose and I believe you may be able to get by without one of them. Anyway, I chose them because I further enhanced my app later. Once done, I opened up my form1 which I renamed to frmMain. Inside there, I added the following lines:
- Imports Microsoft.DirectX
- Imports Microsoft.DirectX.Direct3D
This tells VB.NET that you are going to be working with DirectX objects in the code and to act as though you are working in the DirectX namespace. This saves a lot of typing by not requiring you to put Microsoft.DirectX.<objectname> all through your code.
Now before, we can really do anything, we need a Device. So, I defined a variable inside the frmMain class called moDevice.
- Private moDevice As Device
This is the main device for our graphics rendering. Now, we need to initialize all of our objects, so I wrote a function called InitD3D. It takes a parameter of a Handle for where the rendering will occur. You can pass Me.Handle for the Form object (which is what I do).
I'm going to briefly cover this function as it is pretty straightforward. It works as a simple try...catch block. If it fails, then the program is worthless and I should quit anyway. Inside this function I:
Create my Present Params:
- uDispMode = Manager.Adapters.Default.CurrentDisplayMode
- uParms = New PresentParameters()
- With uParms
- .Windowed = True ' if you want full-screen, set to false
- .SwapEffect = SwapEffect.Discard
- 'our back buffer details, these are pretty important
- .BackBufferCount = 1
- .BackBufferFormat = uDispMode.Format
- .BackBufferHeight = uDispMode.Height
- .BackBufferWidth = uDispMode.Width
- .PresentationInterval = PresentInterval.Immediate
- .AutoDepthStencilFormat = DepthFormat.D16
- .EnableAutoDepthStencil = True
- End With
and Initialize my Device:
- moDevice = New Device(0, DeviceType.Hardware, lHandle, CreateFlags.HardwareVertexProcessing, uParms)
- bRes = Not moDevice Is Nothing
If all of that works, I return True. Now, I have to call this function, so I add this code to form Load:
- If InitD3D(Me.Handle) = False Then
- MsgBox("Unable to initialize Direct3D!", MsgBoxStyle.OKOnly, "Error")
- 'Was a Success
- End If
To clean up my program, I add a line to the Closing event of my form: moDevice = Nothing. At this point, you can actually run the program. It should start up, but you'll still only see your form that you created. That's because we aren't rendering anything.
So, let's do that. For simplicity, I added a Timer control to the form. I set the Interval to 30 and the Enabled to False. In my form_load event, I simply set the timer1.Enabled = True if initD3D returns true.
Inside the Timer1_Tick event, I add the following code:
- moDevice.Clear(ClearFlags.Target Or ClearFlags.ZBuffer, System.Drawing.Color.Black, 1.0F, 0)
- 'Do Our Rendering Here...
Pretty basic and simple. It is your normal Direct3D rendering routines. You clear the device of anything on it, then begin your new scene. I wrote a little comment indicating that we will be putting more stuff there. Then, you tell DirectX that you are done rendering and present it. At this point, if you run the program, your form should be black. Well, at least now you are telling DirectX what to do. :)
At the top of the form class, add the following defs:
- Private moMesh as Mesh
- Private mlMeshMaterials As Int32 = -1
- Private moMaterials() As Material
- Private moTextures() As Texture
Ideally, you would want to create a separate class for this data to contain your mesh object and functionality. Furthermore, you would want to create a class or function to generate your meshes and textures while being as resource efficient as possible. But for now, let's just cut to the chase. Its real easy to load a mesh file. I included the Dolphin.X file that comes with DirectX SDK but you should be able to use any X file you want. I won't go into the details of the LoadMesh sub-routine. Instead, you should open it and look at it yourself. It is pretty straight-forward. You will most likely want to look through the SDK docs to get a better idea of what you want to do.
Now that I have a sub that will load my mesh, I simply include it in my Form_Load after the InitD3D Call. Now, in order to render our mesh, we need to replace that commented line from above 'Render stuff here... in the Timer1_Tick event with some code to actually render.
- With moMesh
- For X = 0 to mlMeshMaterials - 1
- moDevice.Material = moMaterials(X)
- moDevice.SetTexture(0, moTextures(X))
- Next X
- End With
I wouldn't run the code just yet, as we are missing a pretty important step... where we are viewing from. So, let's set up some simple camera functionality. Usually, you would want to set this up in a class or some other encapsulated piece of code, but for simplicity sake, I am just brute forcing it.
When you open the project, you will see at the top of frmMain.vb there are a lot of variables regarding the camera controls there. I didn't want to put them here in order to save space and time.
Now, I am using .NET 2002. In this version, Microsoft did not expose the MouseWheel directly to us programmers, but since I know it is there, I simply added the following code to the frmMain form.
- Protected Overrides Sub OnMouseWheel(ByVal e As System.Windows.Forms.MouseEventArgs)
- If e.Delta < 0 Then
- 'Mousewheel down
- mlCameraY += 50
- 'Mousewheel Up
- mlCameraY -= 50
- End If
Anyway, the rest of the mouse functions are present in the code and I would strongly urge you to read through them.
I hope this tutorial has given you a quick overview of rendering a mesh in VB.NET. Realize that some parts of the code were intentionally left out for sake of keeping the article small. I STRONGLY urge you to read through the code!