When Im rendering to on-screen buffer everything goes fine, but when reading pixels from FrameBuffer with glReadPixels it always returns 0.
The pseudocode is the following:
Bind texture to FrameBuffer:
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
int width, height;
width = 2;
height = 2;
float texture_data[] = {
1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f
};
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_FLOAT, texture_data);
GLuint framebuffer;
glGenFramebuffers(1, &framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
GLint texture_coord_attribute = glGetAttribLocation(program, "texture_coord");
glEnableVertexAttribArray(texture_coord_attribute);
glVertexAttribPointer(texture_coord_attribute, 2, GL_FLOAT, GL_FALSE,
sizeof(vertices[0]), (void*)(sizeof(float) * 5));
Fragment/Vertex shaders:
static const char* vertex_shader_text =
"#version 330\n""
"attribute vec2 vPos;\n"
"attribute vec2 texture_coord;\n"
"varying vec2 Texcoord;\n"
"void main()\n"
"{\n"
" gl_Position = vec4(vPos, 0.0, 1.0);\n"
" Texcoord = texture_coord;\n"
"}\n";
static const char* fragment_shader_text =
"#version 330\n"
"varying vec2 Texcoord;\n"
"uniform sampler2D tex;\n"
"void main()\n"
"{\n"
" gl_FragColor = texture(tex, Texcoord);\n"
"}\n";
Read Pixels in Main loop:
glViewport(0, 0, 720, 480);
glUseProgram(program);
glDrawArrays(GL_TRIANGLES, 0, 6);
GLubyte pixels[3] = {0};
glReadBuffer(GL_COLOR_ATTACHMENT0);
glReadPixels(360, 240, 1, 1, GL_RGB, GL_FLOAT, pixels);
// Any value returns 0 not only 360 and 240
printf("|%f||%f||%f|\n", pixels[0], pixels[1], pixels[2]);
glfwSwapBuffers(window);
glfwPollEvents();
This is the pipeline I follow. What is wrong here?
Thanks.
The 5th and 6th parameter (format and type) of glReadPixels specifies the format and data type of the target pixel data.
Since you want to read to a buffer with the element data type GLubyte, the type has to be GL_BYTE.
Change your code like this:
glReadPixels(360, 240, 1, 1, GL_RGB, GL_BYTE, pixels);
Or read the data to a buffer of type GLfloat:
GLfloat pixels[3];
glReadPixels(360, 240, 1, 1, GL_RGB, GL_FLOAT, pixels);
Note, what you do, is to read 12 bytes (sizeof(float)*3) to a buffer with a size of 3 bytes (GLubyte pixels[3]). This means a part of the floating point value which represents the red color channel is stored to the buffer. The rest overwrites some memory with bad access.
Related
I am using MS visual studio 2019 and just learning opengl in c++. I started learning from https://learnopengl.com and it showed many ways to load textures . I just used stb image for loading textures and here's the function for loading a texture :
static unsigned int loadTexture(char const* path)
{
unsigned int textureID;
glGenTextures(1, &textureID);
int width, height, nrComponents;
unsigned char* data = stbi_load(path, &width, &height, &nrComponents, 0);
if (data)
{
GLenum format;
if (nrComponents == 1)
format = GL_RED;
else if (nrComponents == 3)
format = GL_RGB;
else if (nrComponents == 4)
format = GL_RGBA;
glBindTexture(GL_TEXTURE_2D, textureID);
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
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_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
stbi_image_free(data);
}
else
{
std::cout << "Texture failed to load at path: " << path << std::endl;
stbi_image_free(data);
}
return textureID;
}
I tried loading it in a rectangle but somehow it doesn't seem to print properly on it. I'm stuck for a couple of hours and still couldn't find what mistake I've made.
here's the code for initializing the VAO and VBO:
inline void InitTextureBuffer(const char* img_filepath)
{
texture_shader.Bind();
tex_img_id = loadTexture(img_filepath);
glGenVertexArrays(1, &tex_VAO);
glGenBuffers(1, &tex_VBO);
glBindVertexArray(tex_VAO);
glBindBuffer(GL_ARRAY_BUFFER, tex_VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 6 * 4, NULL, GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 * sizeof(float)));
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
texture_shader.Unbind();
}
and function to draw the rect :
inline void Draw_Rectangle_IMG(_Point _min, _Point _max)
{
glActiveTexture(GL_TEXTURE0);
glBindVertexArray(tex_VAO);
texture_shader.Bind();
float vertices[] =
{
_min.x, _min.y, 0.0f, 0.0f ,
_max.x, _min.y, 0.0f, 1.0f ,
_max.x, _max.y, 1.0f, 1.0f ,
_min.x, _min.y, 0.0f, 0.0f ,
_max.x, _max.y, 1.0f, 1.0f ,
_min.x, _max.y, 1.0f, 0.0f ,
};
glBindTexture(GL_TEXTURE_2D, tex_img_id);
glBindBuffer(GL_ARRAY_BUFFER, tex_VBO);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glDrawArrays(GL_TRIANGLES, 0, 6);
glBindVertexArray(0);
glBindTexture(GL_TEXTURE_2D, 0);
texture_shader.Unbind();
}
the shaders I've used:
const std::string texture_shader_vs =
{
"#version 330 core\n"
"layout(location = 0) in vec2 aPos;\n"
"layout(location = 1) in vec2 aTexCoord;\n"
"\n"
"out vec2 TexCoord;\n"
"\n"
"void main()\n"
"{\n"
" gl_Position = vec4(aPos,0.0f, 1.0f);\n"
" TexCoord = aTexCoord;\n"
"}\n"
};
const std::string texture_shader_fs =
{
"#version 330 core\n"
"out vec4 FragColor;\n"
"\n"
"in vec2 TexCoord;\n"
"\n"
"// texture sampler\n"
"uniform sampler2D texture1;\n"
"\n"
"void main()\n"
"{\n"
" FragColor = texture(texture1, TexCoord);\n"
"}\n"
};
And the function where I did the calls:
_Point p1, p2;
p1 = _Point(-0.5f, -0.25f);
p2 = _Point(0.5f, 0.25f);
ogl.InitTextureBuffer("resources/textures/1.png");
while (!glfwWindowShouldClose(ogl.GetWindow()))
{
glClear(GL_COLOR_BUFFER_BIT);
ogl.Draw_Rectangle_IMG(p1, p2);
glfwSwapBuffers(ogl.GetWindow());
glfwPollEvents();
}
The texture i tried to print is :
but the result I get is
I can't seem to find the error .Any help would be appreciated. Thanks!
The association of the texture coordinates to the vertices is wrong. Change to:
float vertices[] =
{
_min.x, _min.y, 0.0f, 1.0f,
_max.x, _min.y, 1.0f, 1.0f,
_max.x, _max.y, 1.0f, 0.0f,
_min.x, _min.y, 0.0f, 1.0f,
_max.x, _max.y, 1.0f, 0.0f,
_min.x, _max.y, 0.0f, 0.0f,
};
By default OpenGL assumes that the start of each row of an image is aligned to 4 bytes.
This is because the GL_UNPACK_ALIGNMENT parameter by default is 4. When a RGB image with 3 color channels is loaded to a texture object and 3*width is not divisible by 4 this may cause a misalignment.
Change the alignment by setting the GL_UNPACK_ALIGNMENT to 1, before specifying the texture image with glTexImage2D:
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data);
When you remove glGenerateMipmap(GL_TEXTURE_2D);, then you have to change the minifying function (GL_TEXTURE_MIN_FILTER) as well. Since the filter is GL_LINEAR_MIPMAP_LINEAR, the texture would be "Mipmap Incomplete" if you do not change the minimize function to GL_NEAREST or GL_LINEAR.
I am attempting to draw a png file using OpenGL and seem to have a problem with how I am setting up the textures.
Main.cpp:
float positions[] = {
-1.0f, -1.0f,
0.0f, 1.0f,
1.0f, 1.0f,
};
float texCoords[] = {
-1.0f, -1.0f,
-1.0f, 1.0f,
1.0f, 1.0f,
};
unsigned int buffer;
glGenBuffers(1, &buffer);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(positions), positions, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void*)0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
unsigned int texBuffer;
glGenBuffers(1, &texBuffer);
glBindBuffer(GL_ARRAY_BUFFER, texBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(texCoords), texCoords, GL_STATIC_DRAW);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void*)0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
int w;
int h;
int comp;
unsigned char* image = stbi_load("res/images/background_level.png", &w, &h, &comp, STBI_rgb_alpha);
if (image == nullptr)
throw(std::string("Failed to load texture"));
//std::cout << image << std::endl;
unsigned int m_texture;
glGenTextures(1, &m_texture);
glBindTexture(GL_TEXTURE_2D, m_texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
if (comp == 3)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, image);
else if (comp == 4)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, image);
glBindTexture(GL_TEXTURE_2D, 0);
stbi_image_free(image);
/* Loop until the user closes the window */
while (!glfwWindowShouldClose(window))
{
/* Render here */
glClearColor(1.0, 1.0, 1.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
// draw our first triangle
glUseProgram(programID);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, 0);
int uniformLoc = glGetUniformLocation(programID, "tex");
glUniform1i(uniformLoc, 0);
glDrawArrays(GL_TRIANGLES, 0, 3);
/* Swap front and back buffers */
glfwSwapBuffers(window);
/* Poll for and process events */
glfwPollEvents();
}
vertex.shader:
#shader VERTEX
#version 330 core
layout (location=0) in vec2 vert;
layout (location=1) in vec2 vertTexCoord;
out vec2 fragTexCoord;
void main() {
// Pass the tex coord straight through to the fragment shader
fragTexCoord = vertTexCoord;
gl_Position = vec4(vert, 0, 1);
}
fragment.shader:
#shader FRAGMENT
#version 330 core
uniform sampler2D tex; //this is the texture
in vec2 fragTexCoord; //this is the texture coord
out vec4 finalColor; //this is the output color of the pixel
void main() {
//finalColor = vec4(1.0, 1.0, 1.0, 1.0);
finalColor = texture(tex, fragTexCoord);
}
If I swap the line commented out in the fragment shader, I get an all white triangle rendered. However with the line attempting to use the texture, the triangle comes out all black. I am just beginning with OpenGL so I don't necessarily have all of the beginning concepts down pat. Textures may be ahead of my skill level but I figured it couldn't hurt to try and ask here as someone may be able to show me where I have things confused.
You are calling glBindTexture(GL_TEXTURE_2D, 0) instead of glBindTexture(GL_TEXTURE_2D, m_texture) inside the renderloop. With this command, a texture is bound to the currently active texture unit.
I am really having nightmare to achieve what I required in OpenGles 2.0
Before posting the code reference, let me tell what I need.
I have 2D texture fragment shader. On top of the texture I want to draw red color line. I am able to draw the line but coloring to red is not working.
Shader declaration:
static const char s_v_shader[] =
"attribute vec4 vPosition; \n"
"attribute vec2 my_Texcoor; \n"
"uniform mat4 u_TransMatrix; \n"
"varying vec2 vTexcoor; \n"
"void main() \n"
"{ \n"
" vTexcoor = my_Texcoor; \n"
" gl_Position = u_TransMatrix*vPosition; \n"
"} \n";
static const char s_f_shader[] =
"precision mediump float;\n"
"uniform sampler2D my_Sampler; \n"
"varying vec2 vTexcoor; \n"
"void main() \n"
"{ \n"
" vec4 tex = texture2D(my_Sampler, vTexcoor); \n"
" gl_FragColor = tex; \n"
"} \n";
On top of texture I am rendering video frames from camera in infinite loop.
Before rendering video, I am setting up co-ordinates of 2D texture with below code.
Now I will explain my code from main function
main()
{
const GLfloat vertices[][2] = {
{ -1.0f, -1.0f},
{ 1.0f, -1.0f},
{ -1.0f, 1.0f},
{ 1.0f, 1.0f}
};
const GLfloat texcoords[][2] = {
{ 0.0f, 1.0f},
{ 1.0f, 1.0f},
{ 0.0f, 0.0f},
{ 1.0f, 0.0f}
};
GLfloat transformMatrix[16] =
{
1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f
};
// setup OpenGl environment......
Setup_coordinates()
}
Setup_coordinates()
{
LoadShaders(s_v_shader, s_f_shader);
-- Complete function defined below
// By now I should be using shader program.
// Grab location of shader attributes.
GLint locVertices = glGetAttribLocation(programHandle, "vPosition");
GLint locTexcoord = glGetAttribLocation(programHandle, "my_Texcoor");
// Transform Matrix is uniform for all vertices here.
GLint locTransformMat = glGetUniformLocation(programHandle, "u_TransMatrix");
GLint locSampler = glGetUniformLocation(programHandle, "my_Sampler");
/* Create the texture. */
glGenTextures(1, &gTexObj);
glBindTexture(GL_TEXTURE_2D, gTexObj);
if (gTexObj == 0)
{
printf("Could not load the texture \n");
return -1;
}
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glUniformMatrix4fv(locTransformMat, 1, GL_FALSE, transformMatrix);
glUniform1i(locSampler, 0);
glClearColor(0.0f, 0.5f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT);
while(1) -- Infinite loop to render video frames on 2D texture and draw red color line.
{
// enable vertex arrays to push the data.
glEnableVertexAttribArray(locVertices);
glEnableVertexAttribArray(locTexcoord);
// set data in the arrays.
glVertexAttribPointer(locVertices, 2, GL_FLOAT, GL_FALSE, 0, &vertices[0][0]);
glVertexAttribPointer(locTexcoord, 2, GL_FLOAT, GL_FALSE, 0, &texcoords[0][0]);
Render video frames logic goes here...................................
Each frame of video is abosultely rendering fine.
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
Now comes the tricky part to draw the line and color it with red.
float red_left_1[] =
{
-0.85f, -0.9f, -0.6f, -0.5f,
};
glVertexAttribPointer ( 1, 2, GL_FLOAT, GL_FALSE, 0, red_left_1 );
glEnableVertexAttribArray (1 );
glDrawArrays ( GL_LINES , 0, 2 );
glLineWidth( width_test );
}
}
void LoadShaders(const char * vShader, const char * pShader)
{
vertShaderNum = glCreateShader(GL_VERTEX_SHADER);
pixelShaderNum = glCreateShader(GL_FRAGMENT_SHADER);
if (CompileShader(vShader, vertShaderNum) == 0)
{
printf("%d: PS compile failed.\n", __LINE__);
return;
}
if (CompileShader(pShader, pixelShaderNum) == 0)
{
printf("%d: VS compile failed.\n", __LINE__);
return;
}
programHandle = glCreateProgram();
glAttachShader(programHandle, vertShaderNum);
glAttachShader(programHandle, pixelShaderNum);
// Bind vPosition to attribute 0
glBindAttribLocation ( programHandle, 0, "vPosition" );
glLinkProgram(programHandle);
// Check if linking succeeded.
GLint linked = 0;
glGetProgramiv(programHandle, GL_LINK_STATUS, &linked);
if (!linked)
{
printf("%d: Link failed.\n", __LINE__);
// Retrieve error buffer size.
GLint errorBufSize, errorLength;
glGetShaderiv(programHandle, GL_INFO_LOG_LENGTH, &errorBufSize);
char * infoLog = (char*)malloc(errorBufSize * sizeof (char) + 1);
if (infoLog)
{
// Retrieve error.
glGetProgramInfoLog(programHandle, errorBufSize, &errorLength, infoLog);
infoLog[errorBufSize + 1] = '\0';
fprintf(stderr, "%s", infoLog);
free(infoLog);
}
return;
}
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glUseProgram(programHandle);
}
Most of the genius peoples suggested to declare one more shader as above but replace uniform sampler2D my_Sampler with uniform vec4 color.
void main()
{
gl_FragColor = color
}
Then switch between these shader programs while showing texture and drawing color lines using glUseProgram.
I tried and absolutely given up as switching to shader program for drawing lines is not working.
Here is code for generating a colored 1x1 texture that you can use for your line (goes in your main or Setup_coordinates). With this solution you won't need another shader.
GLuint lineTexture;
glGenTextures(1, &lineTexture);
unsigned char red[4] = { 255, 0, 0, 255};
glBindTexture(GL_TEXTURE_2D, lineTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, red);
glBindTexture(GL_TEXTURE_2D, 0);
Before calling glDrawArrays, use this to switch to the correct texture.
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, <lineTexture or gTexObj>);
glUniform1i(locSampler, 0);
A more general solution (that I personally implement in my OpenGL projects) is to create a white texture, add a color uniform to your shader and multiply the uniform with the texture2D return value. With this method you can create different colored lines and graphics from the same white texture, only changing the color uniform. For the video frames, you would send in a white color and the pixels will remain unchanged. This will require very few changes to your code, I'm sure you can figure it out if you think it sounds better. :)
I want to draw yuv image that i got from JPEG file with help FFMPEG processing using OP. Original JPEG image size 640x480 and output YUV image does not have any strides. There are shaders i use:
const GLchar* vertexSource =
"in vec2 position;"
"in vec2 texcoord;"
"out vec2 Texcoord;"
"void main() {"
" Texcoord = texcoord;"
" gl_Position = vec4(position, 0.0, 1.0); }";
const GLchar* fragmentSource = ""
"uniform sampler2D y_tex;"
"uniform sampler2D u_tex;"
"uniform sampler2D v_tex;"
"in vec2 Texcoord;"
"layout( location = 0 ) out vec4 fragcolor;"
""
"const vec3 R_cf = vec3(1.164383, 0.000000, 1.596027);"
"const vec3 G_cf = vec3(1.164383, -0.391762, -0.812968);"
"const vec3 B_cf = vec3(1.164383, 2.017232, 0.000000);"
""
"void main() {"
" float y = texture(y_tex, Texcoord).r;"
" float u = texture(u_tex, Texcoord).r;"
" float v = texture(v_tex, Texcoord).r;"
" vec3 yuv = vec3(y,u,v);"
" fragcolor = vec4(0.0, 0.0, 0.0, 1.0);"
" fragcolor.r = dot(yuv, R_cf);"
" fragcolor.g = dot(yuv, G_cf);"
" fragcolor.b = dot(yuv, B_cf); }";
Below is data preparing code:
GLuint elements[] = {
0, 1, 2,
2, 3, 0
};
static GLfloat vertices[] = {
-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
};
GLuint vbo;
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
GLuint ebo;
glGenBuffers(1, &ebo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(elements), elements, GL_STATIC_DRAW);
GLint m_posAttr = glGetAttribLocation(shaderProgram, "position");
GLint m_texAttr = glGetAttribLocation(shaderProgram, "texcoord");
glEnableVertexAttribArray(m_posAttr);
glEnableVertexAttribArray(m_texAttr);
glVertexAttribPointer(m_posAttr, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), 0);
glVertexAttribPointer(m_texAttr, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat),
(void*)(2 * sizeof(GLfloat)));
// FFMPEG processing inside
AVFrame* frame = decodeFrame("c:\\test2.jpg");
GLuint ytex;
glGenTextures(1, &ytex);
glActiveTexture(GL_TEXTURE0);
glUniform1i(glGetUniformLocation(shaderProgram, "y_tex"), 0);
glBindTexture(GL_TEXTURE_2D, ytex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, frame->width, frame->height, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, frame->data[0]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
GLuint utex;
glGenTextures(1, &utex);
glActiveTexture(GL_TEXTURE1);
glUniform1i(glGetUniformLocation(shaderProgram, "u_tex"), 1);
glBindTexture(GL_TEXTURE_2D, utex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, frame->width / 2, frame->height / 2, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, frame->data[1]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
GLuint vtex;
glGenTextures(1, &vtex);
glActiveTexture(GL_TEXTURE2);
glUniform1i(glGetUniformLocation(shaderProgram, "v_tex"), 2);
glBindTexture(GL_TEXTURE_2D, vtex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, frame->width / 2, frame->height / 2, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, frame->data[2]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
And very simple draw cicle:
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glfwSwapBuffers(window);
But all i got is black screen. Can someone point out my mistakes?
I am trying to do a basic shadow map but for some reason, It doesn't render properly.
Video of the Problem
I render the house using a flat shader:
int shadowMapWidth = WINDOW_SIZE_X * (int)SHADOW_MAP_RATIO;
int shadowMapHeight = WINDOW_SIZE_Y * (int)SHADOW_MAP_RATIO;
// Rendering into the shadow texture.
glActiveTexture(GL_TEXTURE0);
CALL_GL(glBindTexture(GL_TEXTURE_2D, shadowTexture));
// Bind the framebuffer.
CALL_GL(glBindFramebuffer(GL_FRAMEBUFFER, shadowFBO));
//Clear it
CALL_GL(glClear(GL_DEPTH_BUFFER_BIT));
CALL_GL(glViewport(0, 0, shadowMapWidth, shadowMapHeight));
CALL_GL(glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE));
//Render stuff
flatShader.use();
flatShader["baseColor"] = glm::vec4(1.0f,1.0f,1.0f,1.0f);
flatShader["pvm"] = projectionMatrix*pointLight.viewMatrix*cursor.modelMatrix;
cursor.draw(); //binds the vao and draws
// Revert for the scene.
CALL_GL(glBindFramebuffer(GL_FRAMEBUFFER, 0));
CALL_GL(glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE));
CALL_GL(glViewport(0, 0, WINDOW_SIZE_X, WINDOW_SIZE_Y));
Notice that I only render the house. I don't render the floor in the depth-buffer pass.
Following this I render the quad that represents the floor using the following shader pair:
/* [VERT] */
#version 330
in vec3 in_Position;
in vec2 in_TexCoord;
uniform mat4 shadowMatrix;
uniform mat4 mvp;
out vec2 UV;
out vec4 shadowProj;
void main()
{
gl_Position = mvp*vec4(in_Position,1.0);
shadowProj = shadowMatrix*vec4(in_Position,1.0);
UV = in_TexCoord;
}
And the Fragment Shader:
/* [FRAG] */
#version 330
in vec2 UV;
in vec4 shadowProj;
out vec4 fragColor;
uniform sampler2D texturex;
uniform sampler2DShadow shadowMap;
void main()
{
fragColor = vec4(texture(texturex, UV).rgb,1);
float shadow = 1.0;
shadow = textureProj(shadowMap,shadowProj);
fragColor *= shadow;
}
I then draw the house again in color and ... the floor:
textureShader.use();
glUniform1i(baseImageLoc, 0); //Texture unit 0 is for base images.
glUniform1i(shadowMapLoc, 1); //Texture unit 1 is for shadow maps.
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, floorTexture);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, shadowTexture);
textureShader["shadowMatrix"] = projectionMatrix*pointLight.viewMatrix*floorMatrix;
textureShader["mvp"] = projectionMatrix*viewMatrix*floorMatrix;
CALL_GL(glBindVertexArray(floorVAO));
CALL_GL(glDrawArrays(GL_TRIANGLES,0,18));
glfwSwapBuffers();
Has anybody seen this behavior before? Any idea what could be wrong? By the way, the light's coordinates place it directly on top of the house so the shadow should be directly below the house on the floor (but it ends up sideways).
For reference here is how I generate the shadow FBO:
int shadowMapWidth = WINDOW_SIZE_X * (int)SHADOW_MAP_RATIO;
int shadowMapHeight = WINDOW_SIZE_Y * (int)SHADOW_MAP_RATIO;
glGenTextures(1, &shadowTexture);
glBindTexture(GL_TEXTURE_2D, shadowTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, shadowMapWidth, shadowMapHeight, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LESS);
glTexImage2D(GL_TEXTURE_2D,0,GL_DEPTH_COMPONENT,shadowMapWidth,shadowMapHeight,0,GL_DEPTH_COMPONENT,GL_FLOAT,NULL);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_COMPARE_MODE,GL_COMPARE_R_TO_TEXTURE);
glBindTexture(GL_TEXTURE_2D, 0); //unbind the texture
glGenFramebuffers(1, &shadowFBO);
glBindFramebuffer(GL_FRAMEBUFFER, shadowFBO);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, shadowTexture, 0);
glDrawBuffer(GL_NONE);
glReadBuffer(GL_NONE);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
{ printf("GL_FRAMEBUFFER_COMPLETE error 0x%x", glCheckFramebufferStatus(GL_FRAMEBUFFER)); }
glClearDepth(1.0f); glEnable(GL_DEPTH_TEST);
// Needed when rendering the shadow map. This will avoid artifacts.
glPolygonOffset(1.0f, 0.0f); glBindFramebuffer(GL_FRAMEBUFFER, 0);
//to convert the texture coordinates to -1 ~ 1
GLfloat biasMatrixf[] = {
0.5f, 0.0f, 0.0f, 0.0f,
0.0f, 0.5f, 0.0f, 0.0f,
0.0f, 0.0f, 0.5f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f };
biasMatrix = glm::make_mat4(biasMatrixf);
It looks like you forgot to multiply your shadow matrix by the bias matrix.