PDA

View Full Version : (3.2) Texture coords problem



rsp91
10-16-2009, 05:24 PM
Hi I've written this OpenGL 3.2 / GLSL 1.50 core app to display a triangle with a texture on it but it only renders in one color. Probably because a problem with texture coords? No OpenGL error code is set! So it must be logic.

http://img382.imageshack.us/img382/3366/skrmbildfoo.png


#define GL3_PROTOTYPES
#include <GL3/gl3.h>
#include <SDL/SDL.h>
#include <SDL/SDL_image.h>
#include <glm/gtx.hpp>
#include <iostream>
#include <fstream>
#include <stack>

namespace glm {
using namespace gtx;

namespace gtx {
using namespace transform2;
}
}

void glError(const char *file, int line) {
GLenum err{glGetError()};

while(err!=GL_NO_ERROR) {
std::string error;

switch(err) {
case GL_INVALID_OPERATION: error="INVALID_OPERATION"; break;
case GL_INVALID_ENUM: error="INVALID_ENUM"; break;
case GL_INVALID_VALUE: error="INVALID_VALUE"; break;
case GL_OUT_OF_MEMORY: error="OUT_OF_MEMORY"; break;
}

std::cerr<<"GL_"<<error<<" - "<<file<<':'<<line<<std::endl;
err=glGetError();
}
}

int main() {
//Initialization
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION,3 );
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION,2 );
SDL_Init(SDL_INIT_VIDEO);

const int r_width{640},r_height{480};
SDL_WindowID window{SDL_CreateWindow("Foo",SDL_WINDOWPOS_CENTERED,SDL_WINDOWPOS_CENTERED,r_w idth,r_height,SDL_WINDOW_OPENGL|SDL_WINDOW_SHOWN)} ;
SDL_GLContext glcontext{SDL_GL_CreateContext(window)};

std::cout<<"OpenGL "<<glGetString(GL_VERSION)<<" (GLSL "<<glGetString(GL_SHADING_LANGUAGE_VERSION)<<')'<<std::endl;

//Load texture
SDL_Surface *imagesurface{IMG_Load("Lenna.png")};
GLuint textureid;

glGenTextures(1,&amp;textureid);
glBindTexture(GL_TEXTURE_2D,textureid);

glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTE R,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTE R,GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D,0,GL_RGB,imagesurface->w,imagesurface->h,0,GL_RGB,GL_UNSIGNED_BYTE,imagesurface->pixels);

SDL_FreeSurface(imagesurface);

//Create shaders and shader program
GLuint vshader{glCreateShader(GL_VERTEX_SHADER)},fshader{ glCreateShader(GL_FRAGMENT_SHADER)};
GLuint program{glCreateProgram()};

{
std::ifstream source_file{"image.vert"};

std::string data;
std::getline(source_file,data,'\0');

const GLchar *vshader_source{data.c_str()};

glShaderSource(vshader,1,&amp;vshader_source,NULL);
}

{
std::ifstream source_file{"image.frag"};

std::string data;
std::getline(source_file,data,'\0');

const GLchar *fshader_source{data.c_str()};

glShaderSource(fshader,1,&amp;fshader_source,NULL);
}

glCompileShader(vshader);
glCompileShader(fshader);

glAttachShader(program,vshader);
glAttachShader(program,fshader);
glLinkProgram(program);

GLint matrixloc{glGetUniformLocation(program,"projmat")};
GLint matrix2loc{glGetUniformLocation(program,"modelmat")};

//Create geometry
GLuint tris,coords,vao;
const GLfloat vertices[3*2]{0.0f,0.0f, 0.0f,1.0f, 1.0f,1.0f};
const GLfloat texcoords[3*2]{0.0f,0.0f, 0.0f,1.0f, 1.0f,1.0f};

glGenVertexArrays(1,&amp;vao);
glBindVertexArray(vao);

