texturing problem

Started by
9 comments, last by Yours3!f 12 years, 11 months ago
Hi everyone,

as part of migrating to OGL 3.3 (from 2.1) I'm rewriting my code so that I throw out all the immediate mode stuff and use shaders etc. however I got stuck at texturing. I can successfully load the shader (link etc.), load the texture (a png file), load the mesh with the texture coordinates, I can pass the values to the video card through vbos, and also I can pass the uniforms and get them through OGL glGetUniformLocation() however when I'm rendering nothing appears on screen (except untextured stuff).

so here's my vertex shader:

/*
* texture.vs
*
*/
#version 330

//modelviewprojection, modelview matrices
uniform mat4 m4_p, m4_mv;

//the normal vector
in vec3 v3_normal;
//the vertex position
in vec4 v4_vertex;
//the texture coordinates
in vec2 v2_texture;

smooth out vec2 v2_texture_coords;

void main()
{
v2_texture_coords = v2_texture;
mat4 m4_mvp = m4_p * m4_mv;
gl_Position = m4_mvp * v4_vertex;
}


nothing special only passing the texture coordinates and the vertex information to the pixel shader.

here's the fragment shader:

/*
* texture.ps
*
*/
#version 330

uniform sampler2D texture_map;

smooth in vec2 v2_texture_coords;

out vec4 v4_frag_color;

void main()
{
v4_frag_color = texture(texture_map, v2_texture_coords.st);
}


again nothing special, I'm trying to draw the texture... (if I put in v4_frag_color = vec4(1.0); then the mesh does appear...)

here's the rendering code:

modelview_stack.push_matrix();

modelview_stack.translate_matrix(mymath::vec3f(0.0f, -100.0f, 0.0f));

the_pipeline.get_model_view_matrix().copy_m4x4_data(mv);
the_pipeline.get_projection_matrix().copy_m4x4_data(proj);;

texturing_shader.use_program();

glUniformMatrix4fv(glGetUniformLocation(texturing_shader.shader_program, texturing_shader.resources[0].name.c_str()), 1, false, proj);
glUniformMatrix4fv(glGetUniformLocation(texturing_shader.shader_program, texturing_shader.resources[1].name.c_str()), 1, false, mv);

//something is not right...
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, floor.texture);
glUniform1i(glGetUniformLocation(texturing_shader.shader_program, texturing_shader.resources[2].name.c_str()), 0);

draw_meshes(floor);

texturing_shader.return_to_fixed_program();

modelview_stack.pop_matrix();


any ideas what I did wrong?

Best regards,
Yours3!f
Advertisement
One good thing to check if you're not getting anything is to just draw your meshes with the texcoord as the color, bypassing the texture sample. This guarantees that your mesh is there and the texcoords are getting loaded correctly.

If that looks correct but your texture isn't working, then you have to look at the texture itself as a source of error.

How are you sure the texture is being loaded properly? Are you enabling/disabling mipmaps properly with glTexParameter?
[size=2]My Projects:
[size=2]Portfolio Map for Android - Free Visual Portfolio Tracker
[size=2]Electron Flux for Android - Free Puzzle/Logic Game
@karwosts

I tried checking it with tex coords like this:


/*
* texture.ps
*
*/
#version 330

uniform sampler2D texture_map;

smooth in vec2 v2_texture_coords;

out vec4 v4_frag_color;

void main()
{
//v4_frag_color = texture(texture_map, v2_texture_coords.st);
v4_frag_color = vec4(v2_texture_coords.st, 0.0, 0.0);
}


and the mesh became yellow.

I'm sure because with OGL 2.1 functions it worked.

