Home
Search
 
What's New
Index
Books
Links
Q & A
Newsletter
Banners
 
Feedback
Tip Jar
 
C# Helper...
 
XML RSS Feed
Follow VBHelper on Twitter
 
 
 
MSDN Visual Basic Community
 
 
 
 
 
TitleDraw three interlocked 3-D blocks with Direct3D in Visual Basic 2005
DescriptionThis example shows how to draw three interlocked 3-D blocks with Direct3D in Visual Basic 2005.
KeywordsDirect3D, DirectX, blocks, interlocked, hidden surface removal, z-buffer, Visual Basic 2005
CategoriesGraphics, VB.NET
 
Add a module to the program and create the following Sub Main. Change the project to start by executing Sub Main.
 
Module SubMain
    ' Prepare Direct3D and run the event loop.
    Public Sub Main()
        ' Make the form.
        Dim frm As New RenderForm

        ' Initialize Direct3D.
        If frm.InitializeGraphics() Then
            frm.Show()

            ' While the form is valid,
            ' render the scene and process messages.
            Do While frm.Created
                frm.Render()
                Application.DoEvents()
            Loop
        End If
    End Sub
End Module
 
Change the name of the original form to RenderForm and give it the following InitializeGraphics subroutine. This routine initializes Direct3D and creates a device on which to draw. It also calls subroutine CreateVertexBuffer to define the three-dimensional vetex data.
 
' The Direct3D device.
Private m_Device As Device

' Data variables.
Private Const NUM_BLOCKS As Integer = 3
Private Const NUM_RECTANGLES As Integer = NUM_BLOCKS * 6
Private Const NUM_TRIANGLES As Integer = NUM_RECTANGLES * 2
Private Const NUM_POINTS As Integer = 3 * NUM_TRIANGLES

' The vertex buffer that holds drawing data.
Private m_VertexBuffer As VertexBuffer = Nothing

' Initialize the graphics device. Return True if successful.
Public Function InitializeGraphics() As Boolean
    Dim params As New PresentParameters
    params.Windowed = True
    params.SwapEffect = SwapEffect.Discard
    params.EnableAutoDepthStencil = True            ' Depth
        ' stencil on.
    params.AutoDepthStencilFormat = DepthFormat.D16

    ' Best: Hardware device and hardware vertex processing.
    Try
        m_Device = New Device(0, DeviceType.Hardware, _
            pic3d, _
            CreateFlags.HardwareVertexProcessing, params)
        Debug.WriteLine("Hardware, " & _
            "HardwareVertexProcessing")
    Catch
    End Try

    ' Good: Hardware device and software vertex processing.
    If m_Device Is Nothing Then
        Try
            m_Device = New Device(0, DeviceType.Hardware, _
                pic3d, _
                CreateFlags.SoftwareVertexProcessing, _
                    params)
            Debug.WriteLine("Hardware, " & _
                "SoftwareVertexProcessing")
        Catch
        End Try
    End If

    ' Adequate?: Software device and software vertex
    ' processing.
    If m_Device Is Nothing Then
        Try
            m_Device = New Device(0, DeviceType.Reference, _
                pic3d, _
                CreateFlags.SoftwareVertexProcessing, _
                    params)
            Debug.WriteLine("Reference, " & _
                "SoftwareVertexProcessing")
        Catch ex As Exception
            ' If we still can't make a device, give up.
            MessageBox.Show("Error initializing Direct3D" & _
                _
                vbCrLf & vbCrLf & ex.Message, _
                "Direct3D Error", MessageBoxButtons.OK)
            Return False
        End Try
    End If

    ' Turn off D3D lighting because 
    ' we set the vertex colors explicitly.
    m_Device.RenderState.Lighting = False

    ' Turn on the Z-buffer.
    m_Device.RenderState.ZBufferEnable = True

    ' Cull triangles that are oriented counter clockwise.
    m_Device.RenderState.CullMode = Cull.CounterClockwise

    ' Make points bigger so they're easy to see.
    m_Device.RenderState.PointSize = 4

    ' Start in solid mode.
    m_Device.RenderState.FillMode = FillMode.Solid

    ' Create the vertex data.
    CreateVertexBuffer()

    ' We succeeded.
    Return True
End Function
 
Subroutine CreateVertexBuffer calls MakeBlock to add points defining the three interlocking blocks.
 
' Create a vertex buffer for the device.
Public Sub CreateVertexBuffer()
    ' Create a buffer.
    m_VertexBuffer = New VertexBuffer( _
        GetType(CustomVertex.PositionColored), _
        NUM_POINTS, m_Device, 0, _
        CustomVertex.PositionColored.Format, _
        Pool.Default)

    ' Lock the vertex buffer. 
    ' Lock returns an array of positionColored objects.
    Dim vertices As CustomVertex.PositionColored() = _
        CType(m_VertexBuffer.Lock(0, 0), _
            CustomVertex.PositionColored())

    ' Make the vertexes.
    Dim i As Integer = 0

    ' X block.
    MakeBlock(vertices, i, _
        Color.FromArgb(255, 0, 255, 0), _
        Color.FromArgb(255, 0, 205, 0), _
        Color.FromArgb(255, 0, 158, 0), _
        2, 0.75, 1.5)

    ' Y block.
    MakeBlock(vertices, i, _
        Color.FromArgb(255, 255, 0, 0), _
        Color.FromArgb(255, 205, 0, 0), _
        Color.FromArgb(255, 158, 0, 0), _
        1.5, 2, 0.75)

    ' Z block.
    MakeBlock(vertices, i, _
        Color.FromArgb(255, 0, 0, 255), _
        Color.FromArgb(255, 0, 0, 205), _
        Color.FromArgb(255, 0, 0, 158), _
        0.75, 1.5, 2)

    m_VertexBuffer.Unlock()