glGenBuffers(1,&amp;tris);
glBindBuffer(GL_ARRAY_BUFFER,tris);
glBufferData(GL_ARRAY_BUFFER,sizeof(vertices),&amp;ver tices[0],GL_STATIC_DRAW);

const GLint location{glGetAttribLocation(program,"vert")};
glVertexAttribPointer(location,2,GL_FLOAT,GL_FALSE ,0,NULL);
glEnableVertexAttribArray(location);

glGenBuffers(1,&amp;coords);
glBindBuffer(GL_ARRAY_BUFFER,coords);
glBufferData(GL_ARRAY_BUFFER,sizeof(texcoords),&amp;te xcoords[0],GL_STATIC_DRAW);

const GLint coordloc{glGetAttribLocation(program,"texcoord")};
glVertexAttribPointer(coordloc,2,GL_FLOAT,GL_FALSE ,0,NULL);
glEnableVertexAttribArray(coordloc);

GLint texloc{glGetUniformLocation(program,"tex")};

//Render
glm::mat4 projmat;
glm::mat4 modelmat;

projmat*=glm::perspective(45.0f, float(r_width/r_height), 0.1f, 100.0f);
modelmat*=glm::translate(glm::vec3{0.0f,5.0f,0.0f} );

glUseProgram(program);

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D,textureid);
glUniform1i(texloc,0);

glUniformMatrix4fv(matrixloc,1,GL_TRUE,&amp;projmat[0][0]);
glUniformMatrix4fv(matrix2loc,1,GL_TRUE,&amp;modelmat[0][0]);

glBindVertexArray(vao);
glDrawArrays(GL_TRIANGLES,0,3);

glError(__FILE__,__LINE__);
SDL_GL_SwapWindow(window);
SDL_Delay(600);

//Quit
glDeleteShader(vshader);
glDeleteShader(fshader);
glDeleteProgram(program);
glDeleteTextures(1,&amp;textureid);
SDL_GL_DeleteContext(glcontext);
SDL_DestroyWindow(window);
SDL_Quit();
}


#version 150

uniform mat4 projmat;
uniform mat4 modelmat;
in vec2 vert;
in vec2 texcoord;
out vec2 coord;

void main() {
coord=texcoord;
gl_Position=projmat*modelmat*vec4(vert,0,0);
}


#version 150

uniform sampler2D tex;
in vec2 coord;
out vec4 color;

void main() {
color=texture(tex,coord);
}

marshats
10-16-2009, 11:22 PM
I don't quite understand this but I changed the vertex shader line by changing the last 0 to 1:


gl_Position=projmat*modelmat*vec4(vert,0.,1.);

