July 2005 - Posts

Unifying the sites (Tutorials added)

I have worked hard on unifying my sites and at the moment pieterg.com is pulling information from my blog. So I am a bit busy sorting out the layout of the content on it.
I have introduced my tutorials to my blog and added another that talks about "lights and materials" in DirectX. It's going well and I am getting good feedback from people about the tutorials. If you have any comments, suggestions please do not hesitate to contact me at (pieter at pieterg dot com).
This weekend I will start working on some more tutorials like alpha blending, additive blending and a simple terrain engine.
Posted by pieterg | with no comments

Tutorial 5 - Lights and Materials

[Download the source]

Long time no see, How has everyone been doing? Today we are going to look at a very interesting and exciting topic. But you are probably thinking hey, why does this screenshot look exactly like the previous tutorial's shot? It's cause today we are going to enable light and material and this screenshot has light in it.

Let's get into the theory. We are going to introduce 3 new components today. They are Normals, Lights and Materials. Let's see what the definition is for each one of them.
Normal
"A surface normal, or just normal to a flat surface is a three-dimensional vector which is perpendicular to that surface. A normal to a non-flat surface at a point p on the surface is a vector which is perpendicular to the tangent plane to that surface at p."



In this image above I have pointed out what normals are. Normals are unit vectors, A vector that has the length (or magnitude) of one unit eg: (0.0f, 1.0f, 0.0f). This is the normal point upwards for the object in the figure.

Light
"Form of radiant energy that acts upon the retina of the eye, optic nerve, etc., making sight possible. This energy is transmitted at a velocity of about 186,000 miles per second by wavelike or vibrational motion. 2. A form of radiant energy similar to this, but not acting on the normal retina, such as ultraviolet and infrared radiation. Interplay between light rays and the atmosphere cause us to see the sky as blue, and can result in such phenomena as glows, halos, arcs, flashes, and streamers."

There are three types of lights available in Direct3D: point lights, directional lights, and spotlights. We will be working with a directional light as it's simple to setup and for tutorial purposes keeps math out of the equation.

Material
"A material defines the color that is reflected off the surface of a geometric object when a light hits it."


This means that the material is like a costume that the object puts on. This material defines how the light will interact with it. Look at some examples in life. Chrome, Wood, Fur... all these materials handles light in a different way. Some absorb more light than others.

Now that we have some theory covered let's look at some code.