I haven't messed with mipmaps yet, but when I enable them the result is the same.
(I took the mipmap generator from mesa and put it into a class, so that I'm not using the deprecated functions and I still have mipmapping)
When I mention mipmaps, I was referring to this:

http://www.opengl.org/wiki/Common_Mistakes#Creating_a_Texture

Make sure you disable mipmap filtering if you don't generate them. (You can generate mipmaps with non-deprecated function with glGenerateMipmap).

Anyway, its difficult to say if there's something wrong with your rendering code, would need to see vbo and texture initialization to be able to spot problems there.
[size=2]My Projects:
[size=2]Portfolio Map for Android - Free Visual Portfolio Tracker
[size=2]Electron Flux for Android - Free Puzzle/Logic Game

and the mesh became yellow.


If it is yellow, then you have a texcoord problem. It should be from red to green to yellow to black.
Sig: http://glhlib.sourceforge.net
an open source GLU replacement library. Much more modern than GLU.
float matrix[16], inverse_matrix[16];
glhLoadIdentityf2(matrix);
glhTranslatef2(matrix, 0.0, 0.0, 5.0);
glhRotateAboutXf2(matrix, angleInRadians);
glhScalef2(matrix, 1.0, 1.0, -1.0);
glhQuickInvertMatrixf2(matrix, inverse_matrix);
glUniformMatrix4fv(uniformLocation1, 1, FALSE, matrix);
glUniformMatrix4fv(uniformLocation2, 1, FALSE, inverse_matrix);
@V-man

you're right it is...
however I can't find the problem...

here's the vbo init:

void render::fill_vbos(mesh& the_mesh)
{
typedef GLfloat float_3[3]; //so that we have one type with 3 components
typedef GLfloat float_2[2];

float_3* tmp_vertices; //temporary data that will be updated to the VGA
float_3* tmp_normals;
GLuint* tmp_faces;
float_2* tmp_tex_coords;

tmp_vertices = new float_3[the_mesh.faces.size() * 3]; //we allocate space for every face we have
tmp_normals = new float_3[the_mesh.faces.size() * 3];
tmp_faces = new uint[the_mesh.faces.size() * 3];
tmp_tex_coords = new float_2[the_mesh.faces.size() * 3];

the_mesh.numindexes = 0;

int num_index = -1; //this is our face counter

for (int c = 0; c < the_mesh.faces.size(); c++) //for every face
{
for (int i = 0; i < 3; i++) //for every vertex in each face
{
num_index++; //increase the face counter so that it points to the actual face (1st is 0)
for (int j = 0; j < 3; j++) //for every component in each vertex
{
tmp_vertices[num_index][j] = the_mesh.vertices[the_mesh.faces[c][i * 3] - 1][j]; //copy the associated vertex & normal data
tmp_normals[num_index][j] = the_mesh.normals[the_mesh.faces[c][i * 3 + 2] - 1][j];
}

if (the_mesh.tex_coords.size() > 0) //if we have tex coords, otherwise we'd have random values, and probably tex_coords doesn't have that much elements or it'd point to negative values...
{
tmp_tex_coords[num_index][0] = the_mesh.tex_coords[the_mesh.faces[c][i * 3 + 1] - 1][0]; //copy tex coords if we have some
tmp_tex_coords[num_index][1] = the_mesh.tex_coords[the_mesh.faces[c][i * 3 + 1] - 1][1];
}
tmp_faces[c * 3 + i] = num_index; //copy the index of the actual face (it'll be from 0 to the_mesh.faces.size() - 1, incremented always by 1 like 0, 1, 2, 3, ... (if I find out how to draw stuff without them, then they're useless, I mean they're in order the video card should just loop through them))
}
}

the_mesh.numindexes = num_index + 1; //assing the actual number of faces we'll upload to the VGA

glGenBuffers(4, the_mesh.vbos); //generate the VBOs (vertex, normal, tex coord, indices)

// Copy data to video memory
// Vertex data
glBindBuffer(GL_ARRAY_BUFFER, the_mesh.vbos[the_mesh.VERTEX_VBO]); //pass data to the VGA
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat)*the_mesh.numindexes*3, tmp_vertices, GL_STATIC_DRAW);

// Normal data
glBindBuffer(GL_ARRAY_BUFFER, the_mesh.vbos[the_mesh.NORMAL_VBO]);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat)*the_mesh.numindexes*3, tmp_normals, GL_STATIC_DRAW);

// Texture coordinates
glBindBuffer(GL_ARRAY_BUFFER, the_mesh.vbos[the_mesh.TEXTURE_VBO]);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat)*the_mesh.numindexes*2, tmp_tex_coords, GL_STATIC_DRAW);

// Indexes
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, the_mesh.vbos[the_mesh.FACE_VBO]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint)*the_mesh.numindexes, tmp_faces, GL_STATIC_DRAW);

delete [] tmp_vertices; //free up the temporary arrays
delete [] tmp_normals;
delete [] tmp_faces;
delete [] tmp_tex_coords;

tmp_vertices = NULL;
tmp_normals = NULL;
tmp_faces = NULL;
tmp_tex_coords = NULL;
}



