I eventually hope to colorize an image based on 3 1d samplers. I wrote this quick program to test if I could map the red channel of a texture to itself, a so called linear mapping.
Right now the code is showing a blank screen, despite all of my error checking in the program, shader, and general execution. When I don't perform the mapping the texture renders as expected.
I am on a GeForce Ti 550, targeting Windows.
The method was largely inspired from: http://www.arcsynthesis.org/gltut/Texturing/Tutorial%2014.html
Make Texture and Sampler
glActiveTexture(GL_TEXTURE1);
glGenTextures(1,lut);
glBindTexture(GL_TEXTURE_1D,lut[0]);
unsigned char* linear = new unsigned char[256];//should be a 1->1 mapping
for (int i = 0 ;i < 256;i++)
{
linear[i] = i;
}
glTexImage1D(GL_TEXTURE_1D, 0, GL_R8, 256, 0,GL_RED, GL_UNSIGNED_BYTE, linear);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_BASE_LEVEL, 0);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAX_LEVEL, 0);
glBindTexture(GL_TEXTURE_1D, 0);
delete linear;
glGenSamplers(1,sampler);
glSamplerParameteri(sampler[0], GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glSamplerParameteri(sampler[0], GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glSamplerParameteri(sampler[0], GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glE();// no errors
Make the program, also no errors
const char *vsrc1 =
"attribute vec2 vecPosIn;\n"
"attribute vec4 texPosIn;\n"
"varying vec4 texPosOut;\n"
"void main()\n"
"{\n"
"gl_Position = vec4(vecPosIn, 0.0, 1.0);\n"
"texPosOut = texPosIn;\n"
"}\n";
GLint vsH = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vsH,1,&vsrc1,NULL);
glCompileShader(vsH);
shaderCheck(vsH);
glE();
const char *fsrc1 =
"uniform sampler2D tex0;\n"
"uniform sampler1D tex1;\n"
"varying vec4 texPosOut;\n"
"void main(void)\n"
"{\n"
//" gl_FragColor = texture2D(tex0, texPosOut.st);\n" //ignores texture and does what I expect
" float red = texture2D(tex0, texPosOut.st).r;\n"
" gl_FragColor = texture1D(tex1, red);\n"
"}\n";
GLint fsH = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fsH,1,&fsrc1,NULL);
glCompileShader(fsH);
shaderCheck(fsH);
glE();
//Bind
programHandle = glCreateProgram();
glBindAttribLocation(programHandle,0,"vecPosIn");
glBindAttribLocation(programHandle,1,"texPosIn");
glBindAttribLocation(programHandle,2,"texPosOut");
glE();
//Link
glAttachShader( programHandle, vsH );
glAttachShader( programHandle, fsH );
glLinkProgram( programHandle );
programCheck(programHandle);
glE();
//Set render() invariants
glUseProgram( programHandle );
GLuint idk = glGetUniformLocation(programHandle, "tex1");
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_1D,lut[0]);
glUniform1i(idk,0);
glBindTexture(GL_TEXTURE_1D,0);
glUseProgram( 0 );
glE();
//Pack static data into a VAO
float vecData[] = {
-1, 1,
-1,-1,
1, 1,
-1,-1,
1,-1,
1, 1
};
float texData[] = {
0,1,
0,0,
1,1,
0,0,
1,0,
1,1
};
vboHandles=(GLuint*)malloc(sizeof(int)*2);
glGenBuffers(2,vboHandles);
GLuint vecBuf=vboHandles[0];
GLuint texBuf=vboHandles[1];
glBindBuffer(GL_ARRAY_BUFFER, vecBuf);
glBufferData(GL_ARRAY_BUFFER, 8*2 * sizeof(GLfloat), vecData, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, texBuf);
glBufferData(GL_ARRAY_BUFFER, 8*2 * sizeof(GLfloat), texData, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glE();
glGenVertexArrays( 1, &vaoHandle );
glBindVertexArray(vaoHandle);
glEnableVertexAttribArray(0); // Vertex position
glEnableVertexAttribArray(1); // Vertex color
glBindBuffer(GL_ARRAY_BUFFER, vecBuf);
glVertexAttribPointer( 0, 2, GL_FLOAT, GL_FALSE, 0, (GLubyte *)NULL );
glBindBuffer(GL_ARRAY_BUFFER, texBuf);
glVertexAttribPointer( 1, 2, GL_FLOAT, GL_FALSE, 0, (GLubyte *)NULL ); //2 attribute per vertex
glBindBuffer(GL_ARRAY_BUFFER,0);
glBindVertexArray(0);
glE();
Render Function
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
glE();
//Bind
glUseProgram(programHandle);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D,textures[frame]);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_1D,lut[0]);
GLuint idk = glGetUniformLocation(programHandle, "tex1");
glUniform1i(idk,0);
glBindSampler(0,sampler[0]);glE();
glE();
//Draw
glBindVertexArray(vaoHandle);
glDrawArrays(GL_TRIANGLES,0,8);
glBindVertexArray(0);
glE();
//Unbind
glActiveTexture(GL_TEXTURE1);
glBindSampler(0,0);
glBindTexture(GL_TEXTURE_1D,0);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D,0);
glUseProgram(0);
glE();
//DumpFrame
glFlush();
glFinish();
glE();
You are setting
glUniform1i(idk,0);
so you tell the GL to use texture unit 0 to sample the "tex1" 1D texture, which is just invalid as you have a 2D texture bound there.
Related
I'm trying to display RGB images in a GtkGLArea using a gtk/epoxy stack in C(/C++) langage brought by vcpkg.
I have no errors but the widget stay white.
Can someone teel me what I'm missing ?
here are the shaders:
#include <gtk/gtk.h>
#include <epoxy/gl.h>
const char* vertexShaderCode =
"#version 330 core\n"
"in vec3 a_position;"
"void main() {"
" gl_Position = vec4(a_position,1.0);"
"}";
const char* fragmentShaderCode =
"#version 330 core\n"
"uniform sampler2D u_texture;"
"in vec2 tex_pos;"
"out vec3 color;"
"void main() {"
" vec3 texel = texture2D(u_texture, tex_pos).rgb;"
" color = texel;"
"}";
used variables (class members):
guint width, height;
guint vao;
guint texture;
guint program;
void* pixels; // image content
some Triangle coordinates:
GLfloat vertices[12] = {
-1, -1, 0,
1, -1, 0,
-1, 1, 0,
1, 1, 0
};
GLfloat textureVertices[8] = {
0, 1,
1, 1,
0, 0,
1, 0
};
Init:
glViewport(0, 0, width, height);
glClearColor(1.0f, 1.0f, 1.0f, 1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// shaders
guint vshader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vshader, 1, &vertexShaderCode, NULL);
glCompileShader(vshader);
guint fshader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fshader, 1, &fragmentShaderCode, NULL);
glCompileShader(fshader);
//program
program = glCreateProgram();
glAttachShader(program, vshader);
glAttachShader(program, fshader);
glLinkProgram(program);
glUseProgram(program);
glDisable(GL_BLEND);
glDisable(GL_DITHER);
glDisable(GL_DEPTH_TEST);
glDeleteShader(vshader);
glDeleteShader(fshader);
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
GLuint buffers[2];
glGenBuffers(2, &buffers[0]);
glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), 0);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, buffers[1]);
glBufferData(GL_ARRAY_BUFFER, sizeof(textureVertices), textureVertices, GL_STATIC_DRAW);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), 0);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, 0);
int textureHandle = glGetUniformLocation(program, "u_texture");
glUniform1i(textureHandle, 0);
glBindAttribLocation(program, 0, "a_position");
glBindAttribLocation(program, 1, "tex_pos");
// textures
glActiveTexture(GL_TEXTURE0);
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);// OR LINEAR
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glPixelStorei(GL_PACK_ALIGNMENT, 1);
glTexImage2D(
GL_TEXTURE_2D, 0,
GL_RGB,
width, height, 0,
GL_RGB,
GL_UNSIGNED_BYTE, NULL);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glDisableVertexAttribArray(0);
glBindTexture(GL_TEXTURE_2D, 0);
glBindVertexArray(0);
glDeleteBuffers(2, &buffers[0]);
update drawing:
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
glBindTexture(GL_TEXTURE_2D, texture);
// Bind the VAO
glViewport(0, 0, areaWidth, areHeight);
glUseProgram(program);
glBindVertexArray(vao);
glBindTexture(GL_TEXTURE_2D, texture);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, pixels);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glBindTexture(GL_TEXTURE_2D, 0);
each time needed data is copied to pixels pointer and rendering is requested:
gtk_gl_area_queue_render(GTK_GL_AREA(widget));
but the image is never rendered
All vertex attributes are inputs to the vertex shader. You need to pass the texture coordinates from the vertex shader to the fragment shader:
#version 330 core
in vec3 a_position;
in vec2 a_tex_pos;
out vec2 tex_pos;
void main() {
tex_pos = a_tex_pos;
gl_Position = vec4(a_position,1.0);
}
glBindAttribLocation(program, 1, "tex_pos");
glBindAttribLocation(program, 1, "a_tex_pos");
Note that the vertex shader runs per vertex, but the fragment shader runs per fragment. The vertex shader outputs are interpolated along the fragments between the vertices. The interpolated outputs are the inputs to the fragment shader. With the interpolated texture coordinates, a different pixel of the image can be looked up for each fragment of the primitive.
I fixed it, there was several mistakes:
mainly:
draw strips without an bound vertice buffer
working example:
here are the shaders:
#include <gtk/gtk.h>
#include <epoxy/gl.h>
const char* vertexShaderCode =
"#version 330 core\n"
"layout(location = 0) in vec3 a_position;"
"in vec2 a_tex_pos;"
"out vec2 tex_pos;"
"void main() {"
" tex_pos = a_tex_pos;"
" gl_Position = vec4(a_position,1.0);"
"}";
const char* fragmentShaderCode =
"#version 330 core\n"
"uniform sampler2D u_texture;"
"in vec2 tex_pos;"
"layout(location = 0) out vec4 color;"
"void main() {"
" vec4 texel = texture2D(u_texture, tex_pos);"
" color = texel;"
"}";
used variables (class members):
guint width, height;
guint vao;
guint texture;
guint program;
guint buffers[2];
void* pixels; // image content
some Triangle coordinates:
GLfloat vertices[12] = {
-1, -1, 0,
1, -1, 0,
-1, 1, 0,
1, 1, 0
};
GLfloat textureVertices[8] = {
0, 1,
1, 1,
0, 0,
1, 0
};
Init:
glViewport(0, 0, width, height);
glClearColor(1.0f, 1.0f, 1.0f, 1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// shaders
guint vshader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vshader, 1, &vertexShaderCode, NULL);
glCompileShader(vshader);
guint fshader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fshader, 1, &fragmentShaderCode, NULL);
glCompileShader(fshader);
//program
program = glCreateProgram();
glAttachShader(program, vshader);
glAttachShader(program, fshader);
glLinkProgram(program);
glUseProgram(program);
//glDisable(GL_BLEND);
glDisable(GL_DITHER);
//glDisable(GL_DEPTH_TEST);
glDeleteShader(vshader);
glDeleteShader(fshader);
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
fbo = 0;
glGenFramebuffers(1, &fbo);
GLuint buffers[2];
glGenBuffers(2, &buffers[0]);
// I swap buffers order
glBindBuffer(GL_ARRAY_BUFFER, buffers[1]);
glBufferData(GL_ARRAY_BUFFER, sizeof(textureVertices), textureVertices, GL_STATIC_DRAW);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), 0);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), 0);
glEnableVertexAttribArray(0);
//glBindBuffer(GL_ARRAY_BUFFER, 0); not yet !
int textureHandle = glGetUniformLocation(program, "u_texture");
glUniform1i(textureHandle, 0);
glBindAttribLocation(program, 0, "a_position");
glBindAttribLocation(program, 1, "a_tex_pos");
// textures
glActiveTexture(GL_TEXTURE0);
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);// OR LINEAR
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glPixelStorei(GL_PACK_ALIGNMENT, 1);
glTexImage2D(
GL_TEXTURE_2D, 0,
GL_RGB,
width, height, 0,
GL_RGBA,
GL_UNSIGNED_BYTE, NULL);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); // it is effective now
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
GLenum DrawBuffers[1] = { GL_COLOR_ATTACHMENT0 };
glDrawBuffers(1, DrawBuffers);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0); // unbind now
glDisableVertexAttribArray(0);
glBindTexture(GL_TEXTURE_2D, 0);
glBindVertexArray(0);
//glDeleteBuffers(2, &buffers[0]); no !
update drawing:
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
glBindTexture(GL_TEXTURE_2D, texture);
// Bind the VAO
glViewport(0, 0, areaWidth, areHeight);
glUseProgram(program);
glBindVertexArray(vao);
glBindTexture(GL_TEXTURE_2D, texture);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, pixels);
// rebind vertices
glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(0);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glBindTexture(GL_TEXTURE_2D, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
each time needed data is copied to pixels pointer and rendering is requested:
gtk_gl_area_queue_render(GTK_GL_AREA(widget));
I've found similar posts here, but none help me with my problem. I'm just using basic OpenGL, and trying to draw a triangle with a texture applied. But for some reason the triangle is one solid color. This color happens to be the same color as the background of the texture.
This is the texture I'm attempting to draw
And this is the result when I run the program
I've experimented by editing the texture to have some blue in the bottom left (the origin), and it came out like this
My guess is that it's interpolating the red and blue to give me purple. But I have no idea why it'd be interpolating the colors in the first place instead of just drawing the texture like I want.
This is some bits and pieces of the relevant parts of my code:
Enabling things before the main loop
glClearColor(0, 0, 0, 1);
glEnable(GL_BLEND);
glEnable(GL_TEXTURE);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
Loading the shaders
auto vertString = getSource("test.vert");
auto vertSource = vertString.c_str();
GLint vertLength = vertString.length();
auto fragString= getSource("test.frag");
auto fragSource = fragString.c_str();
GLint fragLength = fragString.length();
auto vertShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertShader, 1, &vertSource, &vertLength);
auto fragShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragShader, 1, &fragSource, &fragLength);
//compile shaders
glCompileShader(vertShader);
checkShaderCompilation(vertShader, "vertex shader");
glCompileShader(fragShader);
checkShaderCompilation(fragShader, "fragment shader");
auto program = glCreateProgram();
glAttachShader(program, vertShader);
glAttachShader(program, fragShader);
glBindAttribLocation(program, 0, "i_position");
glBindAttribLocation(program, 1, "i_texCoord");
//link program
glLinkProgram(program);
checkProgramLinkage(program, "vertex shader", "fragment shader");
glDetachShader(program, vertShader);
glDetachShader(program, fragShader);
glDeleteShader(vertShader);
glDeleteShader(fragShader);
Loading the Texture
SDL_Surface* surface = IMG_Load("Numel.png");
if (!surface)
{
std::cout << "Unable to load texture." << std::endl;
return 0;
}
auto width = surface->w;
auto height = surface->h;
GLuint texture = 0;
//generate the id
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
auto mode = surface->format->BytesPerPixel == 4 ? GL_RGBA : GL_RGB;
glTexImage2D(GL_TEXTURE_2D, 0, mode, surface->w, surface->h, false, mode, GL_UNSIGNED_BYTE, surface->pixels);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
SDL_FreeSurface(surface);
glBindTexture(GL_TEXTURE_2D, 0);
Vertex Structure
struct Vertex
{
Vector2 position;
Vector2 texCoord;
};
Generating the Vertex Array
Vertex data[] = {
-0.5, -0.5, 0, 0,
0.5, -0.5, 1, 0,
0.5, 0.5, 1, 1
};
GLuint vertexBuffer = 0, vertexArray = 0;
glGenBuffers(1, &vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex)*3, data, GL_STATIC_DRAW);
glGenVertexArrays(1, &vertexArray);
glBindVertexArray(vertexArray);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, 0, sizeof(Vertex), (char*)offsetof(Vertex, position));
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, 0, sizeof(Vertex), (char*)offsetof(Vertex, texCoord));
And binding/drawing everything in the main loop
glClear(GL_COLOR_BUFFER_BIT);
//texture
glBindTexture(GL_TEXTURE_2D, texture);
//shader
auto colorLoc = glGetUniformLocation(program, "u_color");
glUniform3f(colorLoc, 0, 0, 1);
auto useTextureLoc = glGetUniformLocation(program, "u_usingTexture");
glUniform1i(useTextureLoc, 1);
auto textureLoc = glGetUniformLocation(program, "u_sampler");
glUniform1i(textureLoc, 0);
glUseProgram(program);
//vertex array
glBindVertexArray(vertexArray);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glDrawArrays(GL_TRIANGLES, 0, 3);
SDL_GL_SwapWindow(window);
This is my vertex shader
#version 420
in vec2 i_position;
in vec2 i_texCoord;
out vec2 o_texCoord;
void main()
{
o_texCoord=i_texCoord;
gl_Position=vec4(i_position, 0, 1);
}
And my fragment shader
#version 420
uniform vec3 u_color;
uniform sampler2D u_sampler;
uniform bool u_usingTexture;
in vec2 i_texCoord;
out vec4 o_color;
void main()
{
if(u_usingTexture)
o_color=texture(u_sampler, i_texCoord);
else
o_color=vec4(u_color, 1);
}
I've literally been trying to solve this for days and I have no idea. If anyone could figure out why it's rendering with one color instead of the texture, it'd be very much appreciated.
You are not using your texcoords:
This is my vertex shader
[...]
out vec2 o_texCoord;
And my fragment shader
[...]
in vec2 i_texCoord;
The names of your vertex shader outputs must match those of your fragment shader inputs. Since they do not, your fragment shader sees an input value which will just be undefined as per the spec.
The only reason why you don't get an error during linking is that you use i_texCoord in the fragment shader in some conditional way ("dynamic use"). If you would statically use i_texCoord in the fragment shader, you actually would get a link error. However, since the comipler/linker cannot rule out that you never ever access that variable, this code is allowed as per the spec, and must not result in a compilation error. But if you actually access those values, they are undefined.
I tried to load the same model(modeled in 3Ds max) in opengl, but with different textures. The problem is, that when I try to bind the Texture with glBindTexture after I have acitvated the texture, then it disappears. Before I changed the textures in 3Ds max, it always has show me the model in black color (just in opengl). But I havenĀ“t even assign black color to my model. My image "model-image.png" also contains all textures, that I have assign to my object. So am I missing something?
Thanks for your help in advance.
void initDrawing()
{
glEnable(GL_DEPTH_TEST);
program = glCreateProgram();
std::string shaderV = Utilities::loadFile("shader.vert");
std::string shaderF = Utilities::loadFile("shader.frag");
program = Utilities::compileShader(shaderV, shaderF);
Utilities::loadObj("model.obj", obj);
Utilities::loadPNG("model-image.png", diffuse);
glEnable(GL_TEXTURE_2D);
glGenVertexArrays(1, &vertexArrayObject);
glBindVertexArray(vertexArrayObject);
glGenBuffers(1, &vPosition);
glBindBuffer(GL_ARRAY_BUFFER, vPosition);
glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec4)*obj.vertices.size(), &obj.vertices[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vPosition);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
GLuint vCoordinates;
glGenBuffers(1, &vCoordinates);
glBindBuffer(GL_ARRAY_BUFFER, vCoordinates);
glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec2)*obj.textureCoordinates.size(), &obj.textureCoordinates[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, vCoordinates);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, NULL);
glGenTextures(2, &texture);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, diffuse.width, diffuse.height, 0, GL_RGBA, GL_UNSIGNED_BYTE,
&diffuse.colors[0]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glUseProgram(program);
ModelView = glGetUniformLocation(program, "ModelView");
Projection = glGetUniformLocation(program, "Projection");
Diffuse = glGetUniformLocation(program, "Diffuse");
}
void display()
{
// background color
const GLfloat color[] = { 0.5, 0.5, 0.5, 1 };
glClear(GL_DEPTH_BUFFER_BIT);
glClearBufferfv(GL_COLOR, 0, color);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
modelView = view * model;
glUniformMatrix4fv(ModelView, 1, GL_FALSE, glm::value_ptr(modelView));
glUniformMatrix4fv(Projection, 1, GL_FALSE, glm::value_ptr(projection));
glUniform1i(Diffuse, 0);
glDrawArrays(GL_TRIANGLES, 0, obj.vertices.size());
glutSwapBuffers();
}
My Shader:
fragment shader:
uniform sampler2D Diffuse;
in vec2 fUV;
out vec3 color;
//main for the color
void main(void)
{
color = texture(Diffuse, fUV).rgb;
}
vertex Shader:
layout (location = 0) in vec4 vPosition;
layout (location = 2) in vec2 vCoordinates;
uniform mat4 ModelView;
uniform mat4 Projection;
out vec2 fUV;
void main(void)
{
gl_Position = Projection * ModelView * vPosition;
fUV = vCoordinates;
}
My guess is that when you say
layout(location = 2) in vec2 vCoordinates;
you really mean to say
layout(location = 1) in vec2 vCoordinates;
considering you never enable vertex attribute 2.
I am a bloody newbie to OpenGL and it still looks sometimes like black magic to me. I just want to load and display an texture for testing purposes and I do not want to use the tutorial libraries to really understand what happens. But I just get a black screen and I cannot find the reason for it.
My c++ source code
int main(){
new cpp_logger();
GLint program_rgb_;
Mat img = imread("plane.jpg");
std::string file_path = "plane.jpg";
// Set viewport window size and clear color bit.
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
//set viewport
glViewport(0, 0, img.size().width, img.size().height);
// Create a Vertex Buffer Object and copy the vertex data to it
GLuint vbo;
glGenBuffers(1, &vbo);
GLfloat vertices[] = {-1, 1, -1, -1, 1, 1, 1, -1,
0, 0, 0, 1, 1, 0, 1, 1};
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
//create program and shader
program_rgb_ = glCreateProgram();
const char* vertexShader = read_shader("vertex.glsl"); //simple method to read the shader files
const char* fragmentShader = read_shader("fragment.glsl");
CreateShader(program_rgb_, GL_VERTEX_SHADER, vertexShader); //simple method to link and compile shader programs
CreateShader(program_rgb_, GL_FRAGMENT_SHADER, fragmentShader);
glLinkProgram(program_rgb_);
glUseProgram(program_rgb_);
//use fast 4-byte alignment (default anyway) if possible because using OpenCV
glPixelStorei(GL_UNPACK_ALIGNMENT, (img.step & 3) ? 1 : 4);
//set length of one complete row in data (doesn't need to equal image.cols)
glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, img.step/img.elemSize());
flip(img, img, 0);
// Load texture
GLuint tex;
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D, tex);
//set parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, img.cols, img.rows, 0, GL_RGBA, GL_UNSIGNED_BYTE, img.data);
glUniform1i(glGetUniformLocation(program_rgb_,"tex"), 0);
uint8_t* result = new uint8_t[img.cols * img.rows * 4];
while(true){
GLint pos_location = glGetAttribLocation(program_rgb_, "a_position");
GLint tc_location = glGetAttribLocation(program_rgb_, "a_texCoord");
// Specify the layout of the vertex data
glEnableVertexAttribArray(pos_location);
glVertexAttribPointer(pos_location, 2, GL_FLOAT, GL_FALSE, 0, 0);
//specify color data
glEnableVertexAttribArray(tc_location);
glVertexAttribPointer(tc_location, 2, GL_FLOAT, GL_FALSE, 0, static_cast<float*>(0) + 8);
// Draw a rectangle from the 2 triangles using 6 indices
glDrawArrays(GL_TRIANGLES, 0, 8);
glReadPixels(0, 0, img.rows, img.cols, GL_BGRA_EXT, GL_UNSIGNED_BYTE, (void*)result);
auto result_ = cv::Mat(img.rows, img.cols, CV_8UC4, result);
imshow("img", result_);
if(waitKey(1) >= 0) break;
}
destroyAllWindows();
return EXIT_SUCCESS;
}
My fragment shader
#version 150 core
precision mediump float;
in vec2 texCoord;
uniform sampler2D tex;
void main()
{
gl_FragColor = texture2D(tex, texCoord);
}
my vertex shader
#version 150 core
out vec2 texCoord;
attribute vec2 a_texCoord;
attribute vec4 a_position;
void main()
{
texCoord = a_texCoord;
gl_Position = a_position;
}
Thank you a lot for your help!
EDIT
Sorry for the missunderstanding. I meant: I do not want to use the libraries like SOIL and SFML and I want to go an alternative way to fully understand what actually happens.
I'm trying to load a texture in OpenGL, but all I get is black. I've verified that the shaders are returning GL_TRUE when they compile. So, I don't think that is the issue...
Some things to note:
I have taken and modified code from https://open.gl/content/code/c3_multitexture.txt. This was a tutorial from https://open.gl/textures
The texture I am trying to load is from a 640 x 400 PGM file. You can assume the loader pgmImage correctly loads the file (I have verified it in GDB). PGM is 8-bit B&W data. Here I am trying to just use it as the red channel, although I'd like to be able to eventually display it as B&W, too.
Where am I going wrong?
Thanks!
Code compiled with: -lglut -lGLU -lGL -lm -lGLEW flags in g++ (some aren't necessary, I know).
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <math.h>
// Include GLEW
#include <GL/glew.h>
//Glut
#include <GL/glut.h>
#include "shader.hpp"
#include "PGM.hpp"
GLuint programID;
GLuint output_image;
// Shader sources
const GLchar* vertexSource =
"#version 450 core\n"
"in vec2 position;"
"in vec2 texcoord;"
"out vec2 Texcoord;"
"void main()"
"{"
" Texcoord = texcoord;"
" gl_Position = vec4(position, 0.0, 1.0);"
"}";
const GLchar* fragmentSource =
"#version 450 core\n"
"in vec2 Texcoord;"
"out vec4 outColor;"
"uniform sampler2D texData;"
"void main()"
"{"
" outColor = texture(texData, Texcoord);"
"}";
void display()
{
glClearColor(0.0f, 0.0f, 1.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glFlush();
glutSwapBuffers();
}
void reshape(int width,int height)
{
double w2h = (height>0) ? (double)width/height : 1;
// Set viewport as entire window
glViewport(0,0, width,height);
}
int main(int argc, char** argv)
{
// Image setup
PGM pgmImage;
pgmImage.ReadFile("test.pgm");
// Window Setup
glutInitWindowSize(640, 400);
glutInitWindowPosition (140, 140);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
glutInit(&argc, argv);
glutCreateWindow( "OpenGL Application" );
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glewExperimental = true; // Needed for core profile
if (glewInit() != GLEW_OK) {
fprintf(stderr, "Failed to initialize GLEW\n");
return -1;
}
// Vertices & texture init
GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
GLuint vbo;
glGenBuffers(1, &vbo);
GLfloat vertices[] = {
// X Y S T
-0.5f, 0.5f, 0.0f, 0.0f, // Top-left
0.5f, 0.5f, 1.0f, 0.0f, // Top-right
0.5f, -0.5f, 1.0f, 1.0f, // Bottom-right
-0.5f, -0.5f, 0.0f, 1.0f // Bottom-left
};
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
GLuint ebo;
glGenBuffers(1, &ebo);
GLuint elements[] = {
0, 1, 2,
2, 3, 0
};
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(elements), elements, GL_STATIC_DRAW);
// Create shaders
GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexSource, NULL);
glCompileShader(vertexShader);
GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentSource, NULL);
glCompileShader(fragmentShader);
GLuint shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glBindFragDataLocation(shaderProgram, 0, "outColor");
glLinkProgram(shaderProgram);
glUseProgram(shaderProgram);
// Vertex data specification
GLint posAttrib = glGetAttribLocation(shaderProgram, "position");
glEnableVertexAttribArray(posAttrib);
glVertexAttribPointer(posAttrib, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), 0);
GLint texAttrib = glGetAttribLocation(shaderProgram, "texcoord");
glEnableVertexAttribArray(texAttrib);
glVertexAttribPointer(texAttrib, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), (void *)(2 * sizeof(GLfloat)));
// Load Textures
//TODO: don't really need 2 textures, but just following along with example source code for now...
GLuint textures[2];
unsigned char* image;
int width, height;
width = pgmImage.GetWidth();
height = pgmImage.GetHeight();
image = (unsigned char *)pgmImage.GetData();
glGenTextures(2, textures);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textures[0]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RED_INTEGER, GL_UNSIGNED_BYTE, image);
glUniform1i(glGetUniformLocation(shaderProgram, "texData"), 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// Start program
glutMainLoop();
// Teardown
glDeleteTextures(2, textures);
glDeleteProgram(shaderProgram);
glDeleteShader(fragmentShader);
glDeleteShader(vertexShader);
glDeleteBuffers(1, &ebo);
glDeleteBuffers(1, &vbo);
glDeleteVertexArrays(1, &vao);
return 0;
}
As you had already found, the internalFormat and format of your glTexImage2D() call are incompatible:
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RED_INTEGER, GL_UNSIGNED_BYTE, image);
GL_RED_INTEGER is for integer texture types. For 1-component texture data with normalized textures, the correct format is GL_RED:
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RED, GL_UNSIGNED_BYTE, image);
For new code, I would always recommend to use sized internal types, even though unsized internal types like GL_RGB are still valid for backwards compatibility. So for a normalized texture with 3 8-bit components:
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, width, height, 0, GL_RED, GL_UNSIGNED_BYTE, image);
Your attempt at using GL_R8UI as the internal format failed because using integer textures requires additional changes, particularly in the shader code, where you would need to use usampler2D as the sampler type, and deal with getting integer values when you sample the textures. But in your case, that's not really what you wanted in the first place.