Featured Posts

8. Bump Mapping in GLSL8. Bump Mapping in GLSL Introduction Bump mapping is essential in todays computer games, and computer graphics in general. Would you like to know the best thing about it? It is extremely simple to implement. Bump mapping works...

Read more

Swiftless GLSL Shader DeveloperSwiftless GLSL Shader Developer Swiftless GLSL Shader Developer   Version 0.1a Currently Swiftless GLSL Shader Developer is in it's first public release, and is currently in alpha status, meaning it is not complete and may contain...

Read more

Wordpress Optimization Wordpress Website Optimizations Introduction Wordpress itself is a fairly wonderful tool. Since switching to it, I find it is a lot quicker to make changes to my website and it is also quicker to get...

Read more

36. OpenGL Framebuffers36. OpenGL Framebuffers Introduction Frame buffers are one of those mythical things that we have all heard of, but many beginner OpenGL developers avoid because there is not much information about them, and they can be confusing...

Read more

1. Terrain Class1. Terrain Class Terrain is one of those things that so far, hasn't been perfectly recreated in computer graphics. But it is almost there! Looking over a beautiful landscape can be one of the most amazing feelings in the...

Read more

  • Prev
  • Next

Swiftless GLSL Shader Developer

Posted on : 15-06-2010 | By : Swiftless | In : Software

Tags: , , , , , , , , ,

3

Swiftless GLSL Shader Developer   Swiftless Shader Developer GUI

Version 0.1a

Currently Swiftless GLSL Shader Developer is in it’s first public release, and is currently in alpha status, meaning it is not complete and may contain errors. By downloading this software, you are taking full responsibility for any harm it may cause to your computer.

I have included an example project with the application, which shows how to use the geometry shaders, post processing and performs a simple blur effect. I will have more projects to put up as I progress with the application, you can also email me any projects you would like to share and I will put them up on this page, and may even put them in with a release of the application.

If you find any errors or have any suggestions for this software, please email me at swiftless@gmail.com

Download (Includes example project)
File size: 106kb
Platforms: Windows (All), Linux, OSX
Requirements: JOGL

Features:

* Support for OpenGL 2.1 (As supported by JOGL)
* Fragment Shader, Vertex Shader and Geometry Shader abilities
* Post processing capabilities Access to first render as either texture or depth texture
* Uses framebuffers for speed
* Syntax highlighting
* Project support
* Real-time shader compilation
* Real-time error reporting and shader validation
* Support for all 8 lights in the basic OpenGL pipeline
* Multiple texture support

Future Features:

* Multiple rendering passes
* Backcolor settings

Known Bugs:

* Appears to run slow after several minutes
* Custom uniform variables are not yet accessible
* Cube shape doesn’t appear
* Sphere doesn’t render correctly

Screenshots:

Swiftless GLSL Shader Developer User Interface

Swiftless GLSL Shader Developer User Interface

Swiftless GLSL Shader Developer Error Reporting

Swiftless GLSL Shader Developer Error Reporting

Swiftless GLSL Shader Developer Projects

Swiftless GLSL Shader Developer Projects

Swiftless GLSL Shader Developer Features

Swiftless GLSL Shader Developer Features

VN:F [1.9.3_1094]
Please rate so I know where to improve the site. 1 means needs a lot of improvement, 10 means perfect. If you leave a low rating, please state why. I don't want people just coming to bash the site.
Rating: 10.0/10 (3 votes cast)
VN:F [1.9.3_1094]
Rating: 0 (from 0 votes)

6. Terrain Vertex Buffer Objects

Posted on : 25-03-2010 | By : Swiftless | In : OpenGL, Terrain

Tags: , , , , , , ,

0

Jump To:

heightfield.h Source
heightfield.cpp Source

main.cpp Source
Download

Heightfield.H File:

VBO’s. Well well, this means a total change to our Render function, a new Init function and a few new classes and a few new variables. This is going to be a major change to our code, but in this case, with change comes progress, and wouldn’t you love to go from the current 5 frames per second, to say, 30 or 60? I know I would :-) So lets get to it.

First off, we are going to create a couple of extra classes. The first we are going to call Vert and will hold all our vertices for our terrain, and the second is going to be called TexCoord and guess what?! It will hold all of our texture coordinates for our terrain :-) Lets take a look at the code we need to add:

First our Vert class, which needs to hold the x, y and z coordinates for our terrain vertices:
// class Vert{
// public:
// float x;
// float y;

// float z;
// };

And second we have our TexCoord class which holds the u and v texture coordinates for our terrain:
// class TexCoord{
// public:
// float u;

// float v;
// };

Now I don’t know about you, but basic C++ knowledge explains the above simply enough. I’m going to assume you have at least some idea of what classes are. So lets go take a look at the changes to our SwiftHeightField class, starting off with our new variables. All our variables are going to be private to only our class functions, and will all be used for the creation and use of our Vertex Buffer Objects. So first off we have vhVertexCount. This will hold how many vertices our terrain has and is calculated by the width * height of our heightfield.raw file. Next up is vhVertices, which attached to our new Vert class will hold all our vertices, and finally we have vhTexCoords which used with our TexCoord class will hold all of the texture coordinates we are going to need:

// int vhVertexCount;
// Vert *vhVertices;
// TexCoord *vhTexCoords;

Now lets look at the last two variables we are going to need to add to our heightfield.h file:

// unsigned int vhVBOVertices;
// unsigned int vhVBOTexCoords;

These are going to be the buffers used for the creation of our Vertex Buffer Object. Please see the ‘Vertex Buffer Object’ tutorial (coming soon) for a possibly more indepth tutorial on how these work. As for now, lets look at the new function we are going to add. This is going to be called Init and guess what?! It is going to Initialize our Vertex Buffer Object for us :-)

