Question

I am trying to create my first OpenGL Shader but are experiencing difficulties when trying to add a texture to a Cube object.

Is anyone sharp eyed enough to spot the error? The code might have lots of errors, and I am grateful if anyone points them out, but I am most interested in why my rotating cube is gray and not colorful.

(I have skipped all error handling to keep source code size low, sorry about that)

**EDIT Found out I missed some UV settings, still gray cube though ...

#include <windows.h>
#include <SDL.h>

#include <GL/glew.h>
#include <GL/glu.h>
#include <GL/glut.h>

#include <math.h>
#include <string>

using namespace std;

void            initAll();
void            setupBox();
void            mainloop();
unsigned int    generateTexture();
void            handle_inputs();
void            updateScreen();
void            clean_up();

int             scrWidth, scrHeight, flags;
bool            bQuit = false;
float           angle = 0.0f;

GLuint          tex_Box, tex_Norm;

std::string     vertex_source, fragment_source;
GLuint          shader_program, vertex_shader, fragment_shader;

// vao and vbo handle
GLuint          vao, vbo;

const char      *source;
int             length;

struct sVert
{
    float x;
    float y;
    float z;
};

class cPolygon
{
public:
    int v[4];

    void fillverts(int v1, int v2, int v3, int v4) {
        v[0] = v1;
        v[1] = v2;
        v[2] = v3;
        v[3] = v4;
    }
} p[6];

sVert pv[8];

int main(int argc, char *argv[])
{
    initAll();
    mainloop();
    clean_up();
    return 0;
}

void initAll()
{
    scrWidth = 800;
    scrHeight = 600;

    vertex_source =
        "#version 330\n"
        "layout (location = 0) in vec3 Position;\n"
        "layout (location = 1) in vec2 TexCoord;\n"
        "void main() {\n"
        "   gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n" 
        "   gl_TexCoord[0] = gl_MultiTexCoord0;\n"
        "}\n";

    fragment_source =
        "#version 330\n"
        "uniform sampler2D tex;\n"
        "void main() {\n"
        "   FragColor = texture2D(tex, gl_TexCoord[0].st);\n"
        "}\n";

    SDL_InitSubSystem(SDL_INIT_VIDEO);
    SDL_GL_SetAttribute( SDL_GL_ALPHA_SIZE, 8 );
    SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 8 );
    SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 8 );
    SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 8 );
    SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 16 );
    SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );

    flags = SDL_OPENGL | SDL_ANYFORMAT ;

    SDL_SetVideoMode(scrWidth, scrHeight, 16, flags);

    glMatrixMode( GL_PROJECTION );
    glLoadIdentity( );
    gluPerspective( 45.0f, (GLfloat)scrWidth/(GLfloat)scrHeight, 1.0f, 500.0f );
    glMatrixMode( GL_MODELVIEW );
    glLoadIdentity( );

    glEnable (GL_DEPTH_TEST);
    glEnable (GL_LIGHTING);
    glEnable (GL_LIGHT0);

    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_COLOR, GL_ONE_MINUS_SRC_ALPHA);

    SDL_WM_SetCaption( "Texture Shader", NULL );

    glewInit();

    // Vertex shader
    vertex_shader = glCreateShader(GL_VERTEX_SHADER);
    source = vertex_source.c_str();
    length = vertex_source.size();
    glShaderSource(vertex_shader, 1, &source, &length); 
    glCompileShader(vertex_shader);

    // Fragment shader
    fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
    source = fragment_source.c_str();
    length = fragment_source.size();
    glShaderSource(fragment_shader, 1, &source, &length);
    glCompileShader(fragment_shader);

    // create program
    shader_program = glCreateProgram();
    glAttachShader(shader_program, vertex_shader);
    glAttachShader(shader_program, fragment_shader);
    glLinkProgram(shader_program);

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

    glGenBuffers(1, &vbo);
    glBindBuffer(GL_ARRAY_BUFFER, vbo);

    setupBox();

    GLfloat vd[6*5*6];

    for(int pi=0; pi<6; pi++)
    {
        vd[pi*30+ 0] = pv[ p[pi].v[0] ].x;
        vd[pi*30+ 1] = pv[ p[pi].v[0] ].y;
        vd[pi*30+ 2] = pv[ p[pi].v[0] ].z;

        vd[pi*30+ 3] = 0.0;
        vd[pi*30+ 4] = 1.0;

        vd[pi*30+ 5] = pv[ p[pi].v[1] ].x;
        vd[pi*30+ 6] = pv[ p[pi].v[1] ].y;
        vd[pi*30+ 7] = pv[ p[pi].v[1] ].z;

        vd[pi*30+ 8] = 0.0;
        vd[pi*30+ 9] = 0.0;

        vd[pi*30+10] = pv[ p[pi].v[2] ].x;
        vd[pi*30+11] = pv[ p[pi].v[2] ].y;
        vd[pi*30+12] = pv[ p[pi].v[2] ].z;

        vd[pi*30+13] = 1.0;
        vd[pi*30+14] = 0.0;

        vd[pi*30+15] = pv[ p[pi].v[0] ].x;
        vd[pi*30+16] = pv[ p[pi].v[0] ].y;
        vd[pi*30+17] = pv[ p[pi].v[0] ].z;

        vd[pi*30+18] = 0.0;
        vd[pi*30+19] = 1.0;

        vd[pi*30+20] = pv[ p[pi].v[2] ].x;
        vd[pi*30+21] = pv[ p[pi].v[2] ].y;
        vd[pi*30+22] = pv[ p[pi].v[2] ].z;

        vd[pi*30+23] = 1.0;
        vd[pi*30+24] = 0.0;

        vd[pi*30+25] = pv[ p[pi].v[3] ].x;
        vd[pi*30+26] = pv[ p[pi].v[3] ].y;
        vd[pi*30+27] = pv[ p[pi].v[3] ].z;

        vd[pi*30+28] = 1.0;
        vd[pi*30+29] = 1.0;
    }

    glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat)*6*5*6, vd, GL_STATIC_DRAW);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5*sizeof(GLfloat), (char*)0 + 0*sizeof(GLfloat));
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5*sizeof(GLfloat), (char*)0 + 3*sizeof(GLfloat));

    tex_Box = generateTexture();
    tex_Norm = generateTexture();
}

