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

8. Bump Mapping in GLSL

Posted on : 24-06-2010 | By : Swiftless | In : GLSL, Tutorials

Tags: , , , , , , , ,

4

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 by taking an image which stores surface normals on a per-pixel basis. This means that we can apply standard lighting techniques that require a normal value on a per-pixel basis instead of a per-vertex or per-surface basis. This gives our applications a greatly added sense of realism.

How does bump mapping work in OpenGL with GLSL though? GLSL texturing works on a per-texel basis, where a texel can be thought of as a scaled pixel, either larger or smaller, and we get access to a texel at any fragment on an objects surface when we are texturing in GLSL. We already covered texturing in GLSL in a previous tutorial, so I won’t go over it again.

When you look at a normal map, it is generally a blue and purple color. To get your head around normal mapping, all you need to understand is that each pixel in this image file, can be mapped to a normal value. Once you can understand that, normal mapping is extremely straight forward.

Don’t get this tutorial on bump mapping confused with tangent-space bump mapping though. There aren’t many tutorials around that explain the different, but regular bump mapping only cares about the normal maps relation to lights. Tangent space bump mapping takes it a step further and takes into account the objects surfaces in relation-to the light as well as the normal maps relation.

Coding

Enough theory, how can we get it into OpenGL and GLSL. The first thing we will want to do is load in our normal map, and apply it to our object in OpenGL. This requires multi-texturing in OpenGL, which I don’t believe I have covered in GLSL, so I will include that in this tutorial. This code is going to be based on the GLSL texturing tutorial, but you may notice some additions to make it cross-platform between OSX and Windows correctly.

Main.cpp

We are only going to need one new variable for the main.cpp file which will be used to store our normal map texture. This is stored and used just like a normal texture. I am going to call this normal_texture, and define it with our texture variable at the top of our file.

GLuint normal_texture; // Our normal map texture

Then go down to your init method, and remove the current line that creates a texture, and replace it with the following two lines, which will create both of our new

texture = LoadTexture("colour_map.raw", 256, 256);
normal_texture = LoadTexture("normal_map.raw", 256, 256);

Inside of our init method you may also notice the following code, this is for cross-platform compatibility and simply checks if we are on OSX or not. If not, we initialize glew.

#if ( (defined(__MACH__)) && (defined(__APPLE__)) )
#else
glewInit();
#endif

The rest of our code for the main source code file, goes into our cube method, which I have now modified to draw a square instead.

You should already have code to set the first texture, and we are going to adjust this slightly by adding the following line after we set our active texture:

glEnable(GL_TEXTURE_2D);

Our code to set up our first texture should now look like:

glActiveTexture(GL_TEXTURE0);
glEnable(GL_TEXTURE_2D);
int texture_location = glGetUniformLocation(shader.id(), "color_texture");
glUniform1i(texture_location, 0);
glBindTexture(GL_TEXTURE_2D, texture);

Now we need to set up our second texture. This is done by activating the next texture, GL_TEXTURE1 and modifying the other calls to point to our normal map texture. When we do this, we need to make sure that our glUniform1i for our normal map location in the shader, has the value 1. When multi-texturing in GLSL, each texture used will have an incremented value in the shader. Our final code will look like:

glActiveTexture(GL_TEXTURE1);
glEnable(GL_TEXTURE_2D);
int normal_location = glGetUniformLocation(shader.id(), "normal_texture");
glUniform1i(normal_location, 1);
glBindTexture(GL_TEXTURE_2D, normal_texture);

I won’t explain the code for drawing the square, as I have done this in previous tutorials, so I will jump to after our square. We will need to do some cleaning up, as we don’t want our texture states to mess up when we render other objects later on. All I am doing to clean up, is setting the active texture, binding it to nothing, and then disabling texturing on this texture. Note that I am doing this in reverse to how I have set the textures. You can do this in any order, but I like this as I find it easier to follow (count up on initialization, and then count down on de-initialization).

glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, 0);
glDisable(GL_TEXTURE_2D);

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, 0);
glDisable(GL_TEXTURE_2D);

Shader.vert

Our vertex shader requires absolutely no extra calls, so just use the one provided in the previous texturing tutorial.

Shader.frag

Shader.frag is going to contain all of our bump mapping calculations. To get this going, we need to add a new uniform variable, which will load in our normal mapping texture:

uniform sampler2D normal_texture;

Now that we have access to our normal map, lets load it in. For a normal, we only require a 3 value vector, or vec3 in GLSL, and we are going to normalize this to make sure the final normal vector is of unit length. In other words, it has a length of 1.0. But in this line take note of the (* 2.0 – 1.0). When we read in a texture value, we get a number between 0.0 and 1.0 as color cannot have a negative value. This then multiplies the value by 2.0, giving us values between 0.0 and 2.0, and then subtracts 1.0 so we get our final values in the range of -1.0 to 1.0. We have to do this manipulation as a normal vector is 3D and can be pointing in any direction. It’s a nifty little trick which allows us to convert a normal map texture file to a normal map.

// Extract the normal from the normal map
vec3 normal = normalize(texture2D(normal_texture, gl_TexCoord[0].st).rgb * 2.0 - 1.0);

Since we now have the normal value for the current pixel, I am going to set up a quick light, located at the top right of the scene, and also a little towards us. Usually you would base this on actual lights in your scene, and to do so, take a look at my GLSL lighting tutorial.

// Determine where the light is positioned (this can be set however you like)
vec3 light_pos = normalize(vec3(1.0, 1.0, 1.5));

Finally we can get to some familiar code. We are going to calculate the diffuse value for the current pixel, based on our normal extracted from the normal map. Then we are going to multiply the diffuse value against our color texture, and assign the output to our gl_FragColor variable.

// Calculate the lighting diffuse value
float diffuse = max(dot(normal, light_pos), 0.0);

vec3 color = diffuse * texture2D(color_texture, gl_TexCoord[0].st).rgb;

// Set the output color of our current pixel
gl_FragColor = vec4(color, 1.0);

And now you should have a perfectly working bump mapping shader. If you have any questions, feel free to email me at swiftless@gmail.com or leave a comment below.

Downloads

Colour Map Texture
Normal Map Texture

Tutorial Code

Main.cpp

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

GLuint texture;
GLuint normal_texture; // Our normal map texture

GLuint LoadTexture( const char * filename, int width, int height )
{
GLuint texture;
unsigned char * data;
FILE * file;

//The following code will read in our RAW file
file = fopen( filename, "rb" );

if ( file == NULL ) return 0;
data = (unsigned char *)malloc( width * height * 3 );
fread( data, width * height * 3, 1, file );

fclose( file );

glGenTextures( 1, &texture ); //generate the texture with the loaded data
glBindTexture( GL_TEXTURE_2D, texture ); //bind the texture to it’s array

glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); //set texture environment parameters

//And if you go and use extensions, you can use Anisotropic filtering textures which are of an
//even better quality, but this will do for now.
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

//Here we are setting the parameter to repeat the texture instead of clamping the texture
//to the edge of our shape.
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );

//Generate the texture
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);

free( data ); //free the texture

return texture; //return whether it was successfull
}

void FreeTexture( GLuint texture )
{
glDeleteTextures( 1, &texture );
}

void init(void) {
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);

#if ( (defined(__MACH__)) && (defined(__APPLE__)) )
#else
glewInit();
#endif

shader.init("shader.vert", "shader.frag");

texture = LoadTexture("colour_map.raw", 256, 256);
normal_texture = LoadTexture("normal_map.raw", 256, 256);
}

void cube (void) {
glActiveTexture(GL_TEXTURE0);
glEnable(GL_TEXTURE_2D);
int texture_location = glGetUniformLocation(shader.id(), "color_texture");
glUniform1i(texture_location, 0);
glBindTexture(GL_TEXTURE_2D, texture);

glActiveTexture(GL_TEXTURE1);
glEnable(GL_TEXTURE_2D);
int normal_location = glGetUniformLocation(shader.id(), "normal_texture");
glUniform1i(normal_location, 1);
glBindTexture(GL_TEXTURE_2D, normal_texture);

glBegin(GL_QUADS);
glTexCoord2f(0.0f, 0.0f);
glVertex3f(-1.0f, -1.0f, 0.0f);

glTexCoord2f(1.0f, 0.0f);
glVertex3f(1.0f, -1.0f, 0.0f);

glTexCoord2f(1.0f, 1.0f);
glVertex3f(1.0f, 1.0f, 0.0f);

glTexCoord2f(0.0f, 1.0f);
glVertex3f(-1.0f, 1.0f, 0.0f);
glEnd();

glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, 0);
glDisable(GL_TEXTURE_2D);

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, 0);
glDisable(GL_TEXTURE_2D);
}

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, 2.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);

