问题
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);
}
回答1:
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.
来源:https://stackoverflow.com/questions/22896532/sdl-opengl-in-c-texture-shader-missing-the-texture