// bool Init(void);

This will be in the private section of our class and will return true if our program is able to create our Vertex Buffer Object :-)

1.
2.
3.
4.
5.
6.
7.

8.
9.
10.
11.
12.
13.
14.
15.
16.

17.
18.
19.
20.
21.
22.
23.
24.
25.

26.
27.
28.
29.
30.
31.
32.
33.
34.

35.
36.
37.
38.
39.

  #include <windows.h>

class Vert{
    

public:
    
float x;
    
float y;
    
float z;
};

class TexCoord{
    
public:
    
float u;
    
float v;

};

class SwiftHeightField {
    
private:
    
int hmHeight;
    
int hmWidth;
    

    
int vhVertexCount;
    
Vert *vhVertices;
    
TexCoord *vhTexCoords;
    

    
unsigned int vhVBOVertices;
    

unsigned int vhVBOTexCoords;
    

    
unsigned int tID[2];
    

    
bool Init(void);
    

    
public:
    
bool Create(char *hFileName, const int hWidth, const int hHeight);
    

    
void Render(void);
    

    
BYTE hHeightField[1024][1024];

};

Heightfield.CPP File:

Who’s ready for a major code overhaul?! I know I am :-) So without further ado:

Starting off, we are going to add a couple of new header files, these are the glew.h and glext.h files, used for the incorporation of OpenGL extensions within our program. They just let us call the extensions without us having to link them to OpenGL manually. So we have the new lines:

// #include <GL/glew.h>
// #include <GL/glext.h>

Simple enough so far? Good, now lets look at our new Init function. The following code is the outline of our function. Pretty bland isn’t it?

// bool SwiftHeightField::Init(void){

// return true;
// }

Now lets look at generating a Vertex Buffer Object for our vertices :-) First off, we need to call glGenBuffersARB to tell OpenGL that we want to generate a buffer for our Vertex Buffer Object:

// glGenBuffersARB(1, &vhVBOVertices);

Then we need to bind that buffer as an array for OpenGL to fill with data:

// glBindBufferARB(GL_ARRAY_BUFFER_ARB, vhVBOVertices);

And finally we need to fill the Vertex Buffer Object with our vertex information that is loaded in our Create function:

// glBufferDataARB(GL_ARRAY_BUFFER_ARB, vhVertexCount * 3 * sizeof(float), vhVertices, GL_STATIC_DRAW_ARB);

The last line here is telling OpenGL to fill our current open buffer vhVBOVertices, with our vertices vhVertices, the size of our vertex count vhVertexCount, multiplied by 3 (for our x, y and z coordinates), then multiplied by the size of a float variable. We set our Vertex Buffer Object to GL_STATIC_DRAW_ARB, because we don’t plan on updating/changing the vertices inside our Vertex Buffer Object as a terrain is generally static (unless you want to get into destructible terrain).

After we have generated, bound and filled our buffer, we are going to want to just clean up after ourselves and delete all the information in vhVertices, and set it to nothing to save system resources:

// delete [] vhVertices;
// vhVertices = NULL;

Did you get all that? If not, you can email me, but for now lets continue the tutorial :-) After you have done this for your vertices, you are going to want to do the same for our texture coordinates. This is done the exact same way, just changing which variables we are using for what:

// glGenBuffersARB(1, &vhVBOTexCoords);
// glBindBufferARB(GL_ARRAY_BUFFER_ARB, vhVBOTexCoords);
// glBufferDataARB(GL_ARRAY_BUFFER_ARB, vhVertexCount * 2 * sizeof(float), vhTexCoords, GL_STATIC_DRAW_ARB);

Just make sure here, that you change the 3 from the previous code, to a 2. This is because last time with our vertices, we were working with x, y and z floats for our coordinates, now we are only working with u and v floats for our texture coordinates. Vertices have an extra third dimension to work with, while textures only work in two dimensions. And also remember to clean up after with this as well:

// delete [] vhTexCoords;

// vhTexCoords = NULL;

Now let us move onto our Create function. This is where the next major change occurs. Not in the loading of the terrain, but the loading of the terrain data into our vhVertices and vhTexCoords variables for use in our Init function.

The first one we are going to look at is the preperation of our vhVertices and vhTexCoords variables. First off we are going to declare just how many vertices our Vertex Buffer Object will be using. This is done by multiplying the height by the width by 6 of the terrain. We need to multiply by 6 because we are using triangles, are two triangles make up a ‘patch’ or polygon and there are 3 vertices in each triangle. The extra code division of (1 * 1) will be used later on when I add some REALLY basic Level Of Detail optimization to just lower how many polygons are drawn. At this stage, we are drawing every polygon at once, so we divide it by (1 * 1) = 1 to get our initial number of vertices. Next up we set our vhVertices variable to an array the size of the number of vertices that we have. And we do the same for our texture coordinates.

// vhVertexCount = (int)(hmHeight * hHeight * 6) / (1 * 1);
// vhVertices = new Vert[vhVertexCount];
// vhTexCoords = new TexCoord[vhVertexCount];

After this, we have a few temporary variables, these are nIndex, flX and flZ. These are going to hold which vertex we are up to and which vertex we are working on.

// int nIndex = 0;
// float flX;
// float flZ;

Now we are going to enter a couple of loops that will go through our terrain from left to right, and front to back (entirely open to interpretation).

// for (int hMapX = 0; hMapX < hmWidth; hMapX++){

// for (int hMapZ = 0; hMapZ < hmHeight; hMapZ++){