End Sub
 
Subroutine MakeBlock calls MakeTriangle to make the triangles that define a block.
 
' Add triangles to the vertex buffer to define a block.
Private Sub MakeBlock(ByVal vertices() As _
    CustomVertex.PositionColored, ByRef i As Integer, _
    ByVal clr0 As Color, ByVal clr1 As Color, ByVal clr2 As _
        Color, _
    ByVal xwid As Single, ByVal ywid As Single, ByVal zwid _
        As Single)

    MakeTriangle(vertices, i, clr0, _
        -xwid, ywid, -zwid, _
        -xwid, ywid, zwid, _
        xwid, ywid, zwid)
    MakeTriangle(vertices, i, clr0, _
        xwid, ywid, zwid, _
        xwid, ywid, -zwid, _
        -xwid, ywid, -zwid)

    ... other calls to MakeTriangle omitted ...

End Sub
 
Subroutine MakeTriangle actually adds the vertices to the vertex buffer.
 
' Add a triangle to the vertex buffer.
Private Sub MakeTriangle(ByVal vertices() As _
    CustomVertex.PositionColored, ByRef i As Integer, ByVal _
    clr As Color, _
    ByVal x0 As Single, ByVal y0 As Single, ByVal z0 As _
        Single, _
    ByVal x1 As Single, ByVal y1 As Single, ByVal z1 As _
        Single, _
    ByVal x2 As Single, ByVal y2 As Single, ByVal z2 As _
        Single)

    vertices(i).X = x0
    vertices(i).Y = y0
    vertices(i).Z = z0
    vertices(i).Color = clr.ToArgb
    i += 1

    vertices(i).X = x1
    vertices(i).Y = y1
    vertices(i).Z = z1
    vertices(i).Color = clr.ToArgb
    i += 1

    vertices(i).X = x2
    vertices(i).Y = y2
    vertices(i).Z = z2
    vertices(i).Color = clr.ToArgb
    i += 1
End Sub
 
The form's Render method draws the data. It begins a Direct3D scene and then calls subroutine SetupMatrices to define the world, view, and projection transformations. It then calls the Direct3D device's DrawPrimitives method to draw the data.
 
' Draw.
Public Sub Render()
    ' Clear the back buffer and the Z-buffer.
    m_Device.Clear(ClearFlags.Target Or ClearFlags.ZBuffer, _
        Color.Black, 1, 0)

    ' Make a scene.
    m_Device.BeginScene()

    ' Draw stuff here...
    ' Setup the world, view, and projection matrices.
    SetupMatrices()

    ' Set the device's data stream source (the vertex
    ' buffer).
    m_Device.SetStreamSource(0, m_VertexBuffer, 0)

    ' Tell the device the format of the vertices.
    m_Device.VertexFormat = _
        CustomVertex.PositionColored.Format

    ' Draw the primitives in the data stream.
    m_Device.DrawPrimitives(PrimitiveType.TriangleList, 0, _
        NUM_TRIANGLES)

    ' End the scene and display.
    m_Device.EndScene()
    m_Device.Present()
End Sub
 
Subroutine SetupMatrices defines the world, view, and projection transformations. It makes the world transformation rotate the data around the Y axis once every 4 seconds. It makes a view transformation that assumes the "camera" is located at position (0, 3, -10) and looking at the origin. Finally it makes the projection transformation use a Pi / 4 radian field of view.
 
' Setup the world, view, and projection matrices.
Private Sub SetupMatrices()
    ' World Matrix:
    Const TICKS_PER_REV As Integer = 4000
    Dim angle As Double = Environment.TickCount * (2 * _
        Math.PI) / TICKS_PER_REV
    m_Device.Transform.World = Matrix.RotationY(CSng(angle))

    ' View Matrix:
    m_Device.Transform.View = Matrix.LookAtLH( _
        New Vector3(0, 3, -10), _
        New Vector3(0, 0, 0), _
        New Vector3(0, 1, 0))

    ' Projection Matrix:
    ' Perspective transformation defined by:
    '       Field of view           Pi / 4
    '       Aspect ratio            1
    '       Near clipping plane     Z = 1
    '       Far clipping plane      Z = 100
    m_Device.Transform.Projection = _
        Matrix.PerspectiveFovLH(Math.PI / 4, 1, 1, 100)
End Sub
 
This is a very complicated example and only key elements of code are shown here. Download the example to see further details. Also watch for my upcoming articles at DevX for a much more detailed explanation.
 
 
Copyright © 1997-2006 Rocky Mountain Computer Consulting, Inc.   All rights reserved.
  Updated