home · software · code · tutorials · site map

3664
Congressman warns of current GA- Russia conflict in 2002!!!
Ron Paul in an interview with Jim Lehrer says in 2002 interview that by the US adopting a preemptive first Strike Doctrine would eventually lead to Russia invading GA
3552
Girls Get the Anime Look with Extra-Wide Contact Lenses
Girls in Japanese comics, cartoon videos or anime share a common look - big eyes that, by making the rest of the face look small, add the cuteness and sex appeal prized by many Japanese men. Since no amount of cosmetic surgery will make actual human eyes larger, some girls are trying another way to up their cute quotient: extra-wide contact lenses!
1262
'Everyone Will Remember Me as Some Sort of Monster'
A troubled teenager. An assault rifle. Eight slain in a mall. It was national news for a few days. Then it was forgotten.
822
Repurpose Your Nintendo as a Lunchbox (PICS)
I had a broken NES, a rotary tool, two small hinges, some glue and Alpha Flight's Sasquatch. What I ended up with was a lunchbox that gets all kinds of funny looks.
3104
Once You Look, You Can't Look Away (Pic)



Feb
1

GM6 D3D from the Ground Up - Chapter 3

2007 @ 10:16 AM

Chapter 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.
gm coordinate system

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.
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 strip

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.
triangle fan

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 >>


 Del.icio.us  Digg  Furl  Google  Reddit  Slashdot


Felicity Jane on April 18, 2007 at 1:10 AM

Well done!
A) Triangle Strips drawing above: Vertex 4 should be connected with Vertex 2, not with Vertex 1.
B) It seems that one cannot maintain a determined winding direction while applying Triangle Strips.

CommentsWrite a comment

:

:

:

Blogtastic RSS FEED

Linktastic


TysonC's Profile Page