Inside our loops we are going to add another third loop, which will go through each vertex of the current triangle we are up to.

// for (int nTri = 0; nTri < 6; nTri++){

Now while we are looping through everything, here is where we calculate everything we need. First off we are going to temporarily work out which X and Z coordinate we are up to for our vertex. The following two lines of code read (in pseudocode):

if nTri = 1 or 2 or 5{
hMapX = hMapX + 1;
}
else
{
hMapX = hMapX;

}

And the same goes for the Z value we are currently up to, only now using triangles 2, 4 and 5.

// flX = (float)hMapX + ((nTri == 1 || nTri == 2 || nTri == 5) ? 1 : 0);
// flZ = (float)hMapZ + ((nTri == 2 || nTri == 4 || nTri == 5) ? 1 : 0);

These next three lines, are simply setting the x, y and z values of our current vertex in vhVertices to what it would be if we were just plain out using our render code from the previous tutorials, only difference is I have condensed it with the above lines.

// vhVertices[nIndex].x = flX;

// vhVertices[nIndex].y = hHeightField[(int)flX][(int)flZ];
// vhVertices[nIndex].z = flZ;

The next two lines are devoted to setting the texture coordines for our current VhTexCoords just as we did on the fly in our previous tutorials.

// vhTexCoords[nIndex].u = flX / 1024;
// vhTexCoords[nIndex].v = flZ / 1024;

And the final line of nIndex++ just increments which vertex we are actually up to.

// nIndex++;
// }
// }
// }

Now while we are still in our Create function, we need to call our Init function now that we have everything read in and ready to transfer to our Vertex Buffer Objects. To do this, I just call the line:

// Init();

At some stage after all of the above code :-) Now let us move onwards to our Render function!

Now to start off, we are going to just delete EVERYTHING from inside our Render function and start from scratch :-) Hehe. Sounds like alot of fun now don’t it? Of course it is! We LOVE rewriting functions don’t we?! :-D Anyways…. Now that you are prepared, it’s actually not that tricky. Because we are working with Vertex Buffer Objects, we also start working with Client States. These work in exactly the same way (syntax wise) as glEnable and glDisable. Only now we have glEnableClientState and glDisableClientState. So first off we are going to enable our texture coordinate array client state, enable texturing and then bind our texture like so:

// glEnableClientState(GL_TEXTURE_COORD_ARRAY);
// glEnable(GL_TEXTURE_2D);
// glBindTexture(GL_TEXTURE_2D, tID[0]);

Next off, we need to bind which vertex buffer object goes with this texture coordinate client state. This is our vhVBOTexCoords vertex buffer object that we created in our Init function. After we have bound which buffer object we are going to use, we need to call glTexCoordPointer to tell OpenGL that this is a texture coordinate pointer.

// glBindBufferARB(GL_ARRAY_BUFFER_ARB, vhVBOTexCoords);
// glTexCoordPointer(2, GL_FLOAT, 0, (char *) NULL);

The next three lines are similar, only this time we are working with our vertex buffer, and not our texture coordinate buffer. So we first need to enable the client state we are going to be using:

// glEnableClientState(GL_VERTEX_ARRAY);

Then we have to bind our buffer vhVBOVertices and call glVertexPointer. Now that we have everything set up, it is time to draw our Vertex Buffer Object.

// glBindBufferARB(GL_ARRAY_BUFFER_ARB, vhVBOVertices);
// glVertexPointer(3, GL_FLOAT, 0, (char *) NULL);

We do this with the following line. Yes, it is only one line of code to actually draw it, everything else is setting up to draw it :-) We are drawing our vertex arrays as a set of triangles, starting at position 0 in our Vertex Buffer Object and ending at the size of vhVertexCount.

// glDrawArrays(GL_TRIANGLES, 0, vhVertexCount);

Now that we have setup and drawn our Vertex Buffer Object, we need to disable our client states and texturing with the following lines:

// glDisableClientState(GL_VERTEX_ARRAY);

// glDisable(GL_TEXTURE_2D);
// glDisableClientState(GL_TEXTURE_COORD_ARRAY);

Phew, now we can finally move away from this file :-)

1.
2.
3.
4.
5.
6.
7.
8.
9.

10.
11.
12.
13.
14.
15.
16.
17.
18.

19.
20.
21.
22.
23.
24.
25.
26.
27.

28.
29.
30.
31.
32.
33.
34.
35.
36.

37.
38.
39.
40.
41.
42.
43.
44.
45.

46.
47.
48.
49.
50.
51.
52.
53.
54.

55.
56.
57.
58.
59.
60.
61.
62.
63.

64.
65.
66.
67.
68.
69.
70.
71.
72.

73.
74.
75.
76.
77.
78.
79.
80.
81.

82.
83.
84.
85.
86.
87.
88.
89.
90.

91.
92.
93.
94.
95.
96.
97.
98.

  #include <stdio.h>

#include <GL/glew.h>
#include <GL/gl.h>
#include <GL/glext.h>

#include “jpeg.h”
#include “heightfield.h”

bool SwiftHeightField::Init(void){
    

glGenBuffersARB(1, &vhVBOVertices);
    
glBindBufferARB(GL_ARRAY_BUFFER_ARB, vhVBOVertices);
    
glBufferDataARB(GL_ARRAY_BUFFER_ARB, vhVertexCount * 3 * sizeof(float), vhVertices, GL_STATIC_DRAW_ARB);

    

    
glGenBuffersARB(1, &vhVBOTexCoords);
    
glBindBufferARB(GL_ARRAY_BUFFER_ARB, vhVBOTexCoords);
    

glBufferDataARB(GL_ARRAY_BUFFER_ARB, vhVertexCount * 2 * sizeof(float), vhTexCoords, GL_STATIC_DRAW_ARB);

    

    
delete [] vhVertices;
    
vhVertices = NULL;
    

    
delete [] vhTexCoords;
    

vhTexCoords = NULL;
    

    
return true;
}

