Private Sub SetPresentParams(ByVal PP As PresentParameters) PP.DeviceWindow = Me 'This looks important. PP.Windowed = True 'We'll let it be windowed for now. :) PP.SwapEffect = SwapEffect.Discard 'This one is easy to set... Discard is what the documentation uses, but I figure this just draws over the 'last drawing. 'Now that we've set some properties, we can make our Device. End Sub |

Dim PsPms As PresentParameters 'So, we declare it. PsPms = New PresentParameters SetPresentParams(PsPms) |

Dim Paused As Boolean Dim VertexCount As Integer Dim Camera, FocusPt, CamNormal As Vector3 Const Pi As Single = 3.1415926535897931 Const PiHalf As Single = Pi / 2 Const PiThird As Single = Pi / 3 Const PiFourth As Single = Pi / 4 Const PiFifth As Single = Pi / 5 Const PiSixth As Single = Pi / 6 |

Dim Vertices() As CustomVertex.PositionColored 'Three dimensional plot - each vertex emits a color. |

VertexCount = 5 VxB = New VertexBuffer(GetType(CustomVertex.PositionColored), VertexCount, D9, Usage.WriteOnly, CustomVertex.PositionColored.Format, Pool.Managed) 'That is a LOT of non-trivial parameters. SetVertexBufferData(Vertices, VxB, D9) 'This is the same. |

Private Sub SetVertexBufferData(ByRef vs As CustomVertex.PositionColored(), ByVal vxbf As VertexBuffer, ByVal D9 As Device) 'After that workout, we now have to actually set the vertices. 'We do this by locking the surface out of D9 while we "operate" on it. Dim A As Array = vxbf.Lock(0, LockFlags.None) 'It returns a vanilla array... vs = DirectCast(A, CustomVertex.PositionColored()) 'So we have to convert it to an array of the appropriate vertices. 'Note that it will return an array of 3 because that's how many we specified in the vertex buffer constructor. vs(0) = New CustomVertex.PositionColored(200.0F, 150.0F, 0.0F, &HC0C0C0) 'X,Y,Z, and color. 'X,Y, and Z are self-explanatory: they are the coordinates of the vertex on the form. 'Color is in the &HRRGGBB format: the first two hex digits control the blue in the color, 3 and 4 control the green, and '5 and 6 control the red. Of course, you can always use Color.ToArgb() to get a color. 'I figure I can do all of this inline since I'm just setting values for the vertices. vs(1) = New CustomVertex.PositionColored(200.0F, 250.0F, 40.0F, &HFF) vs(2) = New CustomVertex.PositionColored(100.0F, 150.0F, 0.0F, &HFFFF00) 'vs(1).X = 200.0F : Vertices(1).Y = 250.0F : Vertices(1).Color = &HFF 'vs(2).X = 100.0F : Vertices(2).Y = 150.0F : Vertices(2).Color = &HFFFF00 'Now, you can't just place vertices anywhere: you have to place them clockwise. 'Specifically, you have to place them so that their 'normal vector' or the 'face' points into the screen. 'The normal vector is a vector that lies perpendicular to the object. Since our triangle (and all triangles) 'is a 2D object, the normal can be on one side or the other. In order to determine which side is the 'face' or the 'normal', we use the right hand rule. Put your right wrist at the first vertex of the triangle. Place the tips of the 'four big fingers of your right hand (I hope you have four) at the second vertex (or at least, in its direction). 'Now, see if you can, while closing the open palm of your right hand into a fist, point those four fingers to the 'direction of the third vertex. If you can do this, then the direction of your thumb indicates the normal. 'In this case, if you could do this, then you didn't draw your triangle correctly: try switching the last two vertices. 'If the last vertex is on the knuckle side of your hand, you need to flip your hand over to get the thumb to point in the 'direction of the normal vector... but save your wrist: this just means the normal vector is in the opposite direction 'of your thumb... and in this case, if your thumb is on top and the last point is on your knuckle side, then your points 'are drawn correctly. If you have decent visualization of 3D, then you only need to figure out which side you have to 'be on the triangle for the points to appear clockwise - in this case, the direction that you are looking is the direction 'of the normal vector. vs(3) = New CustomVertex.PositionColored(New Vector3(200.0F, 50.0F, 0.0F), &HFF0000) vs(4) = New CustomVertex.PositionColored(New Vector3(300.0F, 150.0F, 0.0F), &HFF00) 'It's important to unlock the vertex buffer, so that D9 can see what we put in there. vxbf.Unlock() End Sub |