void setupBox()
{
    for (int z=0;z<2;z++)
    for (int y=0;y<2;y++)
    for (int x=0;x<2;x++)
    {
        pv[x+y*2+z*4].x = -1.0+x;
        pv[x+y*2+z*4].y = -1.0+y;
        pv[x+y*2+z*4].z = -1.0+z;
    }

    p[0].fillverts (0, 1, 3, 2);    // above
    p[1].fillverts (4, 5, 1, 0);    // behind
    p[2].fillverts (6, 7, 3, 2);    // in front
    p[3].fillverts (5, 7, 3, 1);    // right
    p[4].fillverts (0, 2, 6, 4);    // left
    p[5].fillverts (7, 6, 4, 5);    // below
}

unsigned int generateTexture()
{
    BYTE    data[128*128*3];
    unsigned int id;

    for (int x=0;x<128;x++)
        for (int y=0;y<128;y++)
        {
            data[y*128*3+x*3+0] = x;        // Red
            data[y*128*3+x*3+1] = y;        // Green
            data[y*128*3+x*3+2] = 128-(abs(64-x)+abs(64-y));    // Blue
        }

    glGenTextures(1, &id); 
    glBindTexture(GL_TEXTURE_2D, id); 
    glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 
    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 128, 128, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
    glGenerateMipmap(GL_TEXTURE_2D);

    return id;
}

void mainloop()
{
    while(bQuit == false)
    {
        handle_inputs();
        updateScreen();
        angle += 1.5f;
        Sleep(50);
    }
}

void handle_inputs()
{
    SDL_PumpEvents();
    Uint8 * keystate = SDL_GetKeyState(NULL);
    if(keystate[SDLK_ESCAPE]) bQuit = true;
}