shader.bind();
cube();
shader.unbind();

glutSwapBuffers();
}

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");

init();

glutDisplayFunc(display);
glutIdleFunc(display);

glutReshapeFunc(reshape);

glutMainLoop();

return 0;
}

Shader.vert

void main() {
gl_TexCoord[0] = gl_MultiTexCoord0;

// Set the position of the current vertex
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}

Shader.frag

uniform sampler2D color_texture;
uniform sampler2D normal_texture;

void main() {

// Extract the normal from the normal map
vec3 normal = normalize(texture2D(normal_texture, gl_TexCoord[0].st).rgb * 2.0 - 1.0);

// Determine where the light is positioned (this can be set however you like)
vec3 light_pos = normalize(vec3(1.0, 1.0, 1.5));

// Calculate the lighting diffuse value
float diffuse = max(dot(normal, light_pos), 0.0);

vec3 color = diffuse * texture2D(color_texture, gl_TexCoord[0].st).rgb;

// Set the output color of our current pixel
gl_FragColor = vec4(color, 1.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: 8.0/10 (3 votes cast)
VN:F [1.9.3_1094]
Rating: 0 (from 2 votes)

5. Terrain Textures

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

Tags: , , , ,

4

Jump To:

heightfield.h Source
heightfield.cpp Source

main.cpp Source
Download

Heightfield.H File:

Another nice little adjustment to our heightfield.h file. We just need to assign a variable to hold our textures :-) I am calling this tID and at this point, is an array with just 2 positions, for now we will just be working with tID[0], but later on when we add normal mapping, we will be working with tID[1]:

// unsigned int tID[2];

Now lets move onto our heightfield.cpp file :-)

1.
2.
3.
4.

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

14.
15.
16.

  #include <windows.h>

class SwiftHeightField {
    
private:
    

int hmHeight;
    
int hmWidth;
    

    
unsigned int tID[2];
    

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

    
void Render(void);
    

    
BYTE hHeightField[1024][1024];

};

Heightfield.CPP File:

The first change here that you will need to pay attention to, is the incorporation of jpeg.h. Just like in the ‘Loading a JPEG texture’ tutorial (coming soon), we will be using the IJG jpeg library to load our textures. So after we add the line:

// include "jpeg.h"

We need to load in our texture. I am doing this after we load in our heightfield, in our Create function. So I am adding the line:

// SwiftTextureJpeg(tID, "texture.jpg", 0);

Where texture.jpg is the texture that will stretch over our terrain. Next is where our texturing comes into play. Just like texturing any other primitive shape in OpenGL, we need to enable texturing and bind our texture. So in our Render function, right before anything else, I am adding the lines:

// glEnable(GL_TEXTURE_2D);

// glBindTexture(GL_TEXTURE_2D, tID[0]);

Which will enable texturing and then bind are texture respectively. To finish off this, we need to disable texturing when we are done with our terrain, so we call:

// glDisable(GL_TEXTURE_2D);

At the end of our Render function. Now we need to take a look at our texture coordinates. At the moment, we have no texture coordinates, so in this tutorial we are going to dynamically compute them on the fly. This sounds really technical but it isn’t really. At the X = 0 coordinate on the map, our U coordinate for our texture is 0, and at the X = Width coordinate, our U coordinate for our texture is X / Width.

So at:
X = 0, U = 0;

Z = 0, V = 0;

X = 1024, U = 1; (X / Width = 1024 / 1024 = 1)
Z = 1024, V = 1; (Z / Height = 1024 / 1024 = 1)

Taking this into practice, our rendering code will now look like this:

// glTexCoord2f((float)hMapX / hmWidth, (float)hMapZ / hmHeight);
// glVertex3f(hMapX, hHeightField[hMapX][hMapZ], hMapZ);

// glTexCoord2f((float)hMapX / hmWidth, (float)(hMapZ + 1) / hmHeight);
// glVertex3f(hMapX, hHeightField[hMapX][hMapZ + 1], hMapZ + 1);

// glTexCoord2f((float)(hMapX + 1) / hmWidth, (float)hMapZ / hmHeight);
// glVertex3f(hMapX + 1, hHeightField[hMapX + 1][hMapZ], hMapZ);

// glTexCoord2f((float)(hMapX + 1) / hmWidth, (float)(hMapZ + 1) / hmHeight);

// glVertex3f(hMapX + 1, hHeightField[hMapX + 1][hMapZ + 1], hMapZ + 1);

And that is all we need to change in our heightfield.cpp 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.

  #include <stdio.h>
#include <gl\gl.h>

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

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

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

    
return true;
}

void SwiftHeightField::Render(void){
    
glEnable(GL_TEXTURE_2D);
    

glBindTexture(GL_TEXTURE_2D, tID[0]);
    

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

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

glTexCoord2f((float)hMapX / hmWidth, (float)hMapZ / hmHeight);
            

glVertex3f(hMapX, hHeightField[hMapX][hMapZ], hMapZ);
            

            
glTexCoord2f((float)hMapX / hmWidth, (float)(hMapZ + 1) / hmHeight) ;

            
glVertex3f(hMapX, hHeightField[hMapX][hMapZ + 1], hMapZ + 1);
            

            
glTexCoord2f((float)(hMapX + 1) / hmWidth, (float)hMapZ / hmHeight);

            
glVertex3f(hMapX + 1, hHeightField[hMapX + 1][hMapZ], hMapZ);
            

            
glTexCoord2f((float)(hMapX + 1) / hmWidth, (float)(hMapZ + 1) / hmHeight);

            
glVertex3f(hMapX + 1, hHeightField[hMapX + 1][hMapZ + 1], hMapZ + 1);
            

glEnd();
        
}
    
}
    

    
glDisable(GL_TEXTURE_2D);
}

Main.CPP File:

And guess what?! No changes need to be made to our main.cpp file :-)

Check out the next tutorial on rendering the heightfield using VBO’s (Vertex Buffer Objects) for speed optimizations 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.

  #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();
    

    
hField.Render();
    

    

glutSwapBuffers();
}

void Init (void) {
    
glEnable(GL_DEPTH_TEST);
    

glDepthFunc(GL_LEQUAL);
    

    
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

Downlaod 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: 10.0/10 (2 votes cast)
VN:F [1.9.3_1094]
Rating: 0 (from 0 votes)

7. Texturing in GLSL

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

Tags: , , , ,

6

Jump To:

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

Woo, congrats for making it this far. By now, you should know how to use basic shaders for lighting an object. So the next logical step would be to add some textures to our shape.

But first, because we are introducing a new type of shader variable, calld a Uniform variable, let me first explain it. A Uniform variable is a variable that we write to in our OpenGL application, and can then send through to a shader program. The Uniform variable can be an integer, a float, a vector, and even a matrix.

Because a texture is stored by OpenGL using an integer for identification, we will be sending through an integer variable to our shader by using Uniforms.

Main.CPP File:

The main.cpp is going to have some fairly minor changes. All of the texturing code itself is taken from previous tutorials, so I am going to jump to the stuff we haven’t seen before.

If you want to just jump to the cube() method (which by now draws a teapot because I didn’t rename the method, naughty me), you will notice 4 lines of code are used to setup our textures.

The first line is a call you should have seen from the multitexturing tutorial. We are going to tell OpenGL (and therefore GLSL0), that we are working with our texture unit 0.
    glActiveTexture(GL_TEXTURE0);

After deciding which texture we are going to use, we then need a variable that tells us the location of our texture variable in our shader. This is done with a call to glGetUniformLocation, and takes the paramters for the shader id, and the name of the variable inside the shader for our texture.
    int texture_location = glGetUniformLocation(shader.id(), “texture_color”);

Now that we know where our variable is inside the shader, we can then go ahead and set it. Because OpenGL uses numbers to identify the textures, we make a call to glUniform1i, which means we have a variable going into the shader (uniform), it is one value long (as opposed to a vec2 or vec3), and the value we are sending it is the first texture for our shader. The numbering for the textures in the shader, go from 0…n.
    glUniform1i(texture_location, 0);

And finally, we do what we always do when we are texturing, and we bind our texture that we want to use.
    glBindTexture(GL_TEXTURE_2D, texture);

This is fairly simple, but when dealing with multiple texture inputs to a shader, remember that you need to use the glActiveTexture calls in order, and then when you have finished with them, set the active textures in reverse order and disable texturing on each of the texture units to cleanup.

 

Feel free now to jump down to our shaders, and checkout the changes.

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.
  #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;

GLuint texture;

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

GLuint LoadTexture( const char * filename, int width, int height )
{
    GLuint texture;
    unsigned char * data;
    FILE * file;
    
    //The following code will read in our RAW file
    file = fopen( filename, “rb” );
    if ( file == NULL ) return 0;
    data = (unsigned char *)malloc( width * height * 3 );
    fread( data, width * height * 3, 1, file );
    fclose( file );
    
    glGenTextures( 1, &texture ); //generate the texture with the loaded 
data

    glBindTexture( GL_TEXTURE_2D, texture ); //bind the texture to it’s 
array

    glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, 
GL_MODULATE ); /
/set texture environment parameters

    
    //And if you go and use extensions, you can use Anisotropic filtering 
textures which are of an

    //even better quality, but this will do for now.
    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, 
GL_LINEAR);
    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, 