and in the c-code I had to change your perspective/translate code in the render function. I tried SDL_image but it failed with my image (frac.png since I don't have your Leena.png file) file so I replaced it with devIL image library. Note, the image file has to be a power of 2, my frac.png file is 2^9x2^9pixels. Is your png an even power of 2 also? ... It is just easier to give you the code that worked for me


#version 150

uniform mat4 projmat;
uniform mat4 modelmat;
in vec2 vert;
in vec2 texcoord;
out vec2 coord;

void main() {
coord=texcoord;
gl_Position=projmat*modelmat*vec4(vert,0.,1.);
}



#version 150

uniform sampler2D tex;
smooth in vec2 coord;
out vec4 color;

void main() {
color=texture(tex,coord);
}



#define GL3_PROTOTYPES
#include <GL3/gl3.h>
#include <SDL.h>
#include <SDL/SDL_image.h>
#include <iostream>
#include <fstream>
#include <stack>

//OpenGL Mathematics (GLM). A C++ mathematics library for 3D graphics.
#include <glm/glm.h>
#include <glm/glmext.h>
#include <glm/GLM_VIRTREV_address.h> // gives helper function address(X) instead of using &amp;X[0][0]
namespace glm
{
// read glm/gtx/transform.h for function prototypes
using GLM_GTX_transform;
using GLM_GTX_matrix_projection;
using GLM_GTX_transform2; // for lookAt
}
using namespace glm;

#include <IL/ilut.h> //http://openil.sourceforge.net/tuts/tut_step/index.htm

struct TextureHandle {
ILubyte *p; /* pointer to image data loaded into memory */
ILuint id; /* unique DevIL id of image */
ILint w; /* image width */
ILint h; /* image height */
};
TextureHandle frac;

//---+----3----+----2----+----1----+---><---+----1----+----2----+----3----+----4
//---------------------------- LoadImageDevIL ------------------------------

// use devIL, cross platform image loading library(openil.sourceforge.net/about.php)

ILuint LoadImageDevIL (char *szFileName, struct TextureHandle *T)
{
//When IL_ORIGIN_SET enabled, the origin is specified at an absolute
//position, and all images loaded or saved adhere to this set origin.
ilEnable(IL_ORIGIN_SET);
//sets the origin to be IL_ORIGIN_LOWER_LEFT when loading all images, so
//that any image with a different origin will be flipped to have the set
//origin.
ilOriginFunc(IL_ORIGIN_LOWER_LEFT);

//Now load the image file
ILuint ImageNameID;
ilGenImages(1, &amp;ImageNameID);
ilBindImage(ImageNameID);
if (!ilLoadImage(szFileName)) return 0; // failure

T->id = ImageNameID;
T->p = ilGetData();
T->w = ilGetInteger(IL_IMAGE_WIDTH);
T->h = ilGetInteger(IL_IMAGE_HEIGHT);

printf("%s %d %d %d\n",szFileName,T->id,T->w,T->h);
return 1; // success
}


//---+----3----+----2----+----1----+---<>---+----1----+----2----+----3----+----4
//--------------------------- cleanup_images -------------------------------

// Clear out the memory used by loading image files.

void cleanup_images(void) {
printf("cleanup image memory:{");

if (frac.id) {
printf(" %d",frac.id);
ilDeleteImages(1, &amp;frac.id);
}

printf(" }\n");
}


void glError(const char *file, int line) {
GLenum err(glGetError());

while(err!=GL_NO_ERROR) {
std::string error;

switch(err) {
case GL_INVALID_OPERATION: error="INVALID_OPERATION"; break;
case GL_INVALID_ENUM: error="INVALID_ENUM"; break;
case GL_INVALID_VALUE: error="INVALID_VALUE"; break;
case GL_OUT_OF_MEMORY: error="OUT_OF_MEMORY"; break;
}

std::cerr<<"GL_"<<error<<" - "<<file<<':'<<line<<std::endl;
err=glGetError();
}
}

int main() {
ilInit();
assert( LoadImageDevIL ((char*)"Frac.png", &amp;frac) );

//Initialization
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION,3 );
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION,2 );
SDL_Init(SDL_INIT_VIDEO);

const int r_width(640),r_height(480);
SDL_WindowID window(SDL_CreateWindow("Foo",SDL_WINDOWPOS_CENTERED,SDL_WINDOWPOS_CENTERED,r_w idth,r_height,SDL_WINDOW_OPENGL|SDL_WINDOW_SHOWN)) ;
SDL_GLContext glcontext(SDL_GL_CreateContext(window));

std::cout<<"OpenGL "<<glGetString(GL_VERSION)<<" (GLSL "<<glGetString(GL_SHADING_LANGUAGE_VERSION)<<')'<<std::endl;

//Load texture
// SDL_Surface *imagesurface(IMG_Load("Frag.png"));
GLuint textureid;

glGenTextures(1,&amp;textureid);
glBindTexture(GL_TEXTURE_2D,textureid);