void updateScreen()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();
    gluLookAt (2.0, 2.0, 2.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
    glUseProgram(shader_program);
    glBindVertexArray(vao);

    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 loc = glGetUniformLocation(shader_program, "tex");
    glUniform1i(loc, 0);
    glBindTexture(GL_TEXTURE_2D, tex_Box);
    glDrawArrays(GL_TRIANGLES, 0, 6*6);
    //glutSolidTeapot(2.0);
    glUseProgram(0);
    SDL_GL_SwapBuffers();
}

void clean_up()
{
    glDeleteVertexArrays(1, &vao);
    glDeleteBuffers(1, &vbo);

    glDetachShader(shader_program, vertex_shader);
    glDetachShader(shader_program, fragment_shader);
    glDeleteShader(vertex_shader);
    glDeleteShader(fragment_shader);
    glDeleteProgram(shader_program);

    SDL_QuitSubSystem(SDL_INIT_VIDEO);
    glDeleteTextures(1, &tex_Box);
    glDeleteTextures(1, &tex_Norm);
    SDL_Quit();
}

**EDIT 2 Here is a fixed version as a result from following the advices in derhass accepted answer. Upvote his answer instead of this if you like it.

#include <windows.h>
#include <SDL.h>

#include <GL/glew.h>
#include <GL/glu.h>
#include <GL/glut.h>
#include <stdio.h>

#include <math.h>
#include <string>

using namespace std;
#define LOG_SIZE 10000

void            initAll();
void            setupBox();
void            mainloop();
unsigned int    generateTexture();
void            handle_inputs();
void            updateScreen();
void            clean_up();
void            dbpf(int, const char *, ...);

int             scrWidth, scrHeight, flags;
bool            bQuit = false;
float           angle = 0.0f;

va_list         m;
int             db_threashold = 0;
GLint           status;
GLchar          elog[LOG_SIZE];
GLint           rLength = 0;

GLuint          tex_Box, tex_Norm;

std::string     vertex_source, fragment_source;
GLuint          shader_program, vertex_shader, fragment_shader;

GLuint          vao, vbo;

const char      *source;
int             length;

struct sVert
{
    float x;
    float y;
    float z;
};

class cPolygon
{
public:
    int v[4];

    void fillverts(int v1, int v2, int v3, int v4) {
        v[0] = v1;
        v[1] = v2;
        v[2] = v3;
        v[3] = v4;
    }
} p[6];

sVert pv[8];

int main(int argc, char *argv[])
{
    initAll();
    mainloop();
    clean_up();
    return 0;
}