GL_LINEAR);
    
    //Here we are setting the parameter to repeat the texture instead of 
clamping the texture

    //to the edge of our shape. 
    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
    
    //Generate the texture
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, 
GL_UNSIGNED_BYTE, data);
    free( data ); //free the texture
    
    return texture; //return whether it was successfull
}

void FreeTexture( GLuint texture )
{
    glDeleteTextures( 1, &texture );
}

void init(void) {
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LESS);
    
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    
    shader.init(“shader.vert”, “shader.frag”);
    texture = LoadTexture(“texture.raw”, 256, 256);
}

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

    glActiveTexture(GL_TEXTURE0);
    int texture_location = glGetUniformLocation(shader.id(), “texture_color”);
    glUniform1i(texture_location, 0);
    glBindTexture(GL_TEXTURE_2D, texture);
    
    glutSolidTeapot(2.0);
}

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);
    
    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);
    
    glewInit();

    glutDisplayFunc(display);
    glutIdleFunc(display);
    
    glutReshapeFunc(reshape);
    
    init();
    
    glutMainLoop();
    
    return 0;
}

Vertex Shader Source:

In this tutorial, we are going to go back to our first shader that we ever made. So this shader will not be using lighting. Ontop of our base shader, all we need is one extra line in our vertex shader.

This line will write to the variable gl_TexCoord[0], the texture coordinates for the current vertex. The variable gl_TexCoord[0] is simply a varying variable between the vertex shader and the fragment shader.

This line is also where the calls to glActiveTexture start to make sense.

When we feed our texture coordinates through to OpenGL, GLSL stores them in the appropriate gl_MultiTexCoord(n) call. This allows us to set multiple uv coordinates per vertex, which is useful when multitexturing.

In the end, our one line needed in the vertex shader to enable texturing, is:
gl_TexCoord[0] = gl_MultiTexCoord0;

1.
2.
3.
4.
5.
6.
7.
  void main() {            
    gl_TexCoord[0] = gl_MultiTexCoord0;
    
    // Set the position of the current vertex 
    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}

 

Fragment Shader Source:

Our Fragment shader is also going to introduce one new line of code, but we are also going to modify another.

The line we want to add, will be used to setup the input location for our texture variable, and will give us a variable we can use to access the texture.

uniform sampler2D color_texture;

You may be wondering why the variable is of the type sampler2D, I honestly have no idea of the naming, I have never looked into it. But all you have to remember is that a sampler2D is code for a 2D texture. You can also get sampler1D’s and sampler3D’s, along with samplers for shadows and projections. But these are a little more advanced, and if all goes well, I’ll have some tutorials for them later.

Now as you know, we need to set the gl_FragColor from our fragment shader, so that we get something on the screen.

We are going to modify our original line to look like:
 gl_FragColor = texture2D(color_texture, gl_TexCoord[0].st);

This line means that we have a 2D texture that we are reading in, and this texture is associated with the color_texture variable, and finally we are calling the u,v coordinates for the current fragment.

When we are calling gl_TexCoord[0].st, it is good to remember that this variable is actually a vec4 variable with the values s, t, p and q. But we only want to use the first two values, s and t. Theoretically you can replace st with xy or even rg, to pull out the first two values, as it is only a vec4 variable. But switching the naming aroung like this can be confusing.

It is also good to keep in mind, that texture2D returns a vec4 variable, with the values for (red, green, blue and alpha). Which is perfect because gl_FragColor requires a vec4.

And thats all there is to texturing in GLSL. It is quite simple, I have just gone to the effort to over explain it for everyone :D

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

1.
2.
3.
4.
5.
6.
7.
  uniform sampler2D color_texture;

void main() {
    // Set the output color of our current pixel
    gl_FragColor = texture2D(color_texture, gl_TexCoord[0].st);
}

 

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.5/10 (4 votes cast)
VN:F [1.9.3_1094]
Rating: +1 (from 1 vote)

33. OpenGL Animating Textures

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

Tags: , , , ,

2

Some of you might be wondering about animating your textures. Well I have
some bad news for you. OpenGL does not support texture animation. So you
will have no luck loading in a Gif or Movie file into your application and
rendering it straight to your shape. But I also have some good news. There are
ways around this. And I am going to show you the way that I know.

Now my way consists of creating a different image file for every frame in your
animation. If you have a gif file, you can probably find an exporter through a
quick search on the internet to render out every frame from your animation.

So why don’t we get started.

I am only adding one extra variable which will control which frame we are
currently displaying for our animation. You will probably need another
variable for each animation you wish you use. And this variable is simple
enough to call. I am just using:
double frame;

Now we don’t have to set our frame to 0 at the start of our application
because if we do not set a value, it will default to 0.

So far so good?

After that I am then loading every frame when the application loads as a
new part of the texture array. There are 9 files in total, so I am loading
them as 0-8 in my array.
texture[0] = LoadTexture( “textures/1.raw”, 256, 256 );
texture[1] = LoadTexture( “textures/2.raw”, 256, 256 );
texture[2] = LoadTexture( “textures/3.raw”, 256, 256 );
texture[3] = LoadTexture( “textures/4.raw”, 256, 256 );
texture[4] = LoadTexture( “textures/5.raw”, 256, 256 );
texture[5] = LoadTexture( “textures/6.raw”, 256, 256 );
texture[6] = LoadTexture( “textures/7.raw”, 256, 256 );
texture[7] = LoadTexture( “textures/8.raw”, 256, 256 );
texture[8] = LoadTexture( “textures/9.raw”, 256, 256 );

Now if we go to our display function, this is where we are going to set the
texture to our quad. I am simply calling our Texture array as the texture, with
the array number being which frame of the animation we are on. The (int) is to
set our frame to an integer.
glBindTexture( GL_TEXTURE_2D, texture[(int)frame] );

Then I am going to add at the bottom of our display function, the code
that will update which frame we are currently on for the current animation.

So our function will look like:
Here we are increasing which frame of the animation we are on each pass of the
display function. Changing this number will change the speed of the animation.
frame+=0.2;
Now I am checking to see if the frame is above the maximum, and if it is,
change it back to the first frame for a steady loop.
if (frame > 8)
{
frame = 1;
}

And if you run this you will have an animation of a man whose arms spin around.

Well, have fun, but keep in mind that this can be time consuming. And I don’t
really see a use for it at this point in time.

If you have any questions, 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.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
191.
192.
193.
194.
195.
196.
197.
198.
199.
200.
201.
202.
203.
204.
205.
206.
207.
208.
209.
210.
211.
212.
213.
214.
215.
216.
217.
218.
219.
220.
221.
222.
223.
224.
225.
226.
227.
228.
229.
230.
231.
232.
  // Some of you might be wondering about animating your textures.
 Well I have

// some bad news for you. OpenGL does not support texture 
animation. So you

// will have no luck loading in a Gif or Movie file into your 
application and

// rendering it straight to your shape. But I also have some 
good news. There are

// ways around this. And I am going to show you the way that I 
know.

// Now my way consists of creating a different image file for 
every frame in your

// animation. If you have a gif file, you can probably find an 
exporter through a

// quick search on the internet to render out every frame from
 your animation.

// So why don’t we get started.

// I am only adding one extra variable which will control which
 frame we are

// currently displaying for our animation. You will probably
 need another

// variable for each animation you wish you use. And this 
variable is simple

