home · software · code · tutorials · site map

3667
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
3543
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!
1263
'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.
3105
Once You Look, You Can't Look Away (Pic)



Feb
2

GM6 D3D from the Ground Up - Chapter 6

2007 @ 12:45 PM

Chapter 6 - Blending and Basic Shapes

Blending

Blending is simply blending colors together. For example, you can draw background objects and then blend a window on top of them to create a translucency effect. There are many different ways to blend colors, however, not just adding them together.

Combining Colors

The color value that is already stored in the color buffer is called the destination color. The source color is the color coming in due to new rendering commands. To activate a blending mode, you can use the function draw_set_blend_mode(mode). Several different modes exist: bm_normal, bm_add, bm_subtract, and bm_max. You must not forget to reset the blending mode to bm_normal when you're done drawing the blended object, however.

Drawing Basic Shapes

Game Maker has functions that simplify some commonly used 3D shapes for us. You can draw blocks, cylinders, cones, ellipsoids, walls, and floors with the commands. The shapes already have their normals and texture coordinates defined, so you don't have to worry about that. The functions follow an easy to use convention - specify the dimensions and a few special parameters for certain shapes(E.G., closed for the cone shape to specify whether or not to close the end of it). Check the Game Maker manual's page on Drawing Basic Shapes for a complete function reference.

Practical Example

Let's use what we have learned on blending and Game Maker's basic shapes to create a fake reflection.
draw_set_color(c_red);
d3d_draw_block(x-15,y-15,40,x+15,y+15,10,-1,0,0);
//Reflect Block and Light
d3d_light_define_point(2,d3dController.x,d3dController.y,-50,1024,c_white);
d3d_draw_block(x-15,y-15,-10,x+15,y+15,-40,-1,0,0);
draw_set_blend_mode(bm_add);
d3d_set_lighting(false);
draw_set_color(c_blue);
d3d_draw_floor(0,500,0,500,0,0,-1,0,0);
d3d_set_lighting(true);
draw_set_blend_mode(bm_normal);
d3d_light_define_point(2,d3dController.x,d3dController.y,10,1024,c_white);
reflection
That's not a bad result, eh?
The first thing we do is draw a block using the function d3d_draw_block(x1,y1,z1,x2,y2,z2,texid,hrepeat,vrepeat). Disregard the texid, hrepeat, and vrepeat arguments for now. Those all have to do with textures, which will be covered soon. Next, we draw the reflected cube below the floor. We also reflect the light below the floor. Next we set the blending mode to bm_add with draw_set_blend_mode. We also disable lighting so it doesn't affect our blending. We then draw the floor which is blended with the reflected cube. After doing that, we reset the blending mode, reenable lighting, and move our light back to where it was.
As you can see, this isn't the most efficient nor elegant way to draw reflections. Everything reflected has to be drawn twice: once above and once below the floor. Combine that with a blending operation and you can really slow your game down.

Other Basic Shapes

Consult the Game Maker manual and play around with the different types of primitives. They're all very simple to use and can be very useful.

<< Previous Chapter      Next Chapter >>

Comments (0)
 Del.icio.us  Digg  Furl  Google  Reddit  Slashdot


Feb
2

GM6 D3D from the Ground Up - Chapter 5

2007 @ 10:13 AM

Chapter 5 - Basic Color and Lighting

Up until now, all of our work has appeared rather bland and not very practical for use in a good 3D game. All of this is about to change once we introduce color and lighting.

What is Color?

It's best to have an understanding of color as it appears in nature. Therefore we can have a better understanding of how to represent it in programming.

A Wave

Color is a wavelength of light that is visible to the human eye. Light whose wavelength is beyond the ends of the spectrum are not visible to the human eye. These include ultraviolet and infrared light, both of which you should be familiar with.

Something you may remember from grade school is that black is the abscense of color while white is the combination of all colors. A white object reflects all wavelengths of light evenly while a black object absorbs them. Therefore, when you perceive the color of an object, it depends upon how many wavelengths of light are absorbed and reflected. A shift in either makes you see a different color.

Color in D3D

Game Maker has a pretty nice list of color constants built in. These include colors like c_dkgray, c_teal, c_silver, etc. However, we can also build our own color. make_color_rgb(red,green,blue) will create a color with the red, green, and blue amounts specified. In computer graphics, RGB is widely used. Each amount of color is between 0 and 255, for 256 shades of each.
Before you draw a primitive, you can set the color of it using draw_set_color(color). This affects every primitive drawn until you set the color again. However, the best way to set color is with d3d_vertex_color(x,y,z,color,alpha) This is just an extension of our familiar d3d_vertex function. alpha is transparency. It is a value between 0-255. 0 is completely transparent while 255 is completely opaque.