and here's the texture init:

void image_loader::load_image_file(std::string filename, mesh& image_mesh, image_type type)
{
image_timer.add_timer(); //start the timer (not important)
image_timer.set_timerbegin();
if (type == TEXTURE) //if it is texture (I load the texture in this mode)
{
load_image(filename.c_str()); //then load the image based on the filename
image_mesh.tex_width = width; //store its width & height (we might need them later)
image_mesh.tex_height = height;
image_mesh.texture = texture_loader(return_value, image_mesh.tex_width, image_mesh.tex_height); //and upload the texture to VGA
}
else if (type == MIPMAPPED_TEXTURE)
{
load_image(filename.c_str());
image_mesh.tex_width = width;
image_mesh.tex_height = height;
image_mesh.texture = mip_texture_loader(return_value, image_mesh.tex_width, image_mesh.tex_height);
}
else if (type == CUBEMAP_TEXTURE)
{
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);

glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_GENERATE_MIPMAP, GL_TRUE);
load_image(filename.c_str());
image_mesh.tex_width = width;
image_mesh.tex_height = height;
image_mesh.texture = cube_texture_loader(return_value, image_mesh.tex_width, image_mesh.tex_height, image_mesh.tex_flag);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_GENERATE_MIPMAP, GL_FALSE);
}
std::cout << " Loaded in: " << image_timer.get_time_passed() / 1000.0f << " seconds\n";
}

void image_loader::load_image(const char* filename) //loading a image file with freeimage
{

std::cout << "-Loading: " << filename << "\n";

// Get the image file type from FreeImage.
FREE_IMAGE_FORMAT file_format = FreeImage_GetFileType(filename, 0); //get the file format

// Actually load the image file.
FIBITMAP *dib = FreeImage_Load(file_format, filename, 0); //load the file based on the file format & the filename

// Now, there is no guarantee that the image file
// loaded will be GL_RGBA, so we force FreeImage to
// convert the image to GL_RGBA.
dib = FreeImage_ConvertTo32Bits(dib); //we only want RGBA textures, so that our life will be easier

if ( dib != NULL ) //if it did load the texture
{
// This is important to note, FreeImage loads textures in
// BGR format. Now we could just use the GL_BGR extension
// But, we will simply swap the B and R components ourselves.
// Firstly, allocate the new bit data doe the image.
BYTE* bits = new BYTE[FreeImage_GetWidth(dib) * FreeImage_GetHeight(dib) * 4]; //then allocate space for each pixel

// get a pointer to FreeImage's data.
BYTE* pixels = FreeImage_GetBits(dib);

// Iterate through the pixels, copying the data
// from 'pixels' to 'bits' except in RGB format.
for (int pix = 0; pix < FreeImage_GetWidth(dib) * FreeImage_GetHeight(dib); pix++) //freeimage loads the images in a wierd color order, so I had to figure it out how to convert them to a proper color order (RGBA)
{
bits[pix * 4 + 0] = pixels[pix * 4 + 3]; //r = 3
bits[pix * 4 + 1] = pixels[pix * 4 + 0]; //g = 0
bits[pix * 4 + 2] = pixels[pix * 4 + 1]; //b = 1
bits[pix * 4 + 3] = pixels[pix * 4 + 2]; //a = 2
}

// and free the bit data.
return_value = bits;
width = FreeImage_GetWidth(dib);
height = FreeImage_GetHeight(dib);

}
}

GLuint image_loader::texture_loader(BYTE* texture, int width, int height) //this is called to upload the texture to the VGA
{
GLuint tex_id;
glGenTextures(1, &tex_id);
glBindTexture(GL_TEXTURE_2D, tex_id);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, texture); //now we really can use RGBA format, hoooray!
return tex_id;
}


I call them like this:
render::fill_vbos(floor);
floor_texture.load_image_file("checker.png", floor, image_loader::TEXTURE);

that's how I render them:

void render::draw_meshes_vbo(const mesh& the_mesh)
{
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY); //just enable the VBOs and draw them

// Here's where the data is now
glBindBuffer(GL_ARRAY_BUFFER, the_mesh.vbos[the_mesh.VERTEX_VBO]);
glVertexPointer(3, GL_FLOAT,0, 0);

// Normal data
glBindBuffer(GL_ARRAY_BUFFER, the_mesh.vbos[the_mesh.NORMAL_VBO]);
glNormalPointer(GL_FLOAT, 0, 0);