// enough to call. I am just using:
// double frame;

// Now we don’t have to set our frame to 0 at the start of our 
application

// because if we do not set a value, it will default to 0.

// So far so good?

// After that I am then loading every frame when the application
 loads as a

// new part of the texture array. There are 9 files in total, so
 I am loading

// them as 0-8 in my array.
//    texture[0] = LoadTextureRAW( “textures/1.raw”, 256, 
256 );

//    texture[1] = LoadTextureRAW( “textures/2.raw”, 256, 
256 );

//    texture[2] = LoadTextureRAW( “textures/3.raw”, 256, 
256 );

//    texture[3] = LoadTextureRAW( “textures/4.raw”, 256, 
256 );

//    texture[4] = LoadTextureRAW( “textures/5.raw”, 256, 
256 );

//    texture[5] = LoadTextureRAW( “textures/6.raw”, 256, 
256 );

//    texture[6] = LoadTextureRAW( “textures/7.raw”, 256, 
256 );

//    texture[7] = LoadTextureRAW( “textures/8.raw”, 256, 
256 );

//    texture[8] = LoadTextureRAW( “textures/9.raw”, 256, 
256 );

// Now if we go to our display function, this is where we are 
going to set the

// texture to our quad. I am simply calling our Texture array 
as the texture, with

// the array number being which frame of the animation we are 
on. The (int) is to

// set our frame to an integer.
// glBindTexture( GL_TEXTURE_2D, texture[(int)frame] )
;

// Then I am going to add at the bottom of our display function,
 the code

// that will update which frame we are currently on for the 
current animation.

// So our function will look like:
// Here we are increasing which frame of the animation we are 
on each pass of the

// display function. Changing this number will change the 
speed of the animation.

//     frame+=0.2;
// Now I am checking to see if the frame is above the maximum, 
and if it is,

// change it back to the first frame for a steady loop.
//     if (frame > 8)
//        {
//     frame = 1;
//     }

// And if you run this you will have an animation of a man whose 
arms spin around.

// Well, have fun, but keep in mind that this can be time consuming.
 And I don’t

// really see a use for it at this point in time.

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

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

GLuint texture[8];

double frame;

GLuint LoadTexture( const char * filename, int width, int 
height )
{
    GLuint texture;
    unsigned char * data;
    FILE * file;

    //The following code will read in our RAW file
    file = fopen( filename, “rb” );
    if ( file == NULL ) return 0;
    data = (unsigned char *)malloc( width * height * 3 );
    fread( data, width * height * 3, 1, file );
    fclose( file );

    glGenTextures( 1, &texture ); //generate the texture with 
the loaded data

    glBindTexture( GL_TEXTURE_2D, texture ); //bind the texture
 to it’s array

    glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, 
GL_MODULATE ); //set texture environment parameters

    //here we are setting what textures to use and when. The MIN 
filter is which quality to show

    //when the texture is near the view, and the MAG filter is which
 quality to show when the texture

    //is far from the view.

    //The qualities are (in order from worst to best)
    //GL_NEAREST
    //GL_LINEAR
    //GL_LINEAR_MIPMAP_NEAREST
    //GL_LINEAR_MIPMAP_LINEAR

    //And if you go and use extensions, you can use Anisotropic 
filtering textures which are of an

    //even better quality, but this will do for now.
    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
 GL_LINEAR_MIPMAP_LINEAR );
    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
 GL_LINEAR_MIPMAP_LINEAR );

    //Here we are setting the parameter to repeat the texture 
instead of clamping the texture

    //to the edge of our shape. 
    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, 
GL_REPEAT );
    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, 
GL_REPEAT );

    //Generate the texture with mipmaps
    gluBuild2DMipmaps( GL_TEXTURE_2D, 3, width, height, 
GL_RGB, GL_UNSIGNED_BYTE, data );
    free( data ); //free the texture
    return texture; //return whether it was successfull
}

void FreeTexture( GLuint texture )
{
  glDeleteTextures( 1, &texture );
}

void cube (void) {
    glBindTexture( GL_TEXTURE_2D, texture[(int)frame] );
    glScalef(2,2,1);
    glBegin (GL_QUADS);
    glTexCoord2d(0,0);
    glVertex3f(-1,1,0);
    glTexCoord2d(1,0);
    glVertex3f(1,1,0);
    glTexCoord2d(1,1);
    glVertex3f(1,-1,0);
    glTexCoord2d(0,1);
    glVertex3f(-1,-1,0);
    glEnd();
}

void display (void) {
    glClearColor (0.0,0.0,0.0,1.0);
    glClear (GL_COLOR_BUFFER_BIT);
    glLoadIdentity();
    glEnable( GL_TEXTURE_2D );
    glTranslatef(0,0,-5);
    cube();
    glutSwapBuffers();
    frame+=0.2;
    if (frame > 8)
    {
    frame = 1;
    }
}
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);
}

void init (void) {
    texture[0] = LoadTexture( “textures/1.raw“, 256, 256 );
    texture[1] = LoadTexture( “textures/2.raw“, 256, 256 );
    texture[2] = LoadTexture( “textures/3.raw“, 256, 256 );
    texture[3] = LoadTexture( “textures/4.raw“, 256, 256 );
    texture[4] = LoadTexture( “textures/5.raw“, 256, 256 );
    texture[5] = LoadTexture( “textures/6.raw“, 256, 256 );
    texture[6] = LoadTexture( “textures/7.raw“, 256, 256 );
    texture[7] = LoadTexture( “textures/8.raw“, 256, 256 );
    texture[8] = LoadTexture( “textures/9.raw“, 256, 256 );
}

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

Download Textures(.RAW files in a Zip file)

Download Textures(.BMP files in a Zip file)

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: 8.5/10 (2 votes cast)
VN:F [1.9.3_1094]
Rating: +1 (from 1 vote)

31. OpenGL Sphere Creation

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

Tags: , , , ,

4

Fancy… Here we are going to create our own sphere without the use of
GLUT. I chose to write this tutorial, because I did not like the way
you could and could not texture the sphere created by GLUT and when
I looked on the internet, I could not find any tutorials on it. The advantage
of our sphere, is that we can set texture coordinates and if need be, place it
inside either a display list, vertex array, or vertex buffer object, allowing
us to call alot more than in immediate mode.

———————————————————————
Section 1: Variables

Now to start off, here are the variables we are going to be using:

This will hold our texture
GLuint texture[1];

This will just hold our angle of rotation
double angle = 0;

This here will hold the information of all our vertices, such as
x, y and z coordinates along with texture coordinates.
typedef struct
{

The x position of our current vertex
int X;
The Y position of our current vertex
int Y;
The Z position of our current vertex
int Z;

The U(x) texture coordinate of the current vertex
double U;
The V(x) texture coordinate of the current vertex
double V;
}VERTICES;

Next we are going to use PI to convert our angles in degrees to radians.
const double PI = 3.1415926535897;

This here is going to determine how far apart each of our vertices are
the further apart, the faster the program, but the squarer the sphere.
I chose 10 because it looks nice, and runs excellent.
const space = 10;

This will hold out total amount of vertices.
const VertexCount = (90 / space) * (360 / space) * 4;

Now we set up how many vertices we are going to use.
VERTICES VERTEX[VertexCount];

———————————————————————
Section 2: Enabling and Creating

Here I am enabling depth testing, texturing and face culling. The depth testing
is so that we acctually have depth to our scene, the texturing is so that
we can apply textures to our sphere, and culling to used to speed up the
application. I have set the front face for culling to Counter Clock Wise, as triangle
strips cull the opposite face to most other shapes.
glEnable(GL_DEPTH_TEST);
glEnable( GL_TEXTURE_2D );
glDepthFunc(GL_LEQUAL);
glCullFace(GL_BACK);
glFrontFace(GL_CCW);
glEnable(GL_CULL_FACE);

Now we load our texture to be used. It will be stored in texture[0]
texture[0] = LoadTextureRAW( “texture.raw” );

Now we call to create the sphere, I do not know why it does this, but the first
input seems to choose how many subdivisions to perform. The next lets you choose
where to move the sphere on the x, y and z axis.
CreateSphere(70,0,0,0);