public Core()
{
     window = new Window(); //instantiate our window
     //we are going to use the same triangle as before but we going to extend it to a 4 vertex quad using      //CustomVertex.PositionNormalTextured that.
     CustomVertex.PositionNormalTextured[] triangle = new CustomVertex.PositionNormalTextured[4];
     //bottom left.
     triangle[0] = new CustomVertex.PositionNormalTextured(-1.0f, 0.0f, 0.0f, 0.0f, 0.0f,-1.0f, 0.0f, 1.0f);
     //top left
     triangle[1] = new CustomVertex.PositionNormalTextured(-1.0f, 2.0f, 0.0f, 0.0f, 0.0f,-1.0f, 0.0f, 0.0f);
     //bottom right
     triangle[2] = new CustomVertex.PositionNormalTextured( 1.0f, 0.0f, 0.0f, 0.0f, 0.0f,-1.0f, 1.0f, 1.0f);
     //top right
     triangle[3] = new CustomVertex.PositionNormalTextured( 1.0f, 2.0f, 0.0f, 0.0f, 0.0f,-1.0f, 1.0f, 0.0f);

     vb = new VertexBuffer(typeof(CustomVertex.PositionNormalTextured), 4, window.D3DDevice, Usage.WriteOnly,      CustomVertex.PositionNormalTextured.Format, Pool.Managed);
     vb.SetData(triangle, 0, LockFlags.None);

     texture = TextureLoader.FromFile(window.D3DDevice, "texture.jpg"); //load the texture from a file

     window.D3DDevice.RenderState.Lighting = true; //enable lighting
     window.D3DDevice.RenderState.CullMode = Cull.None; //Cull nothing (render everything)      window.D3DDevice.Lights[0].Type = LightType.Directional; //set the light type (Directional)
     window.D3DDevice.Lights[0].Direction = new Vector3(0.0f, 0.0f, 1.0f); //we point the light into the scene
     window.D3DDevice.Lights[0].Enabled = true; //enable this light
    
    
material = new Material(); //create a new material (very simple)
     material.Diffuse = Color.White; //set the diffuse color of the material to white.
     /*What is diffuse light?
     The essential color of an object. This is the color that the object reveals under pure white light. It is perceived as the color of      the object itself rather than a reflection of the light. You can set the diffuse color separately from the ambient and specular            colors. Diffuse color is distinguished from the color of specular reflection (highlights) off an object, which are generally the      color of the light source itself. See also Ambient and Specular.*/


We have created all of our resources. The only thing left is to set them and render the quad.

private void Render()
{
      window.BeginRender(Color.Black);
      //set the material (everything will be rendered with this material until it is set to null or another material
      window.D3DDevice.Material = material;
      //set the texture (everything will be rendered with this textureuntil it is set to null or another texture
      window.D3DDevice.SetTexture(0, texture);
      window.D3DDevice.Transform.World = matWorld;
      window.D3DDevice.SetStreamSource(0, vb, 0);
      window.D3DDevice.VertexFormat = CustomVertex.PositionNormalTextured.Format;
      window.D3DDevice.DrawPrimitives(PrimitiveType.TriangleStrip, 0, 2);
      window.FinishRender();
}

Posted by pieterg | with no comments
Filed under:

HLSL Tutorial - Normal mapping (Bump mapping technique)

Normal mapping.

What an interesting and exciting topic to talk about.
What we are going to be looking at is an implementation normal mapping which is basically a technique where we tell the light how to behave according to the map. The map is encoded with 3 channels, one each for red, green, and blue, where if we take a point on the map we can get the normal vector of that point. So how does that work? Well your red channel defines the X coordinates, 100% red being left. The green channel defines the Y direction and 100% green is up. The blue channel is your Z direction and 100% coming straight out of the surface.

Now that we know how the normal map is encoded we will look at how to create one. There is a spiffy tool from NVIDIA. it allows you to create normal maps from textures using photoshop.

If you don't want to go through the hassle. I placed a download link for the normal map and texture I used in my temple demo.

So what we are going to go through now is probably the hardest part to understand in the beginning and i'll try not to get lost myself. heh. Firstly we need to be able to map our normal map and texture to an object. We need a space to specify this so we are going to create one called a texture space. Why do we need a texture space? We need one so that we are able to transform the light into this space and tell it how to react according to the normal map.

We need 3 axis to define this new space. So we take what they call a BiTangent, Tangent and Normal. This will be our basis of this "texture" space. a BiTangent is a line that is tangent to a curve at two distinct points. a Tangent is a line that touches a curve or solid at a single point and a Normal to a flat surface is a 3-dimensional vector that is perpendicular to that surface.

So what we are going to do is go from world space to object space then to texture space using our TBN Matrix. Lights are generally defined in world space, not object space. you need to transform them from worldspace to object space, and then to texture space, since the TBN Matrix is defined in object spaceTo illustrate this better I will use an example or schematic.

So we basically plug the texture unto the object. The normal map unto that aswell. We decompress the normal map and then with N.L ( Normal * Light ) which is the light equation.

Let's look at the code

float4x4 ModelViewProj : WORLDVIEWPROJ; //our world view projection matrix
float4x4 ModelViewIT : WORLDVIEWIT; //our inverse transpose matrix
float4x4 ModelWorld : WORLD; //our world matrix
float4 lightPos; //our light position in object space

texture texture0; //our texture
texture texture1; //our normal map

sampler2D texSampler0 : TEXUNIT0 = sampler_state
{
     Texture = (texture0);
    MIPFILTER = LINEAR;
    MAGFILTER = LINEAR;
    MINFILTER = LINEAR;
};
sampler2D texSampler1 : TEXUNIT1 = sampler_state
{
    Texture = (texture1);
   MIPFILTER = LINEAR;
   MAGFILTER = LINEAR;
   MINFILTER = LINEAR;
};

//application to vertex structure
struct a2v
{
     float4 position : POSITION0;
     float3 normal : NORMAL;
     float2 tex0 : TEXCOORD0;
     float3 tangent : TANGENT;
     float3 binormal : BINORMAL;
};

//vertex to pixel shader structure
struct v2p
{
     float4 position : POSITION0;
     float2 tex0 : TEXCOORD0;
     float2 tex1 : TEXCOORD1;
     float3 lightVec : TEXCOORD2;
     float att : TEXCOORD3;
};

//pixel shader to screen
struct p2f
{
     float4 color : COLOR0;
};

//VERTEX SHADER
void vs( in a2v IN, out v2p OUT )
{
     //getting to position to object space
    OUT.position = mul(IN.position, ModelViewProj);

    //getting the position of the vertex in the world
    float4 posWorld = mul(IN.position, ModelWorld);

    //getting vertex -> light vector
    float3 light = normalize(lightPos - posWorld);

    //calculating the binormal and setting the Tangent Binormal and Normal matrix
    float3x3 TBNMatrix = float3x3(IN.tangent, IN.binormal , IN.normal);

    //setting the lightVector
    OUT.lightVec = mul(TBNMatrix, light);

    //calculate the attenuation
    OUT.att = 1/( 1 + ( 0.005 * distance(lightPos.xyz, posWorld) ) );
 
    OUT.tex0 = IN.tex0;
    OUT.tex1 = IN.tex0;
}

//PIXEL SHADER
void ps( in v2p IN, out p2f OUT )
{
    //calculate the color and the normal
    float4 color = tex2D(texSampler0, IN.tex0);

    /*this is how you uncompress a normal map*/
    float3 normal = 2.0f * tex2D(texSampler1, IN.tex1).rgb - 1.0f;

    //normalize the light
    float3 light = normalize(IN.lightVec);

    //set the output color
    float diffuse = saturate(dot(normal, light));

    //multiply the attenuation with the color
    OUT.color = IN.att * color * diffuse;
}

technique test
{
    pass p0
    {
        vertexshader = compile vs_1_1 vs();
        pixelshader = compile ps_2_0 ps();
    }
}

that's it. Easy huh? If you have any queries/comments/suggestions please do not hestitate to contact me.

Posted by pieterg | 20 comment(s)
Filed under:

More about me



I was born in Johannesburg, South Africa. My parents introduced us to computers at a really young age. I must say that I can remember playing on it since I was a very young boy. Probably about 2 - 3 years of age. I have always wanted to know what goes on inside a computer and how programs are made and run. I played a little with Basic's Gorilla modifying the gravity levels etc...

At the age of 6 or 7 we moved to Pretoria where I went to Constantia Park Primary. I remember feeling bad that I left my friends behind and wanted to keep in contact. Then one day I was sitting with my brother on the side-walk waiting for my mom or dad to come pick us up and seeing a girl that was in my school back in Johannesburg. It felt quite nice seeing someone I knew. I remember speaking to her once or twice. Life was very funny back then. I got caught for all the wrong reasons. I left my lunch inside the classroom once and wanted to go fetch it. I saw that the door was locked and decided the climb through the window. To my surprise my teacher was in the class with the principal and immediately noticed me. You can imagine what happened next. I felt so bad that my father had to come to school only to find out from the teacher and the principal that I had been left behind with my math's homework and the story goes on but I was in grade 5 and didn't think too much back then...

I finally made it to grade 8 and was in Garsfontein Highschool. A really nice place to be. I really felt at home there. I recall this one moment very clearly. We had this play that we were supposed to perform infront of alot of people and my teacher said. "You don't have a part, you better come up with something". So I did. I grabbed a pair of gumboots and a father christmas outfit. In the middle of the play I would run out and shout : "HO HO HO, oops, wrong scene". Now that was funny. There was also this matric girl that came and kissed me and said : "That was funny, well done" and I never saw her face since I have my father christmas mask on. (If you are reading this and kissed a boy around 10 years ago with a father christmas mask on. please contact me.)

So I went through highschool making alot of good friends until the middle of grade 8 when we had to move to Richardsbay.
Time flew so fast, I cannot really remember lots of the grades I did there until about grade 10 when I met a wonderful girl. We went out for 1 year and a couple of months and in that time I really saw the time flying. When we broke up I was in grade 11 and really wondered what I was going to do. All I knew was spending time with her.

So moving on... grade 12 was very very funny and I really enjoyed the time. I had 2 great friends, Ivon and Danie. These okes were a laugh from start to finish. We pulled all kinds of pranks and really had a fun time all around. After matric(Grade 12) I started working at a company as a draughtsman. I really enjoyed it for a bit and 2 months after I started there I moved to another company that offered me a higher salary. So it went on until I got to 2002 when I moved to Durban and started studying (Mechanical Engineering). I started programming again. From there on it was one way and that's the 101101 way.

I soon started studying Information Technology(Development Software). From that time I have became friends with a very good bunch of friends.Tony Whitaker, Graham Wihlidal. Thank you guys and to the others from #graphicsdev. These guys really inspired me to be where I want to be one day and that's to work for a game development company.

For now I am signing off. I might add to this when I'm bored again. Lots of nice little things that I missed out.
Posted by pieterg | 3 comment(s)
Filed under:

Tutorial 4 - Texturing a quad

[Download the source]

Hi there again everyone. How did you enjoy those spinning triangles?

Today we are going to be looking at how to texture a quad (2 triangles form a quad). We are going to build the quad in the order given in the image below.
Texturing quads is a really easy method. It involves placing what they call UV coordinates (Texture coordinates). UV coordinates (Texure coordinates) are used to tell direct3d how to map the texture points to the object. Look at the image below. It shows the UV coordinates for a face on a cube.

Let's move on. We are going to be using the CustomVertex.PositionTextured vertex format and create and texture our quad. The most important part of this exercise is the use of the Texture class. For a better understanding. Let's take an extract out of the SDK Docs.

"Early computer-generated 3-D images, although generally advanced for their time, tended to have a shiny plastic look. They lacked the types of markings—such as scuffs, cracks, fingerprints, and smudges—that give 3-D objects realistic visual complexity. In recent years, textures have gained popularity among developers as a tool for enhancing the realism of computer-generated 3-D images.

In its everyday use, the word texture refers to an object's smoothness or roughness. In computer graphics, however, a texture is a bitmap of pixel colors that give an object the appearance of texture.

Because Microsoft Direct3D textures are bitmaps, any bitmap can be applied to a Direct3D primitive. For instance, applications can create and manipulate objects that appear to have a wood grain pattern in them. Grass, dirt, and rocks can be applied to a set of 3-D primitives that form a hill. The result is a realistic-looking hillside. Textures also can be used to create effects such as signs along a road, rock strata in a cliff, or the appearance of marble on a floor.

In addition, Direct3D supports more advanced texturing techniques such as texture blending—with or without transparency—and light mapping.

If an application creates a hardware abstraction layer (HAL) device or a software device, it can use 8, 16, 24, 32, 64, or 128-bit textures."

Armed with some more knowledge on Textures. We are going to create a texture from file. Direct3D is one step ahead of us. It provides us with a TextureLoader class. The class has a method that creates a texture from file and is called FromFile(). The First parameter it takes is the Device and the second is a string that contains the path to the file. Let's look at the code.

public void createQuad()
{
     texture = TextureLoader.FromFile(direct3d.XilathDevice, "crate.jpg"); //Load the image from the file

     CustomVertex.PositionTextured[] quad = new CustomVertex.PositionTextured[4];
     quad[0] = new CustomVertex.PositionTextured(-1.0f, 0.0f, 0.0f, 0.0f, 1.0f);
     quad[1] = new CustomVertex.PositionTextured(-1.0f, 2.0f, 0.0f, 0.0f, 0.0f);
     quad[2] = new CustomVertex.PositionTextured( 1.0f, 0.0f, 0.0f, 1.0f, 1.0f);
     quad[3] = new CustomVertex.PositionTextured( 1.0f, 2.0f, 0.0f, 1.0f, 0.0f);

     vb = new VertexBuffer(typeof(CustomVertex.PositionTextured), 4, direct3d.XilathDevice, Usage.WriteOnly,      CustomVertex.PositionTextured.Format, Pool.Managed);
     GraphicsStream stm = vb.Lock(0, 0, 0);
           stm.Write(quad);
     vb.Unlock();
     worldMatrix.Translate(0.0f, -1.0f, 0.0f);
}
private Texture texture;


Now that we have loaded the texture and stored the quad into the Vertex Buffer. Let's render the quad.
Note: When we set the texture we are telling direct3d that any object rendered after that call should be rendered with that texture. So keep this in mind. If you want to set the texture to nothing just do SetTexture(0, 0);


public void Render()
{
     direct3d.BeginRender(Color.Black); //render our scene with the background as black

     direct3d.XilathDevice.Transform.World = worldMatrix;
     direct3d.XilathDevice.SetTexture(0, texture); //Here we tell direct3d that anything after this method should be rendered with this      texture
     direct3d.XilathDevice.SetStreamSource(0, vb, 0);
     direct3d.XilathDevice.VertexFormat = CustomVertex.PositionTextured.Format;
     direct3d.XilathDevice.DrawPrimitives(PrimitiveType.TriangleStrip, 0, 2);

     direct3d.FinishRender(); //finish rendering our scene
}

Posted by pieterg | 5 comment(s)
Filed under:

Tutorial 3 - Spinning a triangle

[Download the source]

Welcome back.
I hope you had some fun drawing/rendering some triangles. Well hopefully after today you will know a little more about moving things around. Yep, that's it. Moving/Rotating. In the Graphic development world we have a 2 dimensional array known as matrices that will help us in Translating (The term for moving things)/Rotating objects around.
So what do we need to know?
Well let's start off with an explanation of what really happens when you create an object. This object is known to be in a space. Space? What’s a space? A Space is simply the area where you define this object. Maybe with a example I can explain this a bit better. Also an understanding of coordinate systems. Left/Right handed coordinate systems. If you want a good reference. The DX SDK Docs has a nice explenation of what they are.

Let me explain what is going on in that figure. When we define the object’s dimensions. We are defining it in object space. This means that these coordinates/dimensions we give the object is relative to the object. Then through a World Transform which I will explain in a second we place it in the world. The figure shows that very clearly.
So that’s cool. So let’s move on. What else do we need? A View space offcourse. We need to be able to see this object in the world. So then we also need to be able to define a pertrution/perspective. What is this? This is basically how to tell direct3d that the further away objects are the smaller they are and also gives them depth like the box that you see in fig1.0 is defined with orthogonal projection. Example in fig 1.1


Is that it you ask? Yep that’s it. Let’s look at some code shall we?
Three matrices. One for our world, one for projection and finally one for our view(eye). We also then create 3 vectors. What is a vector you ask? It is a quantity that has both magnitude and direction. We need to tell direct3d where the eye(camera) is in this case we push the camera -1.0f closer to us., where to look at and finally. What is up? We will specify Y as being up in our world.
private Matrix worldMatrix = new Matrix();
private Matrix projMatrix = new Matrix();
private Matrix viewMatrix = new Matrix();
private Vector3 eye = new Vector3(0.0f, 0.0f, -1.0f);
private Vector3 lookAt = new Vector3(0.0f, 0.0f, 0.0f);
private Vector3 up = new Vector3(0.0f, 1.0f, 0.0f);

Let's see what we do here. First off is the view matrix. We build a Left handed view matrix with the values that we specified. Next is the petrusion/projection matrix. We build the projection matrix with the left handed coordinate system. The field of view (What is our angle of view.) Normally it's PI/4. Secondly it's the aspect ratio which we define as one. It's 1 for a square. It's the width divided by the height. So with a rectangular monitor with a resolution of 800/600 it would be 1.3. Third is the near clipping plane. Anything small than the near clipping plane will not get rendered and lastly is the far clipping plane which will do the same for object further than that value.
Then we just set the matrices.
viewMatrix = Matrix.LookAtLH(eye, lookAt, up); //Set the view matrix to be a left handed coordinate system.
direct3d.XilathDevice.Transform.View = viewMatrix; //set the view matrix
projMatrix = Matrix.PerspectiveFovLH( (float)Math.PI/4, 1.0f, 1.0f, 1000.0f ); //build the projection matrix
direct3d.XilathDevice.Transform.Projection = projMatrix; //set the projection matrix
You are probably asking/thinking where on earth that world matrix is hiding. Well I saved the best for last. Let's rotate this triangle.
angle += 0.01f; //increase the angle each frame. This can be any variable
worldMatrix.RotateZ(angle); //rotate the world matrix with this angle
direct3d.XilathDevice.Transform.World = worldMatrix; //set the world matrix. Basically telling direct3d how this object is behaving in the world
That's it. Really simple isn't it? What do you want next? Do not hesitate to contact me. I am happy to hear your views. If you have any problems/comments/critism about the code or anything concept related. Do not hesitate. Till next time. Happy spinning.
Posted by pieterg | with no comments
Filed under:

Tutorial 2 - Rendering a triangle

[Download the source]

Here we are again. Ready for another tutorial? That's good. Let's get started then.
Today we are going to discuss quite a few things. This will be a very huge step so buckle up.

Firstly. Let us assume that you know a little about 3d coordinate spaces. If not, the DirectX API documentation has a nice section on them.
I really thought about this and decided to start from the very beginning. an Atom (Vertex). This is your building block very much like it's the building block for anything in the world we live in. We are really just simulating the world aren't we?
a Vertex is a point. a Vertex has an x, y and z coordinate, other than that it can also have color and a normal vector (do not worry about this too much now). a Vector is a quantity that has magnitude and direction. Now that we know what a point is how do we use them? We aren't really going to be drawing points on the screen, cause that's just plain boring so what we are going to do is draw a triangle. a Triangle is defined by 3 points.

In fig1.0 you will see that each point has a vertex. You are probably thinking but what about the lines? Direct3d helps us in that sense as it has a few ways of connecting the vertices. For the purpose of the exercise we are going to be using a TriangleStrip. a TriangleStrip takes the first 3 vertices and connects them. The vertices will be specified in a clockwise-winding. Consider fig1.1.

 

 

 

 

 


Fig1.1 shows the points that we will be specifying for Direct3d. The easiest way to accomplish this would be to use an array wouldn't it? But we also need to tell Direct3d what information is stored. This is where the Flexible Vertex Format comes in. It's a structure that tells Direct3d what order we stored the data in. Managed Direct3d really makes it easy. So let's dive in.

 

 

 

 

 



We will first create a method called createTriangle where we will be creating the vertices and storing them in an array and after that into a buffer where Direct3d will read and render them from.
Firstly we create an array of CustomVertex.PositionColored which is a predefined class and tells Direct3d that our array data will be holding values in the following order, (x, y, z) and a color. Next we use the constructor of this class to create a vertex at each point using the points in fig 1.0. Following that we have something called a vertex buffer. a Vertex Buffer is exactly what it says it is. It's a buffer that holds vertices. Direct3d can read and write to this buffer depending on what we want to do. Let's look at how we create this buffer.
public VertexBuffer(Type, int, Device, Usage, VertexFormats, Pool);
The first parameter to the constructor is a Type the vertex buffer will be holding.
The second parameter is an integer and will be the number of vertices the buffer will hold.
Third is our Direct3d device.
Fourth is a Usage flag. This will specify how we will be using the buffer. We are just going to write to it. We specify Usage.WriteOnly.
Fifth is our Vertex Format.
Sixth describes how the vertex buffer should be handled in memory. We ask Direct3d to manage it for us.
Let's move on. The GraphicsStream object that we created is a way of accessing the buffer's memory. We need to be able to write to the memory of this buffer to get those triangle points in there. So when we call the Lock() method it returns the vertex buffer memory. We then write the array to the stream and then Unlock() the vertex buffer.

private VertexBuffer vb;
public void createTriangle()
{
      CustomVertex.PositionColored[] triangle = new CustomVertex.PositionColored[3]; //create an array of 3 vertices
      //using the CustomVertex.PositionColored constructor to set each vertex
      triangle[0] = new CustomVertex.PositionColored(-0.1f, 0.0f, 1.0f, Color.Blue.ToArgb());
      triangle[1] = new CustomVertex.PositionColored(-0.1f, 0.2f, 1.0f, Color.Red.ToArgb());
      triangle[2] = new CustomVertex.PositionColored(0.1f, 0.0f, 1.0f, Color.Green.ToArgb());
      vb = new VertexBuffer(typeof(CustomVertex.PositionColored), 3, direct3d.XilathDevice, Usage.WriteOnly, CustomVertex.PositionColored.Format, Pool.Managed);
      GraphicsStream stm; //our GraphicsStream object that we will use to access the
      //lock the VB. Locks a range of vertex data and obtains the vertex buffer memory and stores it in the GraphicsStream object (stm)
      stm = vb.Lock(0, 0, LockFlags.None);
      stm.Write(triangle); //write the triangle array to the GraphicsStream Object
      vb.Unlock(); //unlock the VertexBuffer, we are finished writing the data to it.
}

Let's render our triangle.
SetStreamSource() basically sets the vertex buffer.
The first parameter is the number of streams we will be using.
The second parameter is the Vertex Buffer object.
Third is the offset from the beginning of the buffer to the beginning of the vertex data (bytes).
VertexFormat describes to the device what vertex format we will be drawing.
DrawPrimitives() takes 3 parameters.
First is the primitive type. Ours is PrimitiveType.TriangleStrip.
Second is the index of the first vertex to load.
Third is the number of primitives to render.

public void Render()
{
      direct3d.BeginRender(Color.Black); //render our scene with the background as black
      direct3d.XilathDevice.SetStreamSource(0, vb, 0);
      direct3d.XilathDevice.VertexFormat = CustomVertex.PositionColored.Format;
      direct3d.XilathDevice.DrawPrimitives(PrimitiveType.TriangleStrip, 0, 1);
      direct3d.FinishRender(); //finish rendering our scene
}
Posted by pieterg | 21 comment(s)
Filed under:

Tutorial 1 - Initializing DirectX

[Download the source]

This tutorial will be the base for every other tutorial.
Creating a window and initializing direct3d is the most important task to get you going.

The reason we have bundled the 2 are because it's less than 30 lines of real code and so that we can head over to actually drawing something on the screen. (And that's where we want to be isn't it?).

First we need to tell c# what classes we will be using.
using System; //Contains fundamental classes and base classes
using System.Drawing; //Provides access to GDI+ basic graphics functionality
using System.Windows.Forms; //Contains classes for creating Windows-based applications
using Microsoft.DirectX; //The DirectX class
using Microsoft.DirectX.Direct3D; //The Direct3D class

Now that we have the class included in our project let's continue. Let's define a class that inherits from the Form class. This will give us access to alot of predefined functions and properties to make our life a little easier.
//Direct3d class that inherits it's base from System.Windows.Forms.Form
public class Direct3d : Form
{
//Default constructor that will initialize the window with default values
      public Direct3d()
      {
         Width = 800; //Window Width
         Height = 600; //Window Height
         Text = "Xilath - Basic Window"; //Window Caption
      }
Width and Height are members that we inherited from the Form class. The nice thing about this is that we don't have to redefine every member or function of the Form class. If we don't specify it, it gets initialized to a default value. So we only redefine those members and methods that we want to change.

Initializing direct3d involves telling direct3d what type of window we will be using. Will this window be windowed or fullscreen. What kind of swap chain we will use (for now don't worry too much about it. If you are a very inquisitive man. Read it up in the SDK docs)
So we declare a function a function named InitGraphics() which is well suited for what we want to do. We also create a device. With a device we draw stuff on the screen. You can think of the device as a pen.
      //Initializing the Graphics device
      public bool InitGraphics()
      {
         try //try creating the device if success return true
         {
            PresentParameters presentParams = new PresentParameters(); //our presentation parameters
            presentParams.Windowed = true; //is the application windowed or fullscreen
            presentParams.SwapEffect = SwapEffect.Discard; //our swap chain effect. Don't worry about this now.
            device = new Device(0, DeviceType.Hardware, this, CreateFlags.HardwareVertexProcessing, presentParams); //let's create the device with the parameters we specified
            return true; //return true (we succeeded)
        }
        catch(DirectXException) //if fail. catch the exception and return false
        {
            return false; //we failed
        }
     }
Now that we have coded the base for initializing the device let's get on to telling direct3d where we will be drawing to and what color we want the back buffer to be. In any kind of graphics API, we draw/render to a back buffer. This buffer works exactly like it's named. It's a buffer the same width and the height as the current window that we will be drawing to. So the structure that we have for every frame is basically
1) Clear the back buffer
2) Begin rendering to the buffer
3) End rendering to the buffer
4) Present what we have drawn to the back buffer to the screen

       public void Clear(System.Drawing.Color color) //Clear the back buffer to a specific color.
       {
           device.Clear(ClearFlags.Target, color, 1.0f, 0);
       }
       public void BeginScene()
       {
           device.BeginScene(); //Begin rendering to the back buffer
       }
       public void EndScene()
       {
           device.EndScene(); //End rendering to the back buffer
       }
       public void Present()
       {
           device.Present(); //Present whatever is in the back buffer to the window
       }
       private Device device = null; //rendering device
This will conclude our base class for initializing a window and a device. Now all that is left is the implementation.

using System; //Contains fundamental classes and base classes
using System.Drawing; //Provides access to GDI+ basic graphics functionality
using System.Windows.Forms; //Contains classes for creating Windows-based applications
using Microsoft.DirectX; //The DirectX class
using Microsoft.DirectX.Direct3D; //The Direct3D class

//Our testing class named after my engine
public class Xilath
      {
      //our default constructor used to initialize the device.
      public Xilath()
      {
         direct3d = new Direct3d(); //instantiate the Direct3d object
         if(!direct3d.InitGraphics()) //if we cannot initialize the device then
         MessageBox.Show("Device could not be created. Program quiting.."); //show an appropriate          message
      }
     
      //our Render function. This is where all the fun will happen
      public void Render()
      {
        direct3d.Clear(Color.Black); //our back buffer clear function
        direct3d.BeginScene(); //Begin drawing to the back buffer
        direct3d.EndScene(); //End drawing to the back buffer
        direct3d.Present(); //Present whatever is in the back buffer
      }

      //main program entry point
      public static void Main()
      {
          Xilath xilath = new Xilath(); //instantiate our Xilath class
          xilath.direct3d.Show(); //show the window
          while(xilath.direct3d.Created) //while the window is created and valid
          {
              xilath.Render(); //call our render method
              Application.DoEvents(); //process the window's messages
         }
     }
     private Direct3d direct3d = null; //our Direct3d helper class
}

Posted by pieterg | with no comments
Filed under:

What tutorials do you want?

I was coding last night (big surprise) and thought that I would like to ask the community what tutorials they want to see from a game/graphics development (DirectX) perspective? It can be anything from rendering water to loading a mesh. For simplicity I shall do these tutorials in c++ or C#, depending on the request and the topic at hand.
Other than that. Technikon started yesterday and already we've been notified of a test. Isn't this just insane. I have coding to do. I can't bother with some tests. (Hahaha, just kidding).
Off to technikon I go.
Posted by pieterg | 4 comment(s)

Lunar Lander - (With Sounds)

I started working on this little game last night and all I can say is that it's working. I don't plan on doing anymore work on it but I learnt alot from developing a small game.
Features:
Sounds
Nice Graphics
Controls :
Up = "w"
Down = "s"
Instructions:
Land the spaceship safely between velocities of 100 and -100

The Lunar Lander Source
[Download]
Posted by pieterg | 5 comment(s)
Filed under:

Holidays are over and Technikon starts next week.

So the holidays come to an end. I have done a lot but not necessarily coding wise but helping friends here and there and building friendships. Interesting how you plan to do something during the holidays and it always gets messed up but in the long run it being more beneficial to have made those friends. I am starting my Lunar Lander project. I little spaceship that you need to land on different planets where the gravity changes. The spaceship needs a soft landing otherwise *boom*. It’s a nifty little project for some physics testing and just to get started again.
Posted by pieterg | with no comments