So, we have a 3D figure. We need to define our "eye", that is, how the 3D object will appear on our screen to our eyes - will we be looking at from overhead, or from the side. Will we be up close to it? Or will we be really far away from it? Will it be right side up, or upside down? Will we be able to see the whole object? Will it be too far away to see? Will it be too close to see? We answer these questions with 'camera vectors' and 'view/projection matrices'. Camera vectors describe the location and orientation of the camera (placement, view focus, which way is up) and projection matrices describe our lens or eye (how wide is our lens, how far can we see, our aspect ratio, and how close we can see).

Camera vectors:

Camera = New Vector3(350.0F, 250.0F, 80.0F) FocusPt = New Vector3(0.0F, 0.0F, -30.0F) CamNormal = New Vector3(0.0F, 0.0F, 1.0F) |

Private Sub SetMatrices() D9.Transform.Projection = Matrix.PerspectiveFovLH(PiThird, 1.0F, 0.1F, 1000.0F) 'Pi/3 is the aperture of our camera lens. D9.Transform.View = Matrix.LookAtLH(Camera, FocusPt, CamNormal) End Sub |

We also need to set some RenderStates to get our figure to actually be visible:

D9.RenderState.CullMode = Cull.None 'Do not hide surfaces that we are not supposed to see. D9.RenderState.Lighting = False 'Do not try to light anything up. |

Now, for showing the drawing, I moved the drawing portion into a new subroutine as well:

Private Sub Render() Dim PrT As PrimitiveType = PrimitiveType.TriangleFan 'Now, inside the game loop we do all of the processing. 'Before we do any drawing, we would do the game manipulations and such, but 'since we aren't manipulating any game classes, variables, etc. 'we do nothing here, but go directly into the drawing phase. 'For DX9 3D, the first and most simplest thing is the clear statement. 'Not that it's very easy. D9.Clear(ClearFlags.Target, Color.Black, 1.0F, 0) 'The other overloads either sport an array of rectangles at the end, or make you assign a color in the ARGB integer format. 'When doing more sophisticated drawing, our drawing to the device would be between a .BeginScene and 'an .EndScene() call. D9.BeginScene() SetMatrices() 'So, we'd be drawing here. 'To draw a vertex buffer, we set the device to receive from a vertex stream. 'The data is ready to stream out of the vertex buffer into the device and the device should draw it onto the screen. D9.SetStreamSource(0, VxB, 0) 'StreamNumber is usually zero while we only have one vertex buffer that streams vertex data. 'Of course, we also have to tell it which vertex buffer to get vertex data from. 'Offset as 0 just tells the device how many vertices to skip before drawing. D9.VertexFormat = CustomVertex.PositionColored.Format 'We also need to tell the device what kind of vertices to draw. 'We have not told the device which vertices these are (that was the vertex buffer). 'This could actually come out of the loop, but there will usually be many different types of vertex types 'set within this loop. D9.DrawPrimitives(PrT, 0, GetPrimitiveCount(PrT, VertexCount)) 'This tells how to connect the vertices. 'LineList just means that every pair of vertices are the endpoints of a line (segment) 'LineStrip draws a line for the first two points, and from then on, the last vertex is the first vertex 'of the next line: so the 2nd vertex would serve as the end of the first segment and the 'beginning of the next: vertex #3 is the end of the second segment. 'PointList: a list of vertices, of course. 'TriangleList - every triad of vertices forms a triangle. 'TriangleStrip - like LineStrip: the last two vertices work as the first two vertices for the next 'triangle. 'TriangleFan - the first vertex serves as the first vertex for all triangles drawn like this. 'Afterwards, the last vertex drawn becomes the second vertex for the next triangle (from then on, only one 'vertex is required to make the next triangle). 'PrimitiveType P (rimitive Count) related to N (umber of vertices) 'LineList N = 2P P = N\2 'LineStrip N = P + 1 P = N - 1 'PointList N = P P = N 'TriangleList N = 3P P = N\3 'TriangleStrip N = P + 2 P = N - 2 'TriangleFan N = P + 2 P = N - 2 D9.EndScene() 'And we would NOT be drawing here. 'Typically the line immediately after .EndScene is .Present D9.Present() 'And of course, Present to present what the device has drawn on its own memory 'The device has its own drawing surface: present just transports it to the screen. End Sub |

Private Function GetPrimitiveCount(ByVal PrT As PrimitiveType, ByVal VertexNum As Integer) As Integer Select Case PrT Case PrimitiveType.LineList Return VertexNum \ 2 Case PrimitiveType.LineStrip Return VertexNum - 1 Case PrimitiveType.PointList Return VertexNum Case PrimitiveType.TriangleFan Return VertexNum - 2 Case PrimitiveType.TriangleList Return VertexNum \ 3 Case PrimitiveType.TriangleStrip Return VertexNum - 2 End Select End Function |

.vb file