Now for the actual creation code. We are inputting R as the number of subdivisions,
H as the translation on the horizontal axis, K as the translation on the vertical
axis, and Z as the translation on the Z axis.
void CreateSphere (double R, double H, double K, double Z) {
Now are variables for this is as followed. n is the current vertex we are working
with. While a and b are used to control our loops.
int n;
double a;
double b;

Set n to 0 to start off with the first vertex
n = 0;

Assign our b loop to go through 90 degrees in intervals of our variable space
for( b = 0; b <= 90 – space; b+=space){
Assign our a loop to go through 360 degrees in intervals of our variable space
for( a = 0; a <= 360 – space; a+=space){

Start editing our vertex.
I am calculating the X value here.
VERTEX[n].X = R * sin((a) / 180 * PI) * sin((b) / 180 * PI) – H;
The Y value here.
VERTEX[n].Y = R * cos((a) / 180 * PI) * sin((b) / 180 * PI) + K;
The Z value here.
VERTEX[n].Z = R * cos((b) / 180 * PI) – Z;
Now I am calculating the texture coordinates. I have used (2*b) as the texture
is twice as wide as it is high. Hence 2:1. You can remove the (2*) if you wish
to use a texture with the same width and height, or increase it accordingly.
VERTEX[n].V = (2 * b) / 360;
VERTEX[n].U = (a) / 360;

Then start working with the next vertex
n++;

Then we do the same calculations as before, only adding the space variable
to the b values.
VERTEX[n].X = R * sin((a) / 180 * PI) * sin((b + space) / 180 * PI) – H;
VERTEX[n].Y = R * cos((a) / 180 * PI) * sin((b + space) / 180 * PI) + K;
VERTEX[n].Z = R * cos((b + space) / 180 * PI) – Z;
VERTEX[n].V = (2 * (b + space)) / 360;
VERTEX[n].U = (a) / 360;
n++;

Then we do the same calculations as the first, only adding the space variable
to the a values.
VERTEX[n].X = R * sin((a + space) / 180 * PI) * sin((b) / 180 * PI) – H;
VERTEX[n].Y = R * cos((a + space) / 180 * PI) * sin((b) / 180 * PI) + K;
VERTEX[n].Z = R * cos((b) / 180 * PI) – Z;
VERTEX[n].V = (2 * b) / 360;
VERTEX[n].U = (a + space) / 360;
n++;

Then we do the same calculations as the first again, only adding the space variable
to both the b and the a values.
VERTEX[n].X = R * sin((a + space) / 180 * PI) * sin((b + space) / 180 * PI) – H;
VERTEX[n].Y = R * cos((a + space) / 180 * PI) * sin((b + space) / 180 * PI) + K;
VERTEX[n].Z = R * cos((b + space) / 180 * PI) – Z;
VERTEX[n].V = (2 * (b + space)) / 360;
VERTEX[n].U = (a + space) / 360;
n++;

}
}
}

———————————————————————————
Section 3: Displaying the Sphere

To display the sphere I am calling this funtion which will set the size of it
to 5 and assign the texture specified.
DisplaySphere(5, texture[0]);

This is the actual displaying code itself, it inputs the radius and texture
void DisplaySphere (double R, GLuint texture){
This variable will control which vertex we are currently working with
int b;

I have chosen to scale it here to 0.0125 times its original size, and then
increase it by R as the original sphere is rather large.
glScalef (0.0125 * R, 0.0125 * R, 0.0125 * R);

Now I am rotating it because, if you run it, it is sideways :)
glRotatef (90, 1, 0, 0);

Now I bind the texure we inputted above.
glBindTexture (GL_TEXTURE_2D, texture);

Now to begin drawing the sphere itself. I am drawing it with triangle strips
as they are the fastest shape for this.
glBegin (GL_TRIANGLE_STRIP);
Now I am looping through each vertex
for ( b = 0; b <= VertexCount; b++){
Assigning the texture coordinates of the current vertex
glTexCoord2f (VERTEX[b].U, VERTEX[b].V);
And the drawing the specified vertex with the Z coordinate inverted. Because
our creation code only draws half a sphere, which is why I am also doing
this loop again for the other half below.
glVertex3f (VERTEX[b].X, VERTEX[b].Y, -VERTEX[b].Z);
}

And here I do the same as above, only this time, I invert
the V(y) texture coordinate.
for ( b = 0; b <= VertexCount; b++){
glTexCoord2f (VERTEX[b].U, -VERTEX[b].V);
glVertex3f (VERTEX[b].X, VERTEX[b].Y, VERTEX[b].Z);
}

Then end the shape.
glEnd();
}

———————————————————————————
And there we have it. A textured sphere without the need for GLUT

If you have any questions, please 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.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
191.
192.

  #include <GL/gl.h>
#include <GL/glut.h>
#include <windows.h>
#include <stdio.h>
#include <math.h>
#include <iostream.h>

GLuint texture[1];

double angle = 0;

typedef struct 
{
    
int X;
    
int Y;
    
int Z;
    

    
double U;
    
double V;
}VERTICES;

const double PI = 3.1415926535897;

const space = 10;

const VertexCount = (90 / space) * (360 / space) * 4;

VERTICES VERTEX[VertexCount];

GLuint LoadTextureRAW( const char * filename );

void DisplaySphere (double R, GLuint texture){
    
int b;
    

    
glScalef (0.0125 * R, 0.0125 * R, 0.0125 * R);
    
    
    
glRotatef (90, 1, 0, 0);
    

    
glBindTexture (GL_TEXTURE_2D, texture);
    

    
glBegin (GL_TRIANGLE_STRIP);
    
for ( b = 0; b <= VertexCount; b++){
        
glTexCoord2f (VERTEX[b].U, VERTEX[b].V);
        
glVertex3f (VERTEX[b].X, VERTEX[b].Y, -VERTEX[b].Z);
    
}
    

    
for ( b = 0; b <= VertexCount; b++){
        
glTexCoord2f (VERTEX[b].U, -VERTEX[b].V);
        
glVertex3f (VERTEX[b].X, VERTEX[b].Y, VERTEX[b].Z);
    
}
    
glEnd();
}

void CreateSphere (double R, double H, double K, double Z) {
    
int n;
    
double a;
    
double b;
    

    
n = 0;
    

    
for( b = 0; b <= 90 - space; b+=space){
        
    for( a = 0; a <= 360 - space; a+=space){
            

            
VERTEX[n].X = R * sin((a) / 180 * PI) * sin((b) / 180 * PI) - H;
            
VERTEX[n].Y = R * cos((a) / 180 * PI) * sin((b) / 180 * PI) + K;
            
VERTEX[n].Z = R * cos((b) / 180 * PI) - Z;
            
VERTEX[n].V = (2 * b) / 360;
            
VERTEX[n].U = (a) / 360;
            
n++;
            

            
VERTEX[n].X = R * sin((a) / 180 * PI) * sin((b + space) / 180 * PI
            
) - H;
            
VERTEX[n].Y = R * cos((a) / 180 * PI) * sin((b + space) / 180 * PI
            
) + K;
            
VERTEX[n].Z = R * cos((b + space) / 180 * PI) - Z;
            
VERTEX[n].V = (2 * (b + space)) / 360;
            
VERTEX[n].U = (a) / 360;
            
n++;
            

            
VERTEX[n].X = R * sin((a + space) / 180 * PI) * sin((b) / 180 * PI
            
) - H;
            
VERTEX[n].Y = R * cos((a + space) / 180 * PI) * sin((b) / 180 * PI
            
) + K;
            
VERTEX[n].Z = R * cos((b) / 180 * PI) - Z;
            
VERTEX[n].V = (2 * b) / 360;
            
VERTEX[n].U = (a + space) / 360;
            
n++;
            

            
VERTEX[n].X = R * sin((a + space) / 180 * PI) * sin((b + space) /
            
180 * PI) - H;
            
VERTEX[n].Y = R * cos((a + space) / 180 * PI) * sin((b + space) /
            
180 * PI) + K;
            
VERTEX[n].Z = R * cos((b + space) / 180 * PI) - Z;
            
VERTEX[n].V = (2 * (b + space)) / 360;
            
VERTEX[n].U = (a + space) / 360;
            
n++;
            

            
    }
    
}
}

void display (void) {
    
    glClearDepth(1);
    
    glClearColor (0.0,0.0,0.0,1.0);
    
    glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
    glLoadIdentity();
    

    
    glTranslatef(0,0,-10);
    

    
    glRotatef(angle,0,1,0);
    
    DisplaySphere(5, texture[0]);
    

    
    glutSwapBuffers();
    
    angle ++;
}