void initAll()
{
    scrWidth = 800;
    scrHeight = 600;

    vertex_source =
        "#version 330\n"
        "in vec3 Position;\n"
        "in vec2 TexCoord;\n"
        "out vec3 oColor;"
        "out vec2 oTexcoord;"
        "void main() {\n"
        "    oTexcoord = TexCoord;\n"
        "    gl_Position = gl_ModelViewProjectionMatrix*vec4(Position, 1.0);\n"
        "}\n";

    fragment_source =
        "#version 330\n"
        "in vec2 oTexcoord;"
        "out vec4 oColor;"
        "uniform sampler2D tex;\n"
        "void main() {\n"
        "   oColor = texture2D(tex, oTexcoord);\n"
        "}\n";

    SDL_InitSubSystem(SDL_INIT_VIDEO);
    SDL_GL_SetAttribute( SDL_GL_ALPHA_SIZE, 8 );
    SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 8 );
    SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 8 );
    SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 8 );
    SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 16 );
    SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );

    flags = SDL_OPENGL | SDL_ANYFORMAT ;

    SDL_SetVideoMode(scrWidth, scrHeight, 16, flags);

    glMatrixMode( GL_PROJECTION );
    glLoadIdentity( );
    gluPerspective( 45.0f, (GLfloat)scrWidth/(GLfloat)scrHeight, 1.0f, 500.0f );
    glMatrixMode( GL_MODELVIEW );
    glLoadIdentity( );

    glEnable (GL_DEPTH_TEST);
    glEnable (GL_LIGHTING);
    glEnable (GL_LIGHT0);

    SDL_WM_SetCaption( "Texture Shader", NULL );

    glewInit();

    // create and compiler vertex shader
    vertex_shader = glCreateShader(GL_VERTEX_SHADER);
    source = vertex_source.c_str();
    length = vertex_source.size();
    glShaderSource(vertex_shader, 1, &source, &length); 
    glCompileShader(vertex_shader);

    glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &status);
    glGetShaderInfoLog(vertex_shader, LOG_SIZE, &rLength, elog);
    dbpf(10, "Compile vertex log: \n %s \n", elog);

    // create and compiler fragment shader
    fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
    source = fragment_source.c_str();
    length = fragment_source.size();
    glShaderSource(fragment_shader, 1, &source, &length);
    glCompileShader(fragment_shader);

    glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &status);
    glGetShaderInfoLog(fragment_shader, LOG_SIZE, &rLength, elog);
    dbpf(10, "Compile fragment log: \n %s \n", elog);

    // create program
    shader_program = glCreateProgram();

    // attach shaders
    glAttachShader(shader_program, vertex_shader);
    glAttachShader(shader_program, fragment_shader);

    // link the program and check for errors
    glLinkProgram(shader_program);
    glGetProgramiv(shader_program, GL_LINK_STATUS, &status);
    glGetProgramInfoLog(shader_program, LOG_SIZE, &rLength, elog);
    dbpf(10, "Link log: \n %s \n", elog);

    // generate and bind the vao
    glGenVertexArrays(1, &vao);
    glBindVertexArray(vao);

    // generate and bind the buffer object
    glGenBuffers(1, &vbo);
    glBindBuffer(GL_ARRAY_BUFFER, vbo);

    setupBox();

    GLfloat vd[6*5*6];

    for(int pi=0; pi<6; pi++)
    {
        vd[pi*30+ 0] = pv[ p[pi].v[0] ].x;
        vd[pi*30+ 1] = pv[ p[pi].v[0] ].y;
        vd[pi*30+ 2] = pv[ p[pi].v[0] ].z;

        vd[pi*30+ 3] = 0.0;
        vd[pi*30+ 4] = 1.0;

        vd[pi*30+ 5] = pv[ p[pi].v[1] ].x;
        vd[pi*30+ 6] = pv[ p[pi].v[1] ].y;
        vd[pi*30+ 7] = pv[ p[pi].v[1] ].z;

        vd[pi*30+ 8] = 0.0;
        vd[pi*30+ 9] = 0.0;

        vd[pi*30+10] = pv[ p[pi].v[2] ].x;
        vd[pi*30+11] = pv[ p[pi].v[2] ].y;
        vd[pi*30+12] = pv[ p[pi].v[2] ].z;

        vd[pi*30+13] = 1.0;
        vd[pi*30+14] = 0.0;

        vd[pi*30+15] = pv[ p[pi].v[0] ].x;
        vd[pi*30+16] = pv[ p[pi].v[0] ].y;
        vd[pi*30+17] = pv[ p[pi].v[0] ].z;

        vd[pi*30+18] = 0.0;
        vd[pi*30+19] = 1.0;

        vd[pi*30+20] = pv[ p[pi].v[2] ].x;
        vd[pi*30+21] = pv[ p[pi].v[2] ].y;
        vd[pi*30+22] = pv[ p[pi].v[2] ].z;

        vd[pi*30+23] = 1.0;
        vd[pi*30+24] = 0.0;

        vd[pi*30+25] = pv[ p[pi].v[3] ].x;
        vd[pi*30+26] = pv[ p[pi].v[3] ].y;
        vd[pi*30+27] = pv[ p[pi].v[3] ].z;

        vd[pi*30+28] = 1.0;
        vd[pi*30+29] = 1.0;
    }

    // fill with data
    glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat)*6*5*6, vd, GL_STATIC_DRAW);

    // set up generic attrib pointers
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5*sizeof(GLfloat), (char*)0 + 0*sizeof(GLfloat));

    glEnableVertexAttribArray(1);
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5*sizeof(GLfloat), (char*)0 + 3*sizeof(GLfloat));

    tex_Box = generateTexture();
    tex_Norm = generateTexture();

}