d3d_primitive_begin(pr_trianglelist);
d3d_vertex_color(x,y,50,c_red,255);
d3d_vertex_color(x+50,y+50,5,c_teal,128);
d3d_vertex_color(x+100,y-50,-100,make_color_rgb(12,197,75),0);
d3d_primitive_end();
You may recognize this code. It was our old triangle example. But now we've extended it to include color. The first vertex's color is set to c_red. It has an alpha value of 255, so it has no transparencey at all. The next vertex has a color of c_teal. It has an alpha value of 128, so it is half transparent and half opaque. The last vertex has a color of RGB(12,197,75). This is a dull green color. It has an alpha value of 0. So, it is completely transparent.

Smooth Shading

You may have noticed that the triangle is shaded! Each vertex affects the color of the triangle, as you can see from running the program. The triangle is shaded smoothly from one color to another as it nears the other vertices. However, this is not always desirable. You can disable smooth shading by calling d3d_set_shading(false). You can reenable it by calling d3d_set_shading(true). When you disable it, the color of the triangle will be that of the first vertex.

Adding Light to a Scene

Ah, finally, light. The first thing you need to when starting to use light in D3D is call d3d_set_lighting(true). If you ever need to disable lighting, call d3d_set_lighting(false). Every light in D3D as an index. This index is unique to each light. So when you create a light, it is assigned an index that you pass to other functions to modify that individual light.
d3d_set_lighting(true);
d3d_light_define_direction(1,0.5,0.3,1,c_white);
d3d_light_enable(1,true);

[This should be in the Create event of an object.]
This code first enables lighting. Next, it defines a directional light with a call to d3d_light_define_direction(index,dx,dy,dz,color). A directional light is an ambient light. It's similar to the sun. The first argument of the function is 1. It's an arbitrary, small positive number that represents this light. For example, we could also do this to make it more readable:
lightSun = round(random(1024)+1);
d3d_light_define_direction(lightSun,0.5,0.3,1,c_white);
d3d_light_enable(lightSun,true);
The next three arguments specify the direction of the light. In our case, it's oriented halway towards the x-axis, 1/3 of the way towards the y-axis and pointed down the z-axis. The last argument is the color of the light.

Point Lights

The next kind of light is a point light. Point lights, used in conjunction with a gloabl directional light, can dramatically increase the realism of a scene. You can visualize a point light as a torch. It is single point where light radiates out from for a certain distance, losing intensity the further it goes.
You can define a point light with a call to d3d_light_define_point(index,x,y,z,range,color). Index is the light index, which you should be familiar with. x,y,z is a 3D coordinate specifying the position of the light in space. range is how far the light shines. color is, of course, the color of the light.

Surface Normals

A polygon cannot be shaded correctly without specifying a surface normal. A surface normal is a 3D normal vector that is perpendicular to the polygon(plane).
surface normal

Specifying a Normal

To actually give D3D a normal, we use the function d3d_vertex_normal(x,y,z,nx,ny,nz). x,y,z is the coordinate of the vertex while nx,ny,nz is the vector representing the normal for this vertex. You may have noticed that there is no color for this. To specify a color, we use the super-extended d3d_vertex_normal_color(x,y,z,nx,ny,nz,color,alpha).

Calculating the Surface Normal

x1 = argument0;
y1 = argument1;
z1 = argument2;

x2 = argument3;
y2 = argument4;
z2 = argument5;

x3 = argument6;
y3 = argument7;
z3 = argument8;

crossX = (y2-y1)*(z3-z1)-(y3-y1)*(z2-z1);
crossY = (z2-z1)*(x3-x1)-(z3-z1)*(x2-x1);
crossZ = (x2-x1)*(y3-y1)-(x3-x1)*(y2-y1);
You can find the normal of a polygon by forming the plane of a polygon from any three points on it. Since Game Maker only allows for triangles, this is easy. We then form the two vectors representing the plane and take their cross products. The resulting vector is perpendicular to the surface of our triangle. However, D3D prefers for all normals to be a unit normal. This is a surface normal with a length of 1. We can expand our normal calculator to include the conversion to a normal vector:
x1 = argument0;
y1 = argument1;
z1 = argument2;

x2 = argument3;
y2 = argument4;
z2 = argument5;

x3 = argument6;
y3 = argument7;
z3 = argument8;

crossX = (y2-y1)*(z3-z1)-(y3-y1)*(z2-z1);
crossY = (z2-z1)*(x3-x1)-(z3-z1)*(x2-x1);
crossZ = (x2-x1)*(y3-y1)-(x3-x1)*(y2-y1);

length = sqrt(sqr(crossX) + sqr(crossY) + sqr(crossZ));

global.normX = crossX/length;
global.normY = crossY/length;
global.normZ = crossZ/length;
We first find the length of the normal by squaring each component, adding them, and taking the square root of the sum. We then divide each component by the length to get a new normal vector with a length of one.

Vertex Normals

