Feb
1
GM6 D3D from the Ground Up - Chapter 3
2007 @ 10:16 AMChapter 3 - Drawing in 3D: Primitives
A Primitive?
A
primitive is the smallest "building block" of a 3D scene. You construct everything by organizing primitives. Think of them like atoms that construct our physical world of matter. You can create pretty much anything, not constrained by complexity, with primitives.
Game Maker's 3D Coordinate System
Game Maker uses a special coordinate system inside 3D mode. Since it still wants to use rooms and such, the z and y-axes are switched. The z-axis is vertical, while the y-axis goes in and out of the screen.
Drawing Points in 3D
At some point or another, you've made some type of graphic on the computer. If so, you're familiar with pixels. They are the smallest dot in an image. However, we have a different paradigm in Direct3D. We construct our dots in 3D space and it will project them into 2D pixels.
Defining our 3D Canvas
We are first going to set our projection to an orthographic projection. Don't worry, we'll eventually get to the perspective projection. But, for now, let's keep it simple with the orthographic projection.
Add the following code after your call to
d3d_start();:
d3d_set_perspective(false);. If you recall, this function will turn off the default perspective projection and turn on our orthographic projection. Now we need to actually set up our projection. In the Draw event, add the following code:
d3d_set_projection(x, y, 10, objVertices.x, objVertices.y, 10, 0, 0, 1);
Synopsis:
d3d_set_projection(xfrom, yfrom, zfrom, xto, yto, zto, xup, yup, zup);
xfrom, yfrom, and zfrom for a 3D-coordinate. This coordinate is where the "camera" is located. In our example, we put it at (x,y,10).
The projection starts from the object's position in the room and 10 units into the z-axis. xto, yto, and zto form another 3D-coordinate. This coordinate is the point the camera is looking towards. in our example, we set it to look at objVertices. (We are about to create this object which will draw some points on the screen.) So imagine the camera pointed to look towards our object. The xup, yup, and zup parameters define a 3D
vector. This vector describes the direction that the camera considers upwards. In this case, it's the z-axis.
A 3D Point
To construct a 3D point, we use the Game Maker function
d3d_vertex(x,y,z);. x,y, and z form a 3D coordinate as you should have assumed by now.
Let's Draw Something Finally!
A vertex is just not a 3D point. It's a point where two lines intersect. So, you have to wonder: is it part of a line, a cube, or some arbitrary polygon? We have to tell Game Maker what our vertex is part of.
Drawing Points
Create an object named "objVertices" and place it somewhere in the room. Add this to its draw event:
draw_set_color(c_red);
d3d_primitive_begin(pr_pointlist);
d3d_vertex(x,y,-150);
d3d_vertex(x-50,y,-150);
d3d_primitive_end();
d3d_primitive_begin tells Game Maker to start building a new primitive. it takes one argument, and this argument describes the type of primitive to start building. In our case, we just want some points to be drawn, so we used
pr_pointlist. It simply draws the vertices that are part of the primitive without doing anything special to them.
d3d_primitive_end() closes the current primitive. Go ahead and run your game now. You should see two red dots drawn on the screen. You can play with the x,y,and z values to become more acquainted with the coordinate system and 3D drawing.
Drawing a More Complex Set of Points
Let's do something a bit more practical rather than two simple dots on our screen. Our next example will use D3D to draw a "spring" of points on the screen.
draw_set_color(c_red);
d3d_primitive_begin(pr_pointlist);
zpos = -50;
for(angle = 0.0; angle <= (2*pi)*3; angle += 0.1)
{
xpos = 50*sin(angle);
ypos = 50*cos(angle);
d3d_vertex(xpos, ypos, zpos);
zpos += 0.5;
}
d3d_primitive_end();
This code calculates x and y for an angle that spins between 0 and 360 degrees 3 times, whilst increasing the height of the next point. You don't have to know the trigonometry behind this, but it would be very useful. Unfortunately, it is outside the scope of this tutorial; however it would be easy to find on the web.
Drawing 3D Lines
pr_pointlist is fairly straight-forward. But now let's move on to a more complex primitive:
pr_linelist
draw_set_color(c_red);
d3d_primitive_begin(pr_linelist);
d3d_vertex(x,y,150);
d3d_vertex(x-50,y,150);
d3d_primitive_end();
Here, for every 2 vertices specified, a line is drawn.
Drawing a More Complex Set of Lines
Again, let's see a practical example.
draw_set_color(c_red);
d3d_primitive_begin(pr_linelist);
ypos = 0;
for(angle = 0; angle <= pi; angle+=(pi/20))
{
xpos = 50*sin(angle);
zpos = 50*cos(angle);
d3d_vertex(x+xpos, y+ypos, zpos);
xpos = 50*sin(angle + pi);
zpos = 50*cos(angle + pi);
d3d_vertex(x+xpos, y+ypos, zpos);
}
d3d_primitive_end();
Line Strips
A line strip is very similar to a line list. The major difference is that in a line strip, one line is built continuously with each vertex that is drawn. You can specify the line strip primitive by passing the argument
pr_linestrip to
d3d_primitive_begin().
Drawing Triangles in 3D
So far we've been drawing only open surfaces composed of just lines. To draw a closed surface that can be shaded, we must use a
polygon. A polygon is a shape with an arbitrary number of sides.
The Triangle
This is the simplest polygon possible, with just three sides. To draw these, we must specify the
pr_trianglelist primitive when calling
d3d_primitive_begin()
draw_set_color(c_red);
d3d_primitive_begin(pr_trianglelist);
d3d_vertex(x,y,50);
d3d_vertex(x+50,y+50,5);
d3d_vertex(x+100,y-50,-100);
d3d_primitive_end();
This code draws a single triangle with vertices at different positions.
pr_trianglelist draws a triangle with every three vertices specified. If the number of vertices specified isn't divisible by three, the remainder is ignored.
Winding
There is an order in which you should specify vertices that composes a triangle primitive. This is called
winding. There are basically two types of winding: clockwise and counter-clockwise. In clockwise winding, vertices are supplied in the clockwise direction from the first vertex. The opposite is true for counter-clockwise winding.