// Texture coordinates
glBindBuffer(GL_ARRAY_BUFFER, the_mesh.vbos[the_mesh.TEXTURE_VBO]);
glTexCoordPointer(2, GL_FLOAT, 0, 0);

// Indexes
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, the_mesh.vbos[the_mesh.FACE_VBO]);
glDrawElements(GL_TRIANGLES, the_mesh.numindexes, GL_UNSIGNED_INT, 0);

glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}


calling it like this:

modelview_stack.push_matrix();

modelview_stack.translate_matrix(mymath::vec3f(0.0f, -100.0f, 0.0f)); //we move the mesh below the camera, so that I can see it when I look down

the_pipeline.get_model_view_matrix().copy_m4x4_data(mv); //we copy the modelview & projection matrix data to normal float arrays so that we can pass them to the shaders
the_pipeline.get_projection_matrix().copy_m4x4_data(proj);

texturing_shader.use_program(); //use the shader

glUniformMatrix4fv(glGetUniformLocation(texturing_shader.shader_program, texturing_shader.resources[0].name.c_str()), 1, false, proj); //pass the matrices to the shader
glUniformMatrix4fv(glGetUniformLocation(texturing_shader.shader_program, texturing_shader.resources[1].name.c_str()), 1, false, mv);

//something is not right...
glActiveTexture(GL_TEXTURE0); //make the texture "active"
glBindTexture(GL_TEXTURE_2D, floor.texture); //bind it
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL); //set the settings so that it will repeat itself on the surface (floor)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glUniform1i(glGetUniformLocation(texturing_shader.shader_program, texturing_shader.resources[2].name.c_str()), 0); //lets pass the texture

draw_meshes_vbo(floor); //draw the mesh

texturing_shader.return_to_fixed_program(); //return to fixed functionality (I dont really know if it has an effect in OGL 3.3)

modelview_stack.pop_matrix();
You would have to look into your tmp_tex_coords array to find out. The code is too complex for me to know what it is doing.
Sig: http://glhlib.sourceforge.net
an open source GLU replacement library. Much more modern than GLU.
float matrix[16], inverse_matrix[16];
glhLoadIdentityf2(matrix);
glhTranslatef2(matrix, 0.0, 0.0, 5.0);
glhRotateAboutXf2(matrix, angleInRadians);
glhScalef2(matrix, 1.0, 1.0, -1.0);
glhQuickInvertMatrixf2(matrix, inverse_matrix);
glUniformMatrix4fv(uniformLocation1, 1, FALSE, matrix);
glUniformMatrix4fv(uniformLocation2, 1, FALSE, inverse_matrix);
I have printed them out on screen and according to the OBJ file they're OK.
btw I edited my previous post, it is now heavily commented (hope it helps)

EDIT:
with old OGL 2.1 functions I tried to display the texture, and I could so the problem is definitely not related to loading the image.
You're using glTexCoordPointer with "in vec2 v2_texture;", that's not going to work. glTexCoordPointer only sends data to one special input variable (gl_MultiTexCoord[0] or something, can't quite remember).

Anyway that's deprecated anyway so you shouldn't be using it (or glVertexPointer, or glNormalPointer).

What you want to do is call glGetAttribLocation, and then use glVertexAttribPointer with your vertices, normals, and texcoords.

Also replace glEnableClientState with glEnableVertexAttribArray.
[size=2]My Projects:
[size=2]Portfolio Map for Android - Free Visual Portfolio Tracker
[size=2]Electron Flux for Android - Free Puzzle/Logic Game
In that case http://www.opengl.org/wiki/GlVertexAttribPointer
Sig: http://glhlib.sourceforge.net
an open source GLU replacement library. Much more modern than GLU.
float matrix[16], inverse_matrix[16];
glhLoadIdentityf2(matrix);
glhTranslatef2(matrix, 0.0, 0.0, 5.0);
glhRotateAboutXf2(matrix, angleInRadians);
glhScalef2(matrix, 1.0, 1.0, -1.0);
glhQuickInvertMatrixf2(matrix, inverse_matrix);
glUniformMatrix4fv(uniformLocation1, 1, FALSE, matrix);
glUniformMatrix4fv(uniformLocation2, 1, FALSE, inverse_matrix);

This topic is closed to new replies.

Advertisement