bool SwiftHeightField::Create(char *hFileName, const int hWidth, 
const int hHeight){
    

hmHeight = hHeight;
    
hmWidth = hWidth;
    

    
FILE *fp;
    

    
fp = fopen(hFileName, “rb”);
    

    
fread(hHeightField, 1, hWidth * hHeight, fp);
    

    
fclose(fp);
    

    
vhVertexCount = (int)(hmHeight * hmWidth * 6) / (1 * 1);
    

vhVertices = new Vert[vhVertexCount];
    
vhTexCoords = new TexCoord[vhVertexCount];
    

    
int nIndex = 0;
    
float flX;
    
float flZ;
    

    
for (int hMapX = 0; hMapX < hmWidth; hMapX++){
        

for (int hMapZ = 0; hMapZ < hmHeight; hMapZ++){
            
for (int nTri = 0; nTri < 6; nTri++){
                

flX = (float)hMapX + ((nTri == 1 || nTri == 2 || nTri == 5) ? 1 : 0);
                

flZ = (float)hMapZ + ((nTri == 2 || nTri == 4 || nTri == 5) ? 1 : 0);
                

                
vhVertices[nIndex].x = flX;
                
vhVertices[nIndex].y = hHeightField[(int)flX][(int)flZ];
                

vhVertices[nIndex].z = flZ;
                

                
vhTexCoords[nIndex].u = flX / 1024;
                

vhTexCoords[nIndex].v = flZ / 1024;
                
nIndex++;
            
}
        

}
    
}
    

    
SwiftTextureJpeg(tID, “texture.jpg”, 0);
    

    
Init();
    

    
return true;
}

void SwiftHeightField::Render(void){
    

glEnableClientState(GL_TEXTURE_COORD_ARRAY);
    
glEnable(GL_TEXTURE_2D);
    
glBindTexture(GL_TEXTURE_2D, tID[0]);
    

    
glBindBufferARB(GL_ARRAY_BUFFER_ARB, vhVBOTexCoords);
    
glTexCoordPointer(2, GL_FLOAT, 0, (char *) NULL);
    

    
glEnableClientState(GL_VERTEX_ARRAY);
    
glBindBufferARB(GL_ARRAY_BUFFER_ARB, vhVBOVertices);
    
glVertexPointer(3, GL_FLOAT, 0, (char *) NULL);
    

    
glDrawArrays(GL_TRIANGLES, 0, vhVertexCount);
    

    
glDisableClientState(GL_VERTEX_ARRAY);
    

    

glDisable(GL_TEXTURE_2D);
    
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}

Main.CPP File:

Our major changes to this file are going to take place in the form of initializing our extensions that we are going to use. To do this, I am first going to create a function called initExtensions which is where we are going to initialize all our extensions:

// void initExtensions(void){
// }

Now that we have a nice neat place to initialize our extensions, lets initialize them:

// glGenBuffersARB = (PFNGLGENBUFFERSARBPROC) wglGetProcAddress("glGenBuffersARB");
// glBindBufferARB = (PFNGLBINDBUFFERARBPROC) wglGetProcAddress("glBindBufferARB");
// glBufferDataARB = (PFNGLBUFFERDATAARBPROC) wglGetProcAddress("glBufferDataARB");

// glDeleteBuffersARB = (PFNGLDELETEBUFFERSARBPROC) wglGetProcAddress("glDeleteBuffersARB");

The above extensions are everything we need to create and use our Vertex Buffer Objects. As we now have our extensions initialized and ready to use, we need to call the initExtensions function. I am doing this inside our Init function *before* we create our heightfield. This is because the extensions are needed for the creation of our Vertex Buffer Objects, not just in drawing them. So our Init function now looks like:

// void Init (void) {
// glEnable(GL_DEPTH_TEST);
// glDepthFunc(GL_LEQUAL);

// initExtensions();

// hField.Create("heightField.raw", 1024, 1024);
// }

And that is it for now. Check out the next tutorial on optimizing the heightfield using for a good solid 60 frames per second here :-)

If you have any questions, just email me at swiftless@gmail.com

1.
2.
3.
4.
5.

6.
7.
8.
9.
10.
11.
12.
13.
14.

15.
16.
17.
18.
19.
20.
21.
22.
23.

24.
25.
26.
27.
28.
29.
30.
31.
32.

33.
34.
35.
36.
37.
38.
39.
40.
41.

42.
43.
44.
45.
46.
47.
48.
49.
50.

51.
52.
53.
54.
55.
56.
57.
58.
59.

60.
61.
62.
63.
64.
65.
66.
67.
68.

69.
70.
71.
72.
73.
74.
75.
76.
77.

78.
79.
80.
81.
82.
83.
84.
85.
86.

87.
88.
89.
90.
91.
92.
93.
94.
95.

96.
97.
98.
99.
100.
101.
102.
103.
104.

105.
106.
107.
108.
109.
110.
111.
112.
113.

114.
115.
116.
117.
118.
119.
120.
121.
122.

123.
124.
125.
126.
127.
128.
129.
130.
131.

132.
133.
134.
135.
136.
137.
138.
139.
140.

141.
142.
143.
144.
145.

  #include <GL/glew.h>

#include <GL/gl.h>
#include <GL/glext.h>
#include <GL/GLUT.h>

#include <math.h>

#include <windows.h>
#include <stdio.h>