Polygons with clockwise winding are considered
front-facing by Direct3D, while polygons with counter-clockwise winding are considered
back-facing by Direct3D. This is important because you sometimes want to give the back of a polygon certain characteristics such as a different color. Therefore it is important to keep the winding of polygons in a scene consistent if possible. Most 3D models that are saved from a 3D suite program usually automatically do this for you. So you may not have to worry about it in some cases.
Triangle Strips
A triangle strip is a primitive similar to the
pr_trianglelist primitive. You can create one by passing
pr_trianglestrip to
d3d_primitive_begin(). This primitive allows you to draw connected triangles. By convention, once the first three vertices are drawn, you only have to add one more to get a whole other triangle. This is the bandwith saving caveat of using triangle strips. You can minimize data bandwith and memory usage when defining large amounts of triangles.
Triangle Fans
A triangle fan is a primitive similar to the
pr_trianglelist and
pr_trianglestrip primitives. You can create one by passing
pr_trianglefan to
d3d_primitive_begin().
The difference with this primitive is that you define triangles that "fan" around a central point. You could, for example, create 3 triangles by specifying four vertices, the first of which is the central vertex.
Drawing a More Complex Set of Triangles
Let's do something a bit more practical with our new triangle primitives and create a
solid object.
draw_set_color(c_red);
colorChange = 0;
d3d_primitive_begin(pr_trianglefan);
d3d_vertex(x,75,y);
for(angle = 0; angle < (2*pi); angle+=(pi/9))
{
xpos = 50*sin(angle);
ypos = 50*cos(angle);
if((colorChange mod 2) == 0)
{
draw_set_color(c_red);
}
else {
draw_set_color(c_green);
}
colorChange += 1;
d3d_vertex(x+xpos,75,y+ypos);
}
d3d_primitive_end();
d3d_primitive_begin(pr_trianglefan);
d3d_vertex(x,0,y);
for(angle = 0; angle < (2*pi); angle+=(pi/9))
{
xpos = 50*sin(angle);
ypos = 50*cos(angle);
if((colorChange mod 2) == 0)
{
draw_set_color(c_red);
}
else {
draw_set_color(c_green);
}
colorChange += 1;
d3d_vertex(x+xpos,75,y+ypos);
}
d3d_primitive_end();
This large piece of code may look intimidating at first, but it's really not that complex. What we are accomplishing here is drawing a cone with two triangle fan primitives. The first draws the flat bottom part of the cone. It starts off with a single central vertex and creates 8 around it in a circle. The second triangle fan starts off with the tip of the cone and creates 8 points around it in a circle matching up with the bottom of the cone. Simple, huh?
Polygon Culling
Polygon culling is a Direct3D optimization where primitives that are not visible are not drawn at all. It seems pretty logical that this is enabled, but sometimes you want to see the back of something. However, in our cone example, we never see the inside of the cone. So let's enable culling to tell D3D to not even bother drawing the inside of the cone.
d3d_set_culling(true); will enable backface culling. To disable it, just call
d3d_set_culling(false);
<< Previous Chapter Next Chapter >>
Jan
31
GM6 D3D from the Ground Up - Chapter 2
2007 @ 10:17 PMChapter 2 - Introduction to D3D Programming
I'm sure you have a firm understanding of our we can accomplish 3D drawing now. So, let's actually get into the real action.
Getting into 3D Mode
To do any 3D drawing in Game Maker, we must first set it into 3D mode. We can accomplish this by using the
d3d_start() function. Use the
d3d_end() function to put GM back into 2D mode.
Upon calling
d3d_start(), Game Maker automatically enable hidden surface removal. Hidden surface removal is a way to ensure that everything is drawn in the correct order. Whenever a pixel is drawn, it's assigned a value in the z-buffer that describes its distance from the viewer's perspective. Whenever another pixel needs to be drawn in that same location, D3D tests to see if this new pixel's z-buffer value is closer of further away from the viewer. If it is closer, it overwrites the old pixel. Otherwise, the new pixel is never drawn. However, there sometimes arises a special case where the z-buffer values are the same. This is called z-clipping. It is undefined as to what D3D draws and therefore you get some ugly results. You can toggle the z-buffer and hidden surface removal via the function
d3d_set_hidden({true|false});
Next, Game Maker automatically turns off the
Orthographic projection and turns on the
Perspective projection. You can toggle between the orthographic and perspective projections via the function
d3d_set_perspective({true|false});
Hello, 3D World!
Let's write a skeleton 3D application. Our goal is to simply set Game Maker into 3D mode.
Start a new Game Maker project and save it as "hello.gm6". Create a new object and name it "d3dController." This object will be used to execute code to put GM into 3D mode.
Right-click on "d3dController" and select "Properties..." Click on the "Add Event" button in the Object Properties dialog and click on the "Create" event.
Next, select the "Control" tab. Drag and Drop the "Execute a piece of code" library action into the "Actions:" list.
The GM code editor should show itself. Add the following code:
d3d_start(); //Initializes 3D mode
Now create a new room and add this object to it.
Drawing Some Shapes
Add a "Draw" event to our object. Again, add a new Code Execution action. We're going to simply draw a rectangle on the screen.
d3d_set_projection_ortho(0,0,room_width,room_height,0);
draw_set_color(c_red);
draw_rectangle(30,30,60,60,true);
The only unfamiliar code should be the
d3d_set_project_ortho function. However, you should have an idea of what it does already. Hopefully, you've guessed that it defines an othographic projection for Direct3D to project our coordinates to. If you recall, orthographic projections are for drawing text and images. So, you can use the familiar draw_rectangle function here.
d3d_set_projection_ortho
Synopsis:
d3d_set_projection_ortho(x, y, w, h, angle);
The function creates an orthographic projection over the specified viewing volume in the room. It is then rotated over the given angle. In our example, we just used the room's width and height. However, you could bind it to only a certain part of the window.
<< Previous Chapter Next Chapter >>
Jan
31
GM6 D3D from the Ground Up - Chapter 1
2007 @ 09:25 PMWelcome to my new series of tutorials for Game Maker 6.1's Direct3D wrapping. I will explain it and its concepts starting from the ground up - assuming no prior 3D knowledge.
Chapter 1 - Introduction to 3D and D3D
3D is an acronym meaning
three-dimensional: an object is being described having three dimensions that can be measured: width, height, and depth.
Illusions
You can't actually view an object in 3D on a computer monitor. However, it can be alluded to via
perspective: the illusion of things becoming smaller as the recede into the distance. Perspective is just one element of art that has been employed for years by traditional artists when simulating nature on a two dimensional canvas.
Effects in 3D
Rendering is transcribing the geometric description of a 3D object and representing it on the computer monitor.
Shading and Shadows
This is another trick employed by traditional artists trying to accurately depict nature for a very long time. Difference in color usually denotes a change in surface. A shadow appears on a surface when rays of light are broken before it hits said surface. Therefore, it can only exist in three dimensions. Portrayed accurately in 2D, it can dramatically enhance the 3D quality of the image.
Texture
Only so much can be done with pure shapes shaded with color. When that limit is reached, you can depend upon textures. Textures are real-life images applied to a 3D polygon to increase the detail greatly without having to describe the object with thousands of polygons - which can get very slow.
When you apply this texture to the polygon, you
map it. You supply the texture image and a bunch of coordinates on the texture,
texels, and the 3D graphics rasterizer will map the textures texels to corresponding vertices of the polygon. After the mapping is done, the texture is usually filtered to minimize the detrimental effects of the stretching and moving done whilst mapping the image.
Blending and Transparency
Blending is the combination of objects on the screen. There are different ways to blend things that are drawn with others in the scene to produce a large array of effects. For example, you can make an object slightly translucent. It will blend in partly with its background, creating the illusion that you can see through it.
Anti-Aliasing
A pixel is the smallest dot that you can draw on the screen.
Aliasing is the effect seen when objects appear with "jaggies" - individual pixels contrast with the background and created a jagged border. But when the borders are blended in with the background, it smooths them out. This is called "antialiasing."
3D Graphics Programming in GM
Now that we have covered some of the 3D concepts, we can actually start applying them via Game Maker's Direct3D wrapper.
Direct3D
Direct3D is a proprietary Microsoft 3D graphics library. It is widely deployed and well instituted. Game Maker 6.1 wraps some of its basic functions. Much more could be done with it, but at this point, things are relatively limited.
Coordinate Systems
We have to learn how to do something that has been talked about quite a bit in our 3D concepts introduction - describing a 3D object. Everything must be described in relation to a reference frame. Something you may be familiar with is window coordinates. They are measured in rows and columns of pixels. For example, in a 1024x768, a pixel in the middle would be located at (512, 384). That's a relatively common and well known coordinate system.
Cartesian Coordinates
Again, you should be familiar with this. Throughout your education, you should have graphed things quite a bit in math classes. This was most likely the coordinate system you were using.
Here, the origin is at (0,0). Coordinates are transcribed in (x,y) notation. There exists
axes in this system: lines representing dimensions going infinitely in both the positive and negative directions. Where two axes intersect to form right angles, they define a
plane, or simply a flat surface.
Coordinate Clipping
We have to describe our window and how D3D shall translate the 3D coordinates to window coordinates. To do this, we define bounds of the Cartesian system to occupy our window. These bounds form the region known as the
clipping region. Basically, we're limiting our coordinate system rather than having each axis spanning infinitely.
Vertices
A vertex is simply a point in space. You can think of it as a coordinate pair, triplet, etc. When you draw an object in 3D, it is composed of various
primitives. The most simple primitive is the vertex. Constructing geometry from vertices is like connecting the dots. This is how you form polygons.
The 3D Cartesian Coordinate System
We need to extend our familiar 2D coordinate system to include another axis. We are going to append the
z-axis onto the already existing x and y axes. As the x-axis goes horizontally and the y-axis vertically, the z-axis stretches infinitely from and toward the viewer. To describe it loosely, the positive z-axis comes out of the monitor while the negative z-axis recedes into the monitor.
Projections: Going from 3D to 2D
How exactly does Direct3D draw these 3D coordinates on our obviously 2D screen? Basically, it uses a lot of trigonometry and matrix operations. Fortunately, we don't have to deal with any of that low-level stuff. We simply define a
Projection for Direct3D. It will use our project to project, or flatten, our 3D information onto the 2D screen.
Types of Projections
Orthographic
This is also known as parallel projection. Here, a rectangular viewing volume is defined. Anything outside this volume is simply ignored. No perspective will be used here. Everything will appear the same size. Therefore, we can use this to draw 2D things such as text, images, GUI, etc. onto our 3D game.
Perspective
This is the more common perspective used. It adds perspective to the drawn 3D objects. The viewing volume is no longer rectangular, but is now a frustum. You can visualize the frustum has a camera cone, or a pyramid with a blunt point. Objects further back into the volume a drawn smaller than those closer to the viewer.
<< Previous Chapter
Next Chapter >>