As you can see, you can specify a normal for every vertex. But we only know what the normal of the plane is. Thus we need to do some normal averaging. When you supply the true normal of a vertex, rather than the whole plane, D3D will smoothly shade it for us. Rather than giving the object a faceted look, it will look smooth and realistic.
To find the vertex normal, you have to average the normals of all triangles that share that vertex. Many model converters will do this job for you. It's too tedious to do by hand, so I won't discuss it here. It will, however, be shown in a later chapter.

<< Previous Chapter      Next Chapter >>

Comments (0)
 Del.icio.us  Digg  Furl  Google  Reddit  Slashdot


Feb
1

GM6 D3D from the Ground Up - Chapter 4

2007 @ 10:41 PM

Chapter 4 - Geometric Transformations

We've learned how to draw all kinds of stuff and start to compose a nice populated scene. But there is an integral part of scene elements that we have not discussed - positioning and orientation.
There is an important concept you must first understand though. Rather than actually moving the vertices, we will move the whole coordinate system. Think of it like this - when you are stopped beside another car at a traffic light and the other car starts to move forward, you get the impression that your car is moving backwards. This is the same relation. It's easier to describe your object centered around the origin and then move the coordinate system.

Types of Transformations

Translations

A translation is basically sliding the object. You specify an axis and it will slide along that axis for however many units you specify.

Rotations

A rotation is simply rotating the object. You specify an axis and it will rotate around that axis using the angle you specify.

Scaling

Scaling is simply stretching or shrinking the object. The dimensions of the object is either increased or decreased by the amount you specify.

Understanding Transformations

Transformations occur between the time that you specify vertices and when they appear squished onto the 2D screen.
An important thing to remember about translations is that they are cumulative.
transformations

Matrices

Transformations are all handled in Direct3D by matrices internally. Again, learning matrices is beyond the scope of this tutorial and not completely necessary to use Direct3D. But it does give you a better understand of what is happening inside Direct3D.

Rotation and Scaling

In Direct3D, rotation and scaling are both done in respect to the origin of the world, not of the object's position. So to combat this, we must translate the object to the world origin and perform the scaling and rotation manipulations. Then we translate it back to its old position.

The Identity Transformation

Since all transformations are cumulative, we can't expect to transform more than one object without the previous objects' transformations affecting the new object. To fix this, we need to reset the origin. You can do this by using the function d3d_transform_set_identity();.

Using Transformations

Let's build upon our cone solid object that was built in the last chapter.
...
colorChange = 0;
d3d_transform_set_identity();
d3d_transform_add_rotation_x(45);
d3d_transform_add_scaling(1.5,0,0.8);
d3d_primitive_begin(pr_trianglefan);
...
d3d_primitive_end(); //Last line
d3d_transform_set_identity();
The first transformation we set is the identity to reset the origin so that we can execute the transformations correctly. Next, the object is rotated 45 degrees around the x-axis with a call to d3d_transform_add_rotation_x(angle);. Functions that also exist for this purpose include d3d_transform_add_rotation_y(angle); and d3d_transform_add_rotation_z(angle);. You could also use d3d_transform_add_rotation_axis(xa,ya,za,angle);. xa, ya, and za form a vector identifying which axis to rotate it around. For example, if you wanted to rotate around the y-axis by 35 degrees, you would call d3d_transform_add_rotation_axis(0,1,0,35);.
The next transformation that was done was a scaling. We used the function d3d_transform_add_scaling(xs,ys,zs);. Again, xs, yz, and zs form a vector indicating how much to scale each axes' dimensions by. Values greater than 1 specify a stretch. Values less than 1 specify a shrink. For example, if we wanted to stretch the object on the x-axis by 150%, shrink the object on the y-axis by 85% and leave the object alone on the z-axis, we would call d3d_transform_add_scaling(1.5,0.8,1);.
The last transformation, called at the end of the script, resets the origin. We do this so as to not affect any other things that may be drawn apart from this object.

The Transformation Stack

It is sometimes convenient to save the current cumulative transformation state, execute a new transformation, and then restore the old transformation state for further transformations. For example, if you were building a robot. You just translated the torso and orientated it. You save the transformation state. You then translate and rotate one leg, restore the previous transformation state, and add the other leg. If you didn't do this, you would have had to translate and rotate back to the torso via extraneous transformations. This has greater overhead than simply using our transformation stack.
The transformation stack works just like the stack data structure in other areas of programming. You can clear the whole stack's contents by calling d3d_transform_stack_clear();. You can push(add to) the stack by calling d3d_transform_stack_push();. You can then pop(remove from) the stack with d3d_transform_stack_pop();.
We will see some examples later in the series that make efficient use of this powerful mechanism.
[Thanks to Yourself for notifying me of some errata]

<< Previous Chapter      Next Chapter >>

Comments (4)
 Del.icio.us  Digg  Furl  Google  Reddit  Slashdot


Blogtastic RSS FEED

Linktastic


TysonC's Profile Page