void setupBox()
{

    for (int z=0;z<2;z++)
    for (int y=0;y<2;y++)
    for (int x=0;x<2;x++)
    {
        pv[x+y*2+z*4].x = -1.0+x;
        pv[x+y*2+z*4].y = -1.0+y;
        pv[x+y*2+z*4].z = -1.0+z;
    }

    p[0].fillverts (0, 1, 3, 2);    // above
    p[1].fillverts (4, 5, 1, 0);    // behind
    p[2].fillverts (6, 7, 3, 2);    // in front
    p[3].fillverts (5, 7, 3, 1);    // right
    p[4].fillverts (0, 2, 6, 4);    // left
    p[5].fillverts (7, 6, 4, 5);    // below
}

unsigned int generateTexture()
{
    BYTE    data[128*128*3];
    unsigned int id;

    for (int x=0;x<128;x++)
        for (int y=0;y<128;y++)
        {
            data[y*128*3+x*3+0] = x;        // Red
            data[y*128*3+x*3+1] = y;        // Green
            data[y*128*3+x*3+2] = 128-(abs(64-x)+abs(64-y));    // Blue
        }

    glGenTextures(1, &id); 
    glBindTexture(GL_TEXTURE_2D, id); 
    glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); 
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 
    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 128, 128, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
    glGenerateMipmap(GL_TEXTURE_2D);

    return id;
}

void mainloop()
{
    while(bQuit == false)
    {
        handle_inputs();
        updateScreen();
        angle += 1.5f;
        Sleep(50);
    }
}

void handle_inputs()
{
    SDL_PumpEvents();
    Uint8 * keystate = SDL_GetKeyState(NULL);
    if(keystate[SDLK_ESCAPE]) bQuit = true;
}

void updateScreen()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();

    gluLookAt (2.0, 2.0, 2.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);

    // use the shader program
    glUseProgram(shader_program);

    // bind the vao
    glBindVertexArray(vao);

    // rotation
    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

    // bind texture
    glActiveTexture(GL_TEXTURE0);
    int loc = glGetUniformLocation(shader_program, "tex");
    glUniform1i(loc, 0); 
    glBindTexture(GL_TEXTURE_2D, tex_Box);

    // draw
    glDrawArrays(GL_TRIANGLES, 0, 6*6);

    glUseProgram(0);
    SDL_GL_SwapBuffers();
}

void clean_up()
{
    glDeleteVertexArrays(1, &vao);
    glDeleteBuffers(1, &vbo);

    glDetachShader(shader_program, vertex_shader);
    glDetachShader(shader_program, fragment_shader);
    glDeleteShader(vertex_shader);
    glDeleteShader(fragment_shader);
    glDeleteProgram(shader_program);

    SDL_QuitSubSystem(SDL_INIT_VIDEO);
    glDeleteTextures(1, &tex_Box);
    glDeleteTextures(1, &tex_Norm);
    SDL_Quit();
}

void dbpf(int t, const char * msg, ...)
{
    va_start(m, msg);
    if (t >= db_threashold) vfprintf(stderr, msg, m);
    va_end(m);
}
Was it helpful?

Solution

Your fragment shader shouldn't even compile. You are writing to an undeclated variable 'FragColor'. You should first add code to check the compile and link status, and to query the compile and link log, so that you get all the errors and warnings the GLSL compiler/linker detected. YOu could use something like:

GLint status;
GLubyte log[LOG_SIZE];
// compile shader here
...
glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
if (status != GL_TRUE) {
    // compile error
    ...
}
glGetShaderInfoLog(shader, LOG_SIZE, 0, log);
// print the log

...
// link the program here
// ...
glGetProgramiv(program, GL_LINK_STATUS, &status);
if (status != GL_TRUE) {
    //  error
    ...
}
glGetProgramInfoLog(program, LOG_SIZE, 0, log);
// print the log

Maybe you want to print the info log only in the error case, but there might be some warnings/hints in there even in the successful case, so I recommend printing it alywas, at least in debug/development builts.

I also recommend you stop mixing old, deprecated builtins like gl_TexCoord[0], gl_MultiTexCoord0 and so on with mordern user defined attributes, inputs and outputs. Currently, you are not using the TexCoord attribute which you did declare.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top