void init (void) {
    
glEnable(GL_DEPTH_TEST);
    
glEnable( GL_TEXTURE_2D );
    
glDepthFunc(GL_LEQUAL);
    
glCullFace(GL_BACK);
    
glFrontFace(GL_CCW);
    
glEnable(GL_CULL_FACE);
    
texture[0] = LoadTextureRAW( “earth.raw” );
    
CreateSphere(70,0,0,0);
}
void reshape (int w, int h) {
    
    glViewport (0, 0, (GLsizei)w, (GLsizei)h);
    
    glMatrixMode (GL_PROJECTION);
    
    glLoadIdentity ();
    
    gluPerspective (60, (GLfloat)w / (GLfloat)h, 0.1, 100.0);
    
    glMatrixMode (GL_MODELVIEW);
}

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

GLuint LoadTextureRAW( const char * filename )
{
    
  GLuint texture;
    
  int width, height;
    
  unsigned char * data;
    
  FILE * file;
    

    
  file = fopen( filename, “rb” );
    
  if ( file == NULL ) return 0;
    

    
  width = 1024;
    
  height = 512;
    
  data = (unsigned char *)malloc( width * height * 3 );
    

    
  fread( data, width * height * 3, 1, file );
    
  fclose( file );
    

    
  glGenTextures( 1, &texture );
    

    
  glBindTexture( GL_TEXTURE_2D, texture );
    

    
  glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, 
    
GL_MODULATE );
    

    
  glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
    
 GL_LINEAR_MIPMAP_NEAREST );
    

    
  glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
    
 GL_LINEAR );
    

    
  glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, 
    
GL_REPEAT );
    
  glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, 
    
GL_REPEAT );
    

    
  gluBuild2DMipmaps( GL_TEXTURE_2D, 3, width, height, 
    
GL_RGB, GL_UNSIGNED_BYTE, data );
    

    
  free( data );
    

    
  return texture;
    

}

Download Sphere Texture(.RAW file)

Download Sphere Texture(.BMP file)

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.8/10 (8 votes cast)
VN:F [1.9.3_1094]
Rating: +2 (from 2 votes)

20. OpenGL MipMap Generation

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

Tags: , , , , ,

0

Mipmaps are a group of the same image, scaled to different sizes which are then selected according to how far away the viewer is.
 Instead of resizing the texture to fit the object on the fly,
 opengl will pick the mipmap that best fits the shape and textures
 it with that. This fixes dodgy looking textures, and smooths
 out the overall effect. Making a better looking image.

 To do this all we need is this line in our LoadTexture function:
 gluBuild2DMipmaps( GL_TEXTURE_2D, 3, width, height, GL_RGB, GL_UNSIGNED_BYTE, data );
 Instead of the line:
 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
 The ‘data’ being the texture, the width and height being the width and height
 of the texture file.

Then you just bind it like you would a normal texture.

But because we are now using mipmaps, we also want to change:
    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
 To
    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR );

Simply so that we can get better looking textures.

 And wasn’t that simple, we now have mipmaps :-D
 If you have any questions, please 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.
  #include <GL/gl.h>
#include <GL/glut.h>
#include <windows.h>
#include <stdio.h>

GLuint texture; //the array for our texture

GLfloat angle = 0.0;

GLuint LoadTexture( const char * filename, int width, int 
height )
{
    GLuint texture;
    unsigned char * data;
    FILE * file;

    //The following code will read in our RAW file
    file = fopen( filename, “rb” );
    if ( file == NULL ) return 0;
    data = (unsigned char *)malloc( width * height * 3 );
    fread( data, width * height * 3, 1, file );
    fclose( file );

    glGenTextures( 1, &texture ); //generate the texture with 
the loaded data

    glBindTexture( GL_TEXTURE_2D, texture ); //bind the texture
 to it’s array

    glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, 
GL_MODULATE ); //set texture environment parameters

    //here we are setting what textures to use and when. The MIN 
filter is which quality to show

    //when the texture is near the view, and the MAG filter is which
 quality to show when the texture

    //is far from the view.

    //The qualities are (in order from worst to best)
    //GL_NEAREST
    //GL_LINEAR
    //GL_LINEAR_MIPMAP_NEAREST
    //GL_LINEAR_MIPMAP_LINEAR

    //And if you go and use extensions, you can use Anisotropic 
filtering textures which are of an

    //even better quality, but this will do for now.
    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
 GL_LINEAR_MIPMAP_LINEAR );
    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
 GL_LINEAR_MIPMAP_LINEAR );

    //Here we are setting the parameter to repeat the texture 
instead of clamping the texture

    //to the edge of our shape. 
    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, 
GL_REPEAT );
    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, 
GL_REPEAT );

    //Generate the texture with mipmaps
    gluBuild2DMipmaps( GL_TEXTURE_2D, 3, width, height, 
GL_RGB, GL_UNSIGNED_BYTE, data );
    free( data ); //free the texture
    return texture; //return whether it was successfull
}

void FreeTexture( GLuint texture )
{
  glDeleteTextures( 1, &texture );
}

void square (void) {
    glBindTexture( GL_TEXTURE_2D, texture ); //bind our texture

    glPushMatrix();
    glRotatef( angle, 1.0f, 1.0f, 1.0f );
    glBegin (GL_QUADS);
    glTexCoord2d(0.0,0.0); glVertex2d(-1.0,-1.0);
    glTexCoord2d(1.0,0.0); glVertex2d(+1.0,-1.0);
    glTexCoord2d(1.0,1.0); glVertex2d(+1.0,+1.0);
    glTexCoord2d(0.0,1.0); glVertex2d(-1.0,+1.0);
    glEnd();
    glPopMatrix();
    glPushMatrix();
    glTranslatef( 0,0,-5 );
    glBegin (GL_QUADS);
    glTexCoord2d(0.0,0.0); glVertex2d(-1.0,-1.0);
    glTexCoord2d(1.0,0.0); glVertex2d(+1.0,-1.0);
    glTexCoord2d(1.0,1.0); glVertex2d(+1.0,+1.0);
    glTexCoord2d(0.0,1.0); glVertex2d(-1.0,+1.0);
    glEnd();
    glPopMatrix();
}

void display (void) {
    glClearColor (0.0,0.0,0.0,1.0);
    glClear (GL_COLOR_BUFFER_BIT);
    glLoadIdentity();  
    glEnable( GL_TEXTURE_2D ); //enable texturing
    gluLookAt (0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
    square();
    glutSwapBuffers();
    angle ++;
}
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);
    glutInitWindowSize (500, 500);
    glutInitWindowPosition (100, 100);
    glutCreateWindow (“A basic OpenGL Window);
    glutDisplayFunc (display);
    glutIdleFunc (display);
    glutReshapeFunc (reshape);

    texture = LoadTexture( “texture.raw”, 256, 256 ); //load our texture

    glutMainLoop ();

    FreeTexture( texture );

    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: 9.2/10 (6 votes cast)
VN:F [1.9.3_1094]
Rating: +1 (from 1 vote)

17. OpenGL Texture Coordinate Generation

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

Tags: , , , , ,

5

Texture coordinate generation is used when you are looking for particular effects in which it would take too long to work out the required texture coordinates all the time.

Examples of places you would use texture generation are: environment mapping and reflection mapping.

The very first thing that you need to do, is of course, enable the use of which texture
generation method you would like. There are four different types of textures you can generate, and they are:
GL_TEXTURE_GEN_S
GL_TEXTURE_GEN_R
GL_TEXTURE_GEN_T
GL_TEXTURE_GEN_Q

Also keep in mind that you can use
glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
with paramaters such as:
GL_EYE_LINEAR
GL_OBJECT_LINEAR

GL_SPHERE_MAP
GL_REFLECTION_MAP

Each one of these is used for a different method. But I will not mention them at this point in time, I may in the future if I want to explain more in this tutorial. But every method that is used here, can be done in a GLSL shader program.

Anyway, thats it for using texture coordinate generation, if you have any questions please email me at swiftless@gmail.com

Texture coordinate generation is used when you are looking for particular effects in which it would take too long to work out the required texture coordinates all the time.

Examples of places you would use texture generation are: environment mapping and reflection mapping.

The very first thing that you need to do, is of course, enable the use of which texture
generation method you would like. There are four different types of textures you can generate, and they are:
GL_TEXTURE_GEN_S
GL_TEXTURE_GEN_R
GL_TEXTURE_GEN_T
GL_TEXTURE_GEN_Q

Also keep in mind that you can use
glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
with paramaters such as:
GL_EYE_LINEAR
GL_OBJECT_LINEAR