glTexImage2D (GL_TEXTURE_2D, 0, 3, frac.w, frac.h, 0, GL_RGB, GL_UNSIGNED_BYTE, frac.p);
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_MIPMAP_LINEAR );
glTexImage2D (GL_TEXTURE_2D, 0, 3, frac.w, frac.h, 0, GL_BGR, GL_UNSIGNED_BYTE, frac.p);
//glTexImage2D(GL_TEXTURE_2D,0,GL_RGB,imagesurface->w,imagesurface->h,0,GL_RGB,GL_UNSIGNED_BYTE,imagesurface->pixels);
glGenerateMipmap(GL_TEXTURE_2D); //Generate mipmaps now!!!


// SDL_FreeSurface(imagesurface);

//Create shaders and shader program
GLuint vshader(glCreateShader(GL_VERTEX_SHADER)),fshader( glCreateShader(GL_FRAGMENT_SHADER));
GLuint program(glCreateProgram());

{
std::ifstream source_file("image.vert");

std::string data;
std::getline(source_file,data,'\0');

const GLchar *vshader_source(data.c_str());

glShaderSource(vshader,1,&amp;vshader_source,NULL);
}

{
std::ifstream source_file("image.frag");

std::string data;
std::getline(source_file,data,'\0');

const GLchar *fshader_source(data.c_str());

glShaderSource(fshader,1,&amp;fshader_source,NULL);
}

glCompileShader(vshader);
glCompileShader(fshader);

glAttachShader(program,vshader);
glAttachShader(program,fshader);
glLinkProgram(program);

GLint matrixloc(glGetUniformLocation(program,"projmat"));
GLint matrix2loc(glGetUniformLocation(program,"modelmat"));

//Create geometry
GLuint tris,coords,vao;
const GLfloat vertices[3*2]= {0.0f,0.0f, 0.0f,1.0f, 1.0f,1.0f};
const GLfloat texcoords[3*2]={0.0f,0.0f, 0.0f,1.0f, 1.0f,1.0f};

glGenVertexArrays(1,&amp;vao);
glBindVertexArray(vao);

glGenBuffers(1,&amp;tris);
glBindBuffer(GL_ARRAY_BUFFER,tris);
glBufferData(GL_ARRAY_BUFFER,sizeof(vertices),vert ices,GL_STATIC_DRAW);
const GLint location(glGetAttribLocation(program,"vert"));
glVertexAttribPointer(location,2,GL_FLOAT,GL_TRUE, 0,NULL);
glEnableVertexAttribArray(location);

glGenBuffers(1,&amp;coords);
glBindBuffer(GL_ARRAY_BUFFER,coords);
glBufferData(GL_ARRAY_BUFFER,sizeof(texcoords),tex coords,GL_STATIC_DRAW);
const GLint coordloc(glGetAttribLocation(program,"texcoord"));
glVertexAttribPointer(coordloc,2,GL_FLOAT,GL_TRUE, 0,NULL);
glEnableVertexAttribArray(coordloc);

GLint texloc(glGetUniformLocation(program,"tex"));

//Render
glm::mat4 projmat;
glm::mat4 modelmat;

projmat=glm::mat4(1.0);

modelmat=glm::mat4(1.0);
modelmat*=glm::scale(glm::vec3(0.5f,0.5f,0.5f));

glUseProgram(program);

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D,textureid);
glUniform1i(texloc,0);

glUniformMatrix4fv(matrixloc,1,GL_TRUE,&amp;projmat[0][0]);
glUniformMatrix4fv(matrix2loc,1,GL_TRUE,&amp;modelmat[0][0]);

glBindVertexArray(vao);
glDrawArrays(GL_TRIANGLES,0,3);

glError(__FILE__,__LINE__);
SDL_GL_SwapWindow(window);
SDL_Delay(6000);

//Quit
glDeleteShader(vshader);
glDeleteShader(fshader);
glDeleteProgram(program);
glDeleteTextures(1,&amp;textureid);
SDL_GL_DeleteContext(glcontext);
SDL_DestroyWindow(window);
SDL_Quit();
}