#include <string.h>
#include <fstream>
#include <assert.h>

#include “heightfield.h”

#pragma comment(lib,“glew32.lib”)

float xpos = 851.078, ypos = 351.594, zpos = 281.033, xrot = 758, yrot = 238,
 angle=0.0;

float lastx, lasty;

float bounce;
float cScale = 1.0;

SwiftHeightField hField;

void camera (void) {
    
int posX = (int)xpos;
    

int posZ = (int)zpos;
    

    
glRotatef(xrot,1.0,0.0,0.0);
    
glRotatef(yrot,0.0,1.0,0.0);
    

glTranslated(-xpos,-ypos,-zpos);
}

void display (void) {
    

glClearColor (0.0,0.0,0.0,1.0);
    
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    

glLoadIdentity();
    
camera();
    

    
glPushMatrix();
    
hField.Render();
    

glPopMatrix();
    

    
glutSwapBuffers();
}

void initExtensions(void){
    

glGenBuffersARB = (PFNGLGENBUFFERSARBPROC) wglGetProcAddress(“glGenBuffersARB”);
    
glBindBufferARB = (PFNGLBINDBUFFERARBPROC) wglGetProcAddress(“glBindBufferARB”);

    
glBufferDataARB = (PFNGLBUFFERDATAARBPROC) wglGetProcAddress(“glBufferDataARB”);
    
glDeleteBuffersARB = (PFNGLDELETEBUFFERSARBPROC) wglGetProcAddress(“glDeleteBuffersARB”);

}

void Init (void) {
    
glEnable(GL_DEPTH_TEST);
    

glDepthFunc(GL_LEQUAL);
    

    
initExtensions();
    

    
hField.Create(“heightField.raw”, 1024, 1024);

}

void mouseMovement(int x, int y) {
    
int diffx=x-lastx;
    

int diffy=y-lasty;
    
lastx=x;
    
lasty=y;
    
xrot += (float) diffy;
    

yrot += (float) diffx;
}

void keyboard (unsigned char key, int x, int y) {
    

    
if (key == ‘w’)
    
{
        
float xrotrad, yrotrad;
        

yrotrad = (yrot / 180 * 3.141592654f);
        
xrotrad = (xrot / 180 * 3.141592654f);
        

xpos += float(sin(yrotrad)) * cScale;
        
zpos -= float(cos(yrotrad)) * cScale;
        

ypos -= float(sin(xrotrad)) ;
        
bounce += 0.04;
    

}
    

    
if (key == ‘s’)
    
{
        
float xrotrad, yrotrad;
        

yrotrad = (yrot / 180 * 3.141592654f);
        
xrotrad = (xrot / 180 * 3.141592654f);
        

xpos -= float(sin(yrotrad)) * cScale;
        
zpos += float(cos(yrotrad)) * cScale;
        

ypos += float(sin(xrotrad));
        
bounce += 0.04;
    

}
    

    
if (key == ‘d’)
    
{
        
float yrotrad;
        

yrotrad = (yrot / 180 * 3.141592654f);
        
xpos += float(cos(yrotrad)) * cScale;
        

zpos += float(sin(yrotrad)) * cScale;
    
}
    

    
if (key == ‘a’)
    
{
        
float yrotrad;
        

yrotrad = (yrot / 180 * 3.141592654f);
        
xpos -= float(cos(yrotrad)) * cScale;
        

zpos -= float(sin(yrotrad)) * cScale;
    
}
    

}

void reshape (int w, int h) {
    
glViewport (0, 0, (GLsizei)w, (GLsizei)h);
    

glMatrixMode (GL_PROJECTION);
    
glLoadIdentity ();
    
gluPerspective (60, (GLfloat)w / (GLfloat)h, 1.0, 1000.0);
    

glMatrixMode (GL_MODELVIEW);
}

int main (int argc, char **argv) {
    

glutInit(&argc, argv);
    
glutInitDisplayMode(GLUT_DOUBLE | GLUT_DEPTH | GLUT_RGBA);
    

glutInitWindowSize(500, 500);
    
glutInitWindowPosition(100, 100);
    
glutCreateWindow(“A basic OpenGL Window);
    

Init();
    
glutDisplayFunc(display);
    
glutIdleFunc(display);
    

glutReshapeFunc(reshape);
    
glutKeyboardFunc(keyboard);
    
glutPassiveMotionFunc(mouseMovement);
    

glutMainLoop ();
    
return 0;
}

Download:

Download heightfield.h Source Code for this Tutorial

Download heightfield.cpp Source Code for this Tutorial

Download main.cpp Source Code for this Tutorial

Download heightfield.raw for this Tutorial

Download texture.jpg for this Tutorial

Download jpeg.h Source Code for this Tutorial

Download jpeg.cpp Source Code for this Tutorial

Download jpeglib.zip for this Tutorial

VN:F [1.9.3_1094]
Please rate so I know where to improve the site. 1 means needs a lot of improvement, 10 means perfect. If you leave a low rating, please state why. I don't want people just coming to bash the site.
Rating: 7.0/10 (4 votes cast)
VN:F [1.9.3_1094]
Rating: +3 (from 3 votes)

4. GLSL Lighting

Posted on : 25-03-2010 | By : Swiftless | In : GLSL

Tags: , , , , , ,

2

Jump To:

main.cpp Source
shader.vert Source
shader.frag Source
Download

Ok, so we can create a shader program, and render a shape with a specified color. Lets move into lighting. In this tutorial, I am going to show you how to perform per vertex lighting, which is then easily modified to achieve per pixel lighting in the next tutorial.

Lets get moving :)

Main.CPP File:

There are going to be quite a few additions to this code, but you might recognise most of it from the lighting tutorials.

I am creating a directional light, that points in the direction [0,1,1]. It has a diffuse color of white, and an ambient color of black.

I have placed the calls to setup my lighting inside of a new method, which is called during our display method, *after* we set the camera position. I have a tip on the OpenGL Tips page, that explains why we do this.

Another minor change, is that I am now using a glutSolidSphere, I have kept it to a low polygon count, only 10 stacks and 10 slices. This is to show how per vertex will differ to per pixel lighting later on.

But enough of that, lets move onto our shaders. You should already know how to setup lighting in a standard OpenGL application.

1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
  #if ( (defined(__MACH__)) && (defined(__APPLE__)) )   
#include <stdlib.h>
#include <OpenGL/gl.h>
#include <GLUT/glut.h>
#include <OpenGL/glext.h>
#else
#include <stdlib.h>
#include <GL/glew.h>
#include <GL/gl.h>
#include <GL/glut.h>
#include <GL/glext.h>
#endif

#include “shader.h”

Shader shader;

GLfloat angle = 0.0; //set the angle of rotation

//diffuse light color variables
GLfloat dlr = 1.0;
GLfloat dlg = 1.0;
GLfloat dlb = 1.0;

//ambient light color variables
GLfloat alr = 0.0;
GLfloat alg = 0.0;
GLfloat alb = 0.0;

//light position variables
GLfloat lx = 0.0;
GLfloat ly = 1.0;
GLfloat lz = 1.0;
GLfloat lw = 0.0;

void init(void) {
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LESS);
    
    shader.init(“shader.vert”, “shader.frag”);
}

void cube (void) {
    glRotatef(angle, 1.0, 0.0, 0.0); //rotate on the x axis
    glRotatef(angle, 0.0, 1.0, 0.0); //rotate on the y axis
    glRotatef(angle, 0.0, 0.0, 1.0); //rotate on the z axis
    glColor4f(1.0, 0.0, 0.0, 1.0);
    glutSolidSphere(2, 10, 10);
}

void setLighting(void) {
    GLfloat DiffuseLight[] = {dlr, dlg, dlb}; //set DiffuseLight[] to the 
specified values

    GLfloat AmbientLight[] = {alr, alg, alb}; //set AmbientLight[] to the 
specified values

    
    glLightfv (GL_LIGHT0, GL_DIFFUSE, DiffuseLight); //change the light
 accordingly

    glLightfv (GL_LIGHT0, GL_AMBIENT, AmbientLight); //change the light
 accordingly

    
    GLfloat LightPosition[] = {lx, ly, lz, lw}; //set the LightPosition to 
the specified values

    
    glLightfv (GL_LIGHT0, GL_POSITION, LightPosition); //change the 
light accordingly

}

void display (void) {
    glClearColor (0.0,0.0,0.0,1.0);
    glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();  
    gluLookAt (0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
    
    setLighting();
    
    shader.bind();
    cube();
    shader.unbind();
    
    glutSwapBuffers();
    angle += 0.01f;
}

void reshape (int w, int h) {
    glViewport (0, 0, (GLsizei)w, (GLsizei)h);
    glMatrixMode (GL_PROJECTION);
    glLoadIdentity ();
    gluPerspective (60, (GLfloat)w / (GLfloat)h, 1.0, 100.0);
    glMatrixMode (GL_MODELVIEW);
}

int main (int argc, char **argv) {
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH); //set up
 the double buffering

    glutInitWindowSize(500, 500);
    glutInitWindowPosition(100, 100);
    glutCreateWindow(“A basic OpenGL Window);
    
    glutDisplayFunc(display);
    glutIdleFunc(display);
    
    glutReshapeFunc(reshape);
    
    init();
    
    glutMainLoop();
    
    return 0;
}

Vertex Shader Source:

For this tutorial, I am going show you how to perform per
vertex lighting using shaders. Yes, shaders support per pixel
but this is just a starting point.

First I am going to teach you about varying variables. These
are variables that can be shared between the vertex and fragment
shaders. These variables are set inside the vertex shader, and
then read from the fragment shader. In this case we are going
to share a float type variable from the Vertex shader to the
Fragment shader. This variable is going to be called diffuse_value
and will hold a number that will tell us how lit our vertex
should be.

Because we are using per vertex lighting, the GLSL shader will
automatically interpolate the color between the vertices. Just
like OpenGL does.

Now first off we need to know the surface normal of the current
vertex. Because I am using a GLUT sphere, these are already
calculated and sent off with the glNormal3f command. Any numbers
sent from OpenGL through glNormal*; can be read with
the variable gl_Normal. In later tutorials, I will be using
self calculated normals, using my own normal generation code.

Now as for our normal, I am storing it in the variable vec3 vertex_normal.
But first, I have to multiply the normal (gl_Normal) by
the gl_NormalMatrix. This places the normal into world coordinates so that
we can use it correctly. (Later on I will show you how to use tangent space
normals). We also then have to normalize this multiplication so
that all of the normal vectors are between (and including) -1 and 1. Our final call looks like:

vec3 vertex_normal = normalize(gl_NormalMatrix * gl_Normal);

Next on, we are going to work with our light. I am storing this
in a variable called vec3 vertex_light_position. In this, I am calling for the
position of glLight0. This is gathered by the call:

vec3 vertex_light_position = gl_LightSource[0].position.xyz;

This gives us the position of glLight0, and to get the position of
any other light, we just change the number 0 to the light number we
are after. We do not need to multiply this expression by the
gl_NormalMatrix, it is already in world coordinates, as it has been multiplied by the ModelView Matrix before we set it’s position, but we do have to normalize it still.