GL_SPHERE_MAP
GL_REFLECTION_MAP

Each one of these is used for a different method. But I will not mention them at this point in time, I may in the future if I want to explain more in this tutorial. But every method that is used here, can be done in a GLSL shader program.

Anyway, thats it for using texture coordinate generation, if you have any questions please 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.
#include <GL/gl.h>
#include <GL/glut.h>
#include <windows.h>
#include <stdio.h>

GLuint texture; //the array for our texture

GLfloat angle = 0.0;

GLuint LoadTexture( const char * filename, int width, int
height )
{
GLuint texture;
unsigned char * data;
FILE * file;

//The following code will read in our RAW file
file = fopen( filename, “rb” );
if ( file == NULL ) return 0;
data = (unsigned char *)malloc( width * height *);
fread( data, width * height * 3, 1, file );
fclose( file );

glGenTextures( 1, &texture ); //generate the texture
with the loaded data

glBindTexture( GL_TEXTURE_2D, texture ); //bind the
texture to it’s array

glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE,
GL_MODULATE ); //set texture environment parameters

//here we are setting what textures to use and when. The
MIN filter is which quality to show

//when the texture is near the view, and the MAG filter is
which quality to show when the texture

//is far from the view.

//The qualities are (in order from worst to best)
//GL_NEAREST
//GL_LINEAR
//GL_LINEAR_MIPMAP_NEAREST
//GL_LINEAR_MIPMAP_LINEAR

//And if you go and use extensions, you can use Anisotropic
filtering textures which are of an

//even better quality, but this will do for now.
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
GL_LINEAR_MIPMAP_LINEAR );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
GL_LINEAR_MIPMAP_LINEAR );

//Here we are setting the parameter to repeat the texture
instead of clamping the texture

//to the edge of our shape.
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
GL_REPEAT );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
GL_REPEAT );

//Generate the texture with mipmaps
gluBuild2DMipmaps( GL_TEXTURE_2D, 3, width, height,
GL_RGB, GL_UNSIGNED_BYTE, data );
free( data ); //free the texture
return texture; //return whether it was successfull
}

void FreeTexture( GLuint texture )
{
glDeleteTextures( 1, &texture );
}

void cube (void) {
glBindTexture( GL_TEXTURE_2D, texture ); //bind the
texture

glRotatef( angle, 1.0f, 1.0f, 1.0f );
glutSolidCube(2);
}

void display (void) {
glClearColor (0.0,0.0,0.0,1.0);
glClear (GL_COLOR_BUFFER_BIT);
glLoadIdentity();
gluLookAt (0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
texture = LoadTexture( “texture.raw”, 256, 256 ); //load
the texture

glEnable( GL_TEXTURE_2D ); //enable 2D texturing
glEnable(GL_TEXTURE_GEN_S); //enable texture coordinate
generation

glEnable(GL_TEXTURE_GEN_T);
cube();
FreeTexture( texture );
glutSwapBuffers();
angle ++;
}

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);
glutInitWindowSize (500, 500);
glutInitWindowPosition (100, 100);
glutCreateWindow (“A basic OpenGL Window);
glutDisplayFunc (display);
glutIdleFunc (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: 6.6/10 (5 votes cast)
VN:F [1.9.3_1094]
Rating: +1 (from 1 vote)

16. OpenGL Texturing

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

Tags: , , ,

11

Because it is so much simpler at the moment, I am going to show you how to use
 textures under Windows only, the only thing is the actual, The original loading
 code I was using had it’s limitations so I have reworked it to make it more general.

 But back to the actual texturing, because it is under windows we have to include
 the windows header file, then we also need to add the stdio header file.

 using GLuint we create a variable for the texture, called ‘texture’, but you can call it
 whatever you wish.

 in the ‘display’ function we first set the variable ‘texture’ to the actual
 loaded image using:
 texture = LoadTexture( “texture.raw”, 256, 256 );
 where 256, 256 is the width and the height of the file respectively.
 then we enable the 2D Texturing, this is done with:
 glEnable( GL_TEXTURE_2D );
 and bind the texture with:
 glBindTexture( GL_TEXTURE_2D, texture );

 then after drawing everything we need with the texture, we clear it to save
 system resources.

 ——————————————————————————
 Section 1: The loading of the texture:

GLuint LoadTexture( const char * filename, int width, int height )
{
    GLuint texture;
    unsigned char * data;
    FILE * file;

 The following code will read in our RAW file
    file = fopen( filename, “rb” );  We need to open our file
    if ( file == NULL ) return 0;  If our file is empty, set our texture to empty


    data = (unsigned char *)malloc( width * height * 3 ); assign the nessecary memory for the texture


    fread( data, width * height * 3, 1, file );  read in our file
    fclose( file ); close our file, no point leaving it open

    glGenTextures( 1, &texture ); then we need to tell OpenGL that we are generating a texture
    glBindTexture( GL_TEXTURE_2D, texture ); now we bind the texture that we are working with
    glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); set texture environment parameters
 The parameter GL_MODULATE will blend the texture with whatever is underneath, setting it to GL_DECAL
 will tell the texture to replace whatever is on the object.

here we are setting what textures to use and when. The MIN filter is which quality to show
when the texture is near the view, and the MAG filter is which quality to show when the texture
is far from the view.

The qualities are (in order from worst to best)
GL_NEAREST
GL_LINEAR
GL_LINEAR_MIPMAP_NEAREST
GL_LINEAR_MIPMAP_LINEAR

 The two mipmap variables only work in textures with generated mipmaps, so you will see that in action
 in a later tutorial.

And if you go and use extensions, you can use Anisotropic filtering textures which are of an
even better quality, but this will do for now.

    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );

Here we are setting the parameter to repeat the texture instead of clamping the texture
to the edge of our shape.

    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );

Generate the texture
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);

    free( data ); free the texture
    return texture; return the texture data
}

——————————————————————————–
Section 2: Cleaning Up:

If we decide not to clean up after our work, you will find that the program will inevitably
slow down your computer, taking more and more memory.
void FreeTexture( GLuint texture )
{
  glDeleteTextures( 1, &texture );  Delete our texture, simple enough.
}

——————————————————————————-
Section 3: Texture Coordinates

This is how texture coordinates are arranged

  0,1   —–   1,1
       |     |
       |     |
       |     |
  0,0   —–   1,0

 With 0,0 being the bottom left and 1,1 being the top right.

 Now the point of using the value 0,1 instead of 0,10, is so that it is mapping 1 texture to the
 coordinates. Changing that to 10 would then try to map 10 textures to the one quad. Which because
 I have the repeat parameter set in our texture, it would draw 10 across and 10 down, if we had
 it clamped, we would be still drawing 1. The repeat function is good for things like
 brick walls.

 To assign texture coordinates to a vertex look at the following code:
glBegin (GL_QUADS);

glTexCoord2d(0.0,0.0);
with our vertices we have to assign a texcoord so that our texture has some points to draw to
glVertex2d(-1.0,-1.0);

glTexCoord2d(1.0,0.0);
glVertex2d(+1.0,-1.0);

glTexCoord2d(1.0,1.0);
glVertex2d(+1.0,+1.0);

glTexCoord2d(0.0,1.0);
glVertex2d(-1.0,+1.0);

glEnd();

For every vertex, we are assigning a texture coordinate that corresponds with it. Keep in mind
that this does not mean that if a vertex is a -10, 20, the texture coordinates will be -10, 20.
They will infact be something along the lines of 0,1.

———————————————————————

So now you should have a rough idea of the basics associated with texturing.
If you have any questions, feel free to 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.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
191.
192.
193.
194.
195.
196.
197.
198.
199.
200.
201.
202.
203.
204.
205.
206.
207.
208.
209.
210.
211.
212.
213.
214.
215.
216.
217.
218.
219.
220.
221.
222.
223.
224.
225.
226.
227.
228.
229.
230.
231.
232.
233.
234.
235.
236.
237.
238.
239.
240.
241.
242.
243.
244.
245.
246.
247.
248.
249.
250.
  // Because it is so much simpler at the moment, I am going to show
 you how to use

// textures under Windows only, the only thing is the actual,
 The original loading

// code I was using had it’s limitations so I have reworked it 
to make it more general.

// But back to the actual texturing, because it is under windows
 we have to include

// the windows header file, then we also need to add the stdio 
header file.

// using GLuint we create a variable for the texture, called 
‘texture’, but you can call it

// whatever you wish.

// in the ’display’ function we first set the variable ’texture’
 to the actual