marshats
10-17-2009, 08:26 AM
There are some changes to the code I posted previously. Some better use of perspective and model matrices



//Render
glm::mat4 projmat;
glm::mat4 modelmat;

projmat=glm::mat4(1.0); //loadIdentity
projmat*=glm::perspective(45.0f, float(r_width/r_height), 0.1f, 100.0f);

modelmat=glm::mat4(1.0); //loadIdentity
modelmat*=glm::lookAt( glm::vec3(0.5f,0.5f,0.5f),
glm::vec3(0.5f,0.5f,0.0f),
glm::vec3(0.0f,1.0f,0.0f));
modelmat*=glm::translate(glm::vec3(0.0,0.0,-2.0f));


Also you should not transpose the GLM matrices ie changed so GL_FALSE used instead of GL_TRUE as follows


glUniformMatrix4fv(matrixloc,1,GL_FALSE,&amp;projmat[0][0]);
glUniformMatrix4fv(matrix2loc,1,GL_FALSE,&amp;modelmat[0][0]);


And with my changes to DevIL I forgot to cleanup after exiting. To be complete the first line after LoadImageDevIL should set up cleanup on exit as


assert( LoadImageDevIL ((char*)"Frac.png", &amp;frac) );
atexit(cleanup_images);


Also in image.frag the added "smooth" qualifier was not really necessary.

rsp91
10-17-2009, 09:34 AM
Oh so it was a projection error not OpenGL error! Thanks a bunch

marshats
10-17-2009, 11:13 AM
In addition to the projection error. I think you also needed the line to generate a complete set of mipmaps for your texture object


glTexImage2D (GL_TEXTURE_2D, 0, GL_RGB, frac.w, frac.h, 0, GL_RGB, GL_UNSIGNED_BYTE, frac.p);
glGenerateMipmap(GL_TEXTURE_2D); //Generate mipmaps now!!!


Note, replaced GL_INVALID_ENUM "3" with correct GL_RGB.

rsp91
10-17-2009, 11:30 AM
No it worked fine without it, but thanks for the hint. I was looking for how to do this is OpenGL 3.2 core

marshats
10-17-2009, 12:33 PM
That is interesting. I am using Linux/OpenGL 3.2.0 NVIDIA 190.18.04 (GLSL 1.50 NVIDIA via Cg compiler) and it would fail to show anything but a black screen if I commented out the glGenerateMipmap(GL_TEXTURE_2D); line! So I definitely needed it.

glGenerateMipmap(GL_TEXTURE_2D) is not deprecated so I think it is still ok with ogl3.2.

But if you are using SDL_image that may generate the mipmaps for you whereas DevIL does not the way I am using it in the above code. Or maybe the size of your image is different than mine (512x512) and that is causing the difference.

rsp91
10-17-2009, 12:44 PM
Okay I am using 190.18.05 there is a newer version available FYI http://developer.nvidia.com/object/opengl_3_driver.html

marshats
10-18-2009, 09:20 AM
Thanks, I upgraded to 190.18.05.

However I realized there was no problem it worked fine before. It was a false alarm on my part -- if I changed two things:
1.commented out glGenerateMipmap
2.GL_LINEAR_MIPMAP_LINEAR -> GL_LINEAR
everything worked fine.

ie from:


glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
glTexImage2D (GL_TEXTURE_2D, 0, GL_RGB, frac.w, frac.h, 0, GL_RGB, GL_UNSIGNED_BYTE, frac.p);
glGenerateMipmap(GL_TEXTURE_2D); //Generate mipmaps now!!!

to:


glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glTexImage2D (GL_TEXTURE_2D, 0, GL_RGB, frac.w, frac.h, 0, GL_RGB, GL_UNSIGNED_BYTE, frac.p);
//glGenerateMipmap(GL_TEXTURE_2D); //Generate mipmaps now!!!

Both work.