Now that we have our vertex_normal and the position of our vertex_light_position.
We can now calculate the diffuse_value of our lighting at the
given vertex. To do this we need to take the dot product of both
the vertex_normal and the vertex_light_position together. If you have any idea on
calculating normals, then you should have a fair idea of what the
dot product does. It works as such:
dot(a,b) = (x1 * x2) + (y1 * y2) + (z1 * z3)
If this happens to be equal to 0, then the vectors a and b are
perpendicular (the light meets the surface at a 90 degree angle).
We use the call max(), to make sure we do not get a negative value.
So our diffuse_value equation becomes:

diffuse_value = max(dot(vertex_normal, vertex_light_position), 0.0);

And from that, we have now calculated the intensity of the light
at the given vertex. That started to turn into a bit of a maths
lesson, but it even cleared up some stuff for me without even
thinking about it. GO MATHS :)

1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.

  varying float diffuse_value;

void main() {            
    // Calculate the normal value for this vertex, in world coordinates (
multiply by gl_NormalMatrix)

    vec3 vertex_normal = normalize(gl_NormalMatrix * gl_Normal);
    // Calculate the light position for this vertex
    vec3 vertex_light_position = gl_LightSource[0].position.xyz;
    // Set the diffuse value (darkness). This is done with a dot product between
 the normal and the light

    // and the maths behind it is explained in the maths section of the site.
    diffuse_value = max(dot(vertex_normal, vertex_light_position), 0.0);

    // Set the front color to the color passed through with glColor*f
    gl_FrontColor = gl_Color;
    // Set the position of the current vertex 
    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}

 

Fragment Shader Source:

Because we are using the varying float Diffuse in
our vertex shader, if we wish to read it in here, we
need to set the same variable, so I have done this
first:

varying float diffuse_value;

After that, because I am building on the last tutorial, we will multiply
our colour value, by our new diffuse_value, so our final call to
gl_FragColor will look like:

gl_FragColor = gl_Color * diffuse_value;

Once you get this running, it should show a sphere that gets darker down the bottom, or if you add a camera, it will be dark behind as well. Which you can see in the image at the top of the page.

If you have any questions, please email me at swiftless@gmail.com

1.
2.
3.
4.
5.
6.
7.
  varying float diffuse_value;

void main() {
    // Set the output color of our current pixel
    gl_FragColor = gl_Color * diffuse_value;
}

 

Download:

Download shader.h Source Code for this Tutorial

Download shader.cpp Source Code for this Tutorial

Download main.cpp Source Code for this Tutorial

Download shader.vert Source Code for this Tutorial

Download shader.frag Source Code for this Tutorial

VN:F [1.9.3_1094]
Please rate so I know where to improve the site. 1 means needs a lot of improvement, 10 means perfect. If you leave a low rating, please state why. I don't want people just coming to bash the site.
Rating: 9.0/10 (3 votes cast)
VN:F [1.9.3_1094]
Rating: 0 (from 0 votes)

26. OpenGL Vertex Alphas

Posted on : 25-03-2010 | By : Swiftless | In : OpenGL

Tags: , , , , ,

0

This OpenGL tutorial will show you how to add different alpha values to specific vertices in your shape. It uses the same glColor4f commands but the code is now written just before each vertex.

Vertex alphas are basically the same as vertex colors. They just set the
alpha of selected vertices instead of just setting the whole object to a
selected alpha.

So anyway, I did this with a normal quad
but it does work with any shape you choose
Here it is:
I have started my quad.
I then set the color red for the first vertex, with an alpha of only 0.2.
I then draw that vertex.
The next is green, with an alpha value of 1.
Then blue with an alpha value of 0.2.
And finally white with an alpha value of 1.

glBegin(GL_QUADS);
glColor4f(1,0,0,0.2);
glVertex3f(-0.5, -0.5, 0.0);
glColor4f(0,1,0,1);
glVertex3f(-0.5, 0.5, 0.0);
glColor4f(0,0,1,0.2);
glVertex3f(0.5, 0.5, 0.0);
glColor4f(1,1,1,1);
glVertex3f(0.5, -0.5, 0.0);
glEnd();

Just remember to call each vertex after you call the color
for this to work.

Just email swiftless@gmail.com if you have any questions :-)

1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
  //Vertex alphas are basically the same
//as vertex colors. They just set the
//alpha of selected vertices instead of
//just setting the whole object to a
//selected alpha.

//So anyway, I did this with a normal quad
//but it does work with any shape you choose
//Here it is:
//I have started my quad.
//I then set the color red for the first vertex, with an alpha of only 0.2
//I then draw that vertex.
//The next is green, with an alpha value of 1.
//Then blue with an alpha value of 0.2.
//And finally white with an alpha value of 1.

//glBegin(GL_QUADS);
//glColor4f(1,0,0,0.2);
//glVertex3f(-0.5, -0.5, 0.0);
//glColor4f(0,1,0,1);
//glVertex3f(-0.5, 0.5, 0.0);
//glColor4f(0,0,1,0.2);
//glVertex3f(0.5, 0.5, 0.0);
//glColor4f(1,1,1,1);
//glVertex3f(0.5, -0.5, 0.0);
//glEnd();

//Just remember to call each vertex after you call the color
//for this to work.

#include <GL/gl.h>
#include <GL/glut.h>

void square (void) {
    glBegin(GL_QUADS);
    glColor4f(1,0,0,0.2); //red, alpha 0.2
    glVertex3f(-0.5, -0.5, 0.0);
    glColor4f(0,1,0,1); //green, alpha 1
    glVertex3f(-0.5, 0.5, 0.0);
    glColor4f(0,0,1,0.2); //blue, alpha 0.2
    glVertex3f(0.5, 0.5, 0.0);
    glColor4f(1,1,1,1); //white, alpha 1
    glVertex3f(0.5, -0.5, 0.0);
    glEnd();
}

void display (void) {
    glClearColor (0.0,0.0,0.0,1.0);
    glClear (GL_COLOR_BUFFER_BIT);
    glLoadIdentity();
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glTranslatef(0,0,-1);
    square();
    glFlush();
}

void reshape (int w, int h) {
    glViewport (0, 0, (GLsizei)w, (GLsizei)h);
    glMatrixMode (GL_PROJECTION);
    glLoadIdentity ();
    gluPerspective (60, (GLfloat)w / (GLfloat)h, 1.0, 100.0);
    glMatrixMode (GL_MODELVIEW);
}

int main (int argc, char **argv) {
    glutInit (&argc, argv);
    glutInitDisplayMode (GLUT_SINGLE | GLUT_RGBA);
    glutInitWindowSize (500, 500);
    glutInitWindowPosition (100, 100);
    glutCreateWindow (“A basic OpenGL Window);
    glutDisplayFunc (display);
    glutReshapeFunc (reshape);
    glutMainLoop ();
    return 0;
}

VN:F [1.9.3_1094]
Please rate so I know where to improve the site. 1 means needs a lot of improvement, 10 means perfect. If you leave a low rating, please state why. I don't want people just coming to bash the site.
Rating: 0.0/10 (0 votes cast)
VN:F [1.9.3_1094]
Rating: 0 (from 0 votes)

25. OpenGL Vertex Coloring

Posted on : 25-03-2010 | By : Swiftless | In : OpenGL

Tags: , , , ,

1

This OpenGL tutorial will show you how to add colors to specific vertices in your shape. It uses the same color commands but the code is now written just before each vertex.

Vertex coloring is nothing really special
it is just normal coloring, only setting the colors
to specific vertices instead of whole objects.
This then blends the colors into each other
forming a nice little rainbow type thing
with the colors I have chosen.

So anyway, I did this with a normal quad
but it does work with any shape you choose
Here it is:
I have started my quad.
I then set the color red for the first vertex.
I then draw that vertex.
The next is green.
Then blue.
And finally white.

glBegin(GL_QUADS);
glColor3f(1,0,0);
glVertex3f(-0.5, -0.5, 0.0);
glColor3f(0,1,0);
glVertex3f(-0.5, 0.5, 0.0);
glColor3f(0,0,1);
glVertex3f(0.5, 0.5, 0.0);
glColor3f(1,1,1);
glVertex3f(0.5, -0.5, 0.0);
glEnd();

Just remember to call each vertex after you call the color
for this to work.

1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
  //Vertex coloring is nothing really special
//it is just normal coloring only setting the colors
//to specific vertices instead of whole objects.
//This then blends the colors into each other
//forming a nice little rainbow type thing
//with the colors I have chosen.

//So anyway, I did this with a normal quad
//but it does work with any shape you choose
//Here it is:
//I have started my quad.
//I then set the color red for the first vertex.
//I then draw that vertex.
//The next is green.
//Then blue.
//And finally white.

//glBegin(GL_QUADS);
//glColor3f(1,0,0);
//glVertex3f(-0.5, -0.5, 0.0);
//glColor3f(0,1,0);
//glVertex3f(-0.5, 0.5, 0.0);
//glColor3f(0,0,1);
//glVertex3f(0.5, 0.5, 0.0);
//glColor3f(1,1,1);
//glVertex3f(0.5, -0.5, 0.0);
//glEnd();

//Just remember to call each vertex after you call the color
//for this to work.

#include <GL/gl.h>
#include <GL/glut.h>

void square (void) {
    glBegin(GL_QUADS);
    glColor3f(1,0,0); //red
    glVertex3f(-0.5, -0.5, 0.0);
    glColor3f(0,1,0); //green
    glVertex3f(-0.5, 0.5, 0.0);
    glColor3f(0,0,1); //blue
    glVertex3f(0.5, 0.5, 0.0);
    glColor3f(1,1,1); //white
    glVertex3f(0.5, -0.5, 0.0);
    glEnd();
}

void display (void) {
    glClearColor (0.0,0.0,0.0,1.0);
    glClear (GL_COLOR_BUFFER_BIT);
    glLoadIdentity();
    glTranslatef(0,0,-1);
    square();
    glFlush();
}

void reshape (int w, int h) {
    glViewport (0, 0, (GLsizei)w, (GLsizei)h);
    glMatrixMode (GL_PROJECTION);
    glLoadIdentity ();
    gluPerspective (60, (GLfloat)w / (GLfloat)h, 1.0, 100.0);
    glMatrixMode (GL_MODELVIEW);
}

int main (int argc, char **argv) {
    glutInit (&argc, argv);
    glutInitDisplayMode (GLUT_SINGLE);
    glutInitWindowSize (500, 500);
    glutInitWindowPosition (100, 100);
    glutCreateWindow (“A basic OpenGL Window);
    glutDisplayFunc (display);
    glutReshapeFunc (reshape);
    glutMainLoop ();
    return 0;
}

VN:F [1.9.3_1094]
Please rate so I know where to improve the site. 1 means needs a lot of improvement, 10 means perfect. If you leave a low rating, please state why. I don't want people just coming to bash the site.
Rating: 0.0/10 (0 votes cast)
VN:F [1.9.3_1094]
Rating: 0 (from 0 votes)
Improve the web with Nofollow Reciprocity.