// loaded image using:
// texture = LoadTexture( ”texture.raw”, 256, 256 );
// where 256, 256 is the width and the height of the file 
respectively.

// then we enable the 2D Texturing, this is done with:
// glEnable( GL_TEXTURE_2D );
// and bind the texture with:
// glBindTexture( GL_TEXTURE_2D, texture );

// then after drawing everything we need with the texture, we
 clear it to save

// system resources.

// ——————————————————————————

// Section 1: The loading of the texture:

//GLuint LoadTexture( const char * filename, int width, int
 height )

//{
//    GLuint texture;
//    unsigned char * data;
//    FILE * file;

// The following code will read in our RAW file
//    file = fopen( filename, ”rb” ); // We need to open our file
//    if ( file == NULL ) return 0; // If our file is empty, set our 
texture to empty

//    data = (unsigned char *)malloc( width * height * 3 ); //assign
 the nessecary memory for the texture

//    fread( data, width * height * 3, 1, file ); // read in our file

//    fclose( file ); //close our file, no point leaving it open

//    glGenTextures( 1, &texture ); //then we need to tell OpenGL
 that we are generating a texture

//    glBindTexture( GL_TEXTURE_2D, texture ); //now we bind 
the texture that we are working with

//    glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, 
GL_MODULATE ); //set texture environment parameters

// The parameter GL_MODULATE will blend the texture with 
whatever is underneath, setting it to GL_DECAL

// will tell the texture to replace whatever is on the object.

//here we are setting what textures to use and when. The MIN 
filter is which quality to show

//when the texture is near the view, and the MAG filter is which
 quality to show when the texture

//is far from the view.

//The qualities are (in order from worst to best)
//GL_NEAREST
//GL_LINEAR
//GL_LINEAR_MIPMAP_NEAREST
//GL_LINEAR_MIPMAP_LINEAR

// The two mipmap variables only work in textures with generated
 mipmaps, so you will see that in action

// in a later tutorial.

//And if you go and use extensions, you can use Anisotropic 
filtering textures which are of an

//even better quality, but this will do for now.

//    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
 GL_LINEAR );

//    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
 GL_LINEAR );

//Here we are setting the parameter to repeat the texture 
instead of clamping the texture

//to the edge of our shape. 

//    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, 
GL_REPEAT );

//    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, 
GL_REPEAT );

//Generate the texture
//    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height,
 0, GL_RGB, GL_UNSIGNED_BYTE, data);

//    free( data ); //free the texture
//    return texture; //return the texture data
//}

//——————————————————————————–

//Section 2: Cleaning Up:

//If we decide not to clean up after our work, you will find that
 the program will inevitably

//slow down your computer, taking more and more memory.
//void FreeTexture( GLuint texture )
//{
//  glDeleteTextures( 1, &texture ); // Delete our texture, 
simple enough.

//}

//——————————————————————————-

//Section 3: Texture Coordinates

//This is how texture coordinates are arranged
//
//  0,1   —–   1,1
//       |     |
//       |     |
//       |     |
//  0,0   —–   1,0

// With 0,0 being the bottom left and 1,1 being the top right.

// Now the point of using the value 0,1 instead of 0,10, is so 
that it is mapping 1 texture to the

// coordinates. Changing that to 10 would then try to map 10 
textures to the one quad. Which because

// I have the repeat parameter set in our texture, it would draw
 10 across and 10 down, if we had

// it clamped, we would be still drawing 1. The repeat function
 is good for things like

// brick walls.

// To assign texture coordinates to a vertex look at the 
following code:

//    glBegin (GL_QUADS);
//    glTexCoord2d(0.0,0.0); glVertex2d(-1.0,-1.0); //with
 our vertices we have to assign a texcoord

//  glTexCoord2d(1.0,0.0); glVertex2d(+1.0,-1.0); //so 
that our texture has some points to draw to

//  glTexCoord2d(1.0,1.0); glVertex2d(+1.0,+1.0);
//  glTexCoord2d(0.0,1.0); glVertex2d(-1.0,+1.0);
//    glEnd();

//For every vertex, we are assigning a texture coordinate 
that corresponds with it. Keep in mind

//that this does not mean that if a vertex is a -10, 20, the 
texture coordinates will be -10, 20. 

// They will infact be something along the lines of 0,1.

//———————————————————————

//So now you should have a rough idea of the basics associated
 with texturing.

//If you have any questions, feel free to email me at 
swiftless@gmail.com

#include <GL/gl.h>
#include <GL/glut.h>
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>

GLuint texture; //the array for our texture

GLfloat angle = 0.0;

//function to load the RAW file

GLuint LoadTexture( const char * filename, int width, int 
height )
{
    GLuint texture;
    unsigned char * data;
    FILE * file;

    //The following code will read in our RAW file
    file = fopen( filename, “rb” );
    if ( file == NULL ) return 0;
    data = (unsigned char *)malloc( width * height * 3 );
    fread( data, width * height * 3, 1, file );
    fclose( file );

    glGenTextures( 1, &texture ); //generate the texture with 
the loaded data

    glBindTexture( GL_TEXTURE_2D, texture ); //bind the texture
 to it’s array

    glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, 
GL_MODULATE ); //set texture environment parameters

    //here we are setting what textures to use and when. The MIN 
filter is which quality to show

    //when the texture is near the view, and the MAG filter is which
 quality to show when the texture

    //is far from the view.

    //The qualities are (in order from worst to best)
    //GL_NEAREST
    //GL_LINEAR
    //GL_LINEAR_MIPMAP_NEAREST
    //GL_LINEAR_MIPMAP_LINEAR

    //And if you go and use extensions, you can use Anisotropic 
filtering textures which are of an

    //even better quality, but this will do for now.
    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
 GL_LINEAR );
    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
 GL_LINEAR );

    //Here we are setting the parameter to repeat the texture 
instead of clamping the texture

    //to the edge of our shape. 
    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, 
GL_REPEAT );
    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, 
GL_REPEAT );

    //Generate the texture
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0,
 GL_RGB, GL_UNSIGNED_BYTE, data);
    free( data ); //free the texture
    return texture; //return whether it was successfull
}

void FreeTexture( GLuint texture )
{
  glDeleteTextures( 1, &texture );
}

void square (void) {
    glBindTexture( GL_TEXTURE_2D, texture ); //bind our texture
 to our shape

    glRotatef( angle, 1.0f, 1.0f, 1.0f );
    glBegin (GL_QUADS);
    glTexCoord2d(0.0,0.0); glVertex2d(-1.0,-1.0); //with 
our vertices we have to assign a texcoord

    glTexCoord2d(1.0,0.0); glVertex2d(+1.0,-1.0); //so that
 our texture has some points to draw to

    glTexCoord2d(1.0,1.0); glVertex2d(+1.0,+1.0);
    glTexCoord2d(0.0,1.0); glVertex2d(-1.0,+1.0);
    glEnd();

//This is how texture coordinates are arranged
//
//  0,1   —–   1,1
//       |     |
//       |     |
//       |     |
//  0,0   —–   1,0

// With 0,0 being the bottom left and 1,1 being the top right.

// Now the point of using the value 0,1 instead of 0,10, is so 
that it is mapping 1 texture to the

// coordinates. Changing that to 10 would then try to map 10 
textures to the one quad. Which because

// I have the repeat parameter set in our texture, it would draw
 10 across and 10 down, if we had

// it clamped, we would be still drawing 1. The repeat function
 is good for things like

// brick walls.
}

void display (void) {
    glClearColor (0.0,0.0,0.0,1.0);
    glClear (GL_COLOR_BUFFER_BIT);
    glLoadIdentity();
    glEnable( GL_TEXTURE_2D );
    gluLookAt (0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
    square();
    glutSwapBuffers();
    angle ++;
}
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);
    glutInitWindowSize (500, 500);
    glutInitWindowPosition (100, 100);
    glutCreateWindow (“A basic OpenGL Window);
    glutDisplayFunc (display);
    glutIdleFunc (display);
    glutReshapeFunc (reshape);

    //Load our texture
    texture = LoadTexture( “texture.raw”, 256, 256 );

    glutMainLoop ();

    //Free our texture
    FreeTexture( texture );

    return 0;
}

Download Texture(.RAW file)

Download Texture(.BMP file)

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: 5.4/10 (8 votes cast)
VN:F [1.9.3_1094]
Rating: +2 (from 2 votes)
Improve the web with Nofollow Reciprocity.