I'm using Deferred Shading method to render the scene, but I have a problem with a Skybox technique due to weird behaviour of Z-Buffer. I've created additional Framebuffer and attached 5 textures, one of which is being used as a depth buffer. First pass is a geometry pass, which fills the textures with needed data, second pass renders the final objects with textures and lightning applied to the main framebuffer, the last pass renders Skybox. The problem is Skybox being ignored (Z-Buffer check fails, so it is invisible).
When rendering a Skybox, I map the secondary framebuffer as a GL_READ_FRAMEBUFFER and main framebuffer (screen) as a GL_DRAW_FRAMEBUFFER, so the depth buffer of the secondary framebuffer can be used, then I set the depth function to GL_LEQUAL. And only if I change depth function to GL_GREATER (or GL_ALWAYS) the Skybox can be seen, however it is being rendered on top of the objects.
The Vertex Shader:
#version 330
layout (location = 0) in vec3 Position;
uniform mat4 M;
uniform mat4 V;
uniform mat4 P;
out vec3 TexCoord0;
void main()
{
vec4 MVP_Pos = P * V * M * vec4(Position, 1.0);
gl_Position = MVP_Pos.xyww;
TexCoord0 = Position;
}
Model matrix is a product of translation of the Skybox to the camera coordinates.
glDepthFunction set to GL_LEQUAL:
glDepthFunction set to GL_GREATER:
Contents of the Z-Buffer:
UPDATE 1: I've tried to use glBlitFramebuffer like that:
glBindFramebuffer(GL_READ_FRAMEBUFFER, m_fbo); //Additional framebuffer
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glDepthMask(GL_TRUE);
glBlitFramebuffer(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, GL_DEPTH_BUFFER_BIT, GL_NEAREST);
But it doesn't work. Main depth buffer contains array of black pixels.
UPDATE 2:
//FBO initialization
glGenFramebuffers(1, &m_fbo);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbo);
// Create gbuffer textures
glGenTextures(ARRAY_SIZE_IN_ELEMENTS(m_textures), m_textures);
glGenTextures(1, &m_depthTexture);
for (unsigned int i = 0; i < ARRAY_SIZE_IN_ELEMENTS(m_textures); i++) {
glBindTexture(GL_TEXTURE_2D, m_textures[i]);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, WindowWidth, WindowHeight, 0, GL_RGB, GL_FLOAT, NULL);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_TEXTURE_2D, m_textures[i], 0);
}
// depth buffer
glBindTexture(GL_TEXTURE_2D, m_depthTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32F, WindowWidth, WindowHeight, 0, GL_DEPTH_COMPONENT, GL_FLOAT,
NULL);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, m_depthTexture, 0);
GLenum DrawBuffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3 };
glDrawBuffers(ARRAY_SIZE_IN_ELEMENTS(DrawBuffers), DrawBuffers);
GLenum Status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (Status != GL_FRAMEBUFFER_COMPLETE) {
fprintf(stderr, "FB error, status: 0x%x\n", Status);
return false;
}
Skybox buffers:
GLfloat cube_vertices[] = {
// front
-1.0, -1.0, 1.0,
1.0, -1.0, 1.0,
1.0, 1.0, 1.0,
-1.0, 1.0, 1.0,
// back
-1.0, -1.0, -1.0,
1.0, -1.0, -1.0,
1.0, 1.0, -1.0,
-1.0, 1.0, -1.0,
};
GLushort cube_elements[] = {
// front
0, 1, 2,
2, 3, 0,
// top
3, 2, 6,
6, 7, 3,
// back
7, 6, 5,
5, 4, 7,
// bottom
4, 5, 1,
1, 0, 4,
// left
4, 0, 3,
3, 7, 4,
// right
1, 5, 6,
6, 2, 1,
};
When rendering a Skybox, I map the secondary framebuffer as a
GL_READ_FRAMEBUFFER and main framebuffer (screen) as a
GL_DRAW_FRAMEBUFFER, so the depth buffer of the secondary framebuffer
can be used,
That is not how things work. The GL_READ_FRAMEBUFFER is not relevant for the depth test. It is used as the source for opeations like glReadPixels or glBlitFramebuffer. But for any kind of rendering, only the GL_DRAW_FRAMEBUFFER is relevant. This includes the depth test.
Unfortuanly, you can't mix user-defined render targets like render buffers or textures with window-system provided buffers, so you just can't render to the final screen while using the specific depth test. So you either have to do an additional render pass to an FBO using the custom depth buffer, and blit the result to the screen, or you can blit the contents of the custom depth buffer to the window-system provided one and render with that.
I found a solution. Additional framebuffer had 32 bits/pixel, but main framebuffer had only 24, that prevented glBlitFramebuffer from working. So the proper Framebuffer initialization would look like that:
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, WindowWidth, WindowHeight, 0, GL_DEPTH_COMPONENT, GL_FLOAT,
NULL);
Related
Normally this code renders the image of the texture to screen. But if I now add the command glBindFramebuffer(GL_FRAMEBUFFER,0) to the code, it will not render anything. It renders the screens just in the color of glClearColor. I am working with QT so using QOpenGLWidget.
glViewport(0, 0, _width, _height);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glClearColor(0.0,0.0,0.0,1.0);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
glDisable(GL_DEPTH_TEST);
_program.bind();
glBindVertexArray(_vao);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, textureID);
glUniform1i(glGetUniformLocation(_program.programId(), "u_texture"), 1);
glDrawArrays(GL_TRIANGLES, 0, 6);
glBindVertexArray(0);
Want can go possibly wrong?
EDIT:
/* final.fsh */
# version 330 core
uniform sampler2D u_texture;
in vec4 qt_TexCoord0;
out vec4 fragColor;
void main(void)
{
fragColor = texture(u_texture, qt_TexCoord0.xy);
}
/* final.vsh */
# version 330 core
layout (location = 0) in vec3 a_position;
out vec4 qt_TexCoord0;
void main(void)
{
gl_Position = vec4(a_position, 1.0);
const mat4 B = mat4(0.5, 0.0, 0.0, 0.0,
0.0, 0.5, 0.0, 0.0,
0.0, 0.0, 0.5, 0.0,
0.5, 0.5, 0.5, 1.0);
qt_TexCoord0 = B * vec4(a_position, 1.0);
}
/* Loads VAO to GPU */
GLfloat max_ = 1.0;
GLfloat min_ = -1.0;
GLfloat vert[] = {
max_, max_, 0,
max_, min_, 0,
min_, max_, 0,
max_, min_, 0,
min_, min_, 0,
min_, max_, 0,
};
glGenVertexArrays(1, &_vao);
glBindVertexArray(_vao);
GLuint vbo;
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vert), vert, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat)*3, (GLvoid*)0);
glBindVertexArray(0);
As stated by G.M., and according to the docs, glBindFramebuffer(GL_FRAMEBUFFER, 0) "breaks the existing binding of a framebuffer object to the target". You need this call after having used your framebuffers to do some offscreen rendering. When you want to finally render to the screen, you have to render the the back buffer, by calling glDrawBuffer(GL_BACK).
So your render loop might look like
// Do some rendering stuff in n offscreen textures
glBindFramebuffer(GL_FRAMEBUFFER, the_buffer);
glDrawBuffers(n, buffers);
// Rendering calls
// Finally use the results for the final rendering
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glDrawBuffer(GL_BACK);
// Rendering calls
EDIT:
It appears you are using QOpenGLWidget as your OpenGL provider / windowing system. The Qt guys are using framebuffers to render their UI, and the content of the result of your QOpenGLWidget is drawn inside an FBO.
So, what it means (at least in my experience, there might be a better way to tackle this problem), is that you cannot render in the backbuffer anymore, you have to render in Qts framebuffer.
One way to do this (again, it might not be the best way at all, but it has worked for me), is to save the bound framebuffer at the begining of your rendering, and do your final rendering in this buffer. Which leads to
// First of all, save the already bound framebuffer
GLint qt_buffer;
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &qt_buffer);
// Do some rendering stuff in n offscreen textures
glBindFramebuffer(GL_FRAMEBUFFER, your_buffer);
glDrawBuffers(n, buffers);
// Rendering calls
// Finally use the results for the final rendering
if (glIsFramebuffer(qt_buffer))
{
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glDrawBuffer(GL_BACK);
}
else
{
glBindFramebuffer(GL_FRAMEBUFFER, qt_buffer);
glDrawBuffers(1, buffers);
}
// Rendering calls
I have the same issue and finally I find the cause is glBindFramebuffer(GL_FRAMEBUFFER, 0);
QOpenGLWidget's default framebuffer may not be 0, so you need to get it by calling QOpenGLContext::defaultFramebufferObject()
so change like this:
glViewport(0, 0, _width, _height);
glBindFramebuffer(GL_FRAMEBUFFER, defaultFramebufferObject()); //<-- change here
glClearColor(0.0,0.0,0.0,1.0);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
glDisable(GL_DEPTH_TEST);
_program.bind();
glBindVertexArray(_vao);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, textureID);
glUniform1i(glGetUniformLocation(_program.programId(), "u_texture"), 1);
glDrawArrays(GL_TRIANGLES, 0, 6);
glBindVertexArray(0);
I've been trying to implement shadow mapping into my OpenGL engine in SFML 2.2, and they don't seem to be rendering right. I believe I narrowed down the issue to the ortho projection used to calculate the shadows.
/* before the main loop, creating the depth buffer for shadow mapping */
glm::vec3 lightPos(glm::vec3(-45.f, 45.f, -40.f));
const GLuint SHADOW_WIDTH = 1024, SHADOW_HEIGHT = 1024;
GLuint depthMapFBO;
glGenFramebuffers(1, &depthMapFBO);
GLuint depthMap;
glGenTextures(1, &depthMap);
glBindTexture(GL_TEXTURE_2D, depthMap);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, SHADOW_WIDTH, SHADOW_HEIGHT, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
GLfloat borderColor[] = { 1.0, 1.0, 1.0, 1.0 };
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);
glBindFramebuffer(GL_FRAMEBUFFER, depthMapFBO);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthMap, 0);
glDrawBuffer(GL_NONE);
glReadBuffer(GL_NONE);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
/* in the main loop, sending information to the appropiate shaders and setting viewports */
glm::mat4 lightProjection, lightView;
glm::mat4 lightSpaceMatrix;
GLfloat near_plane = 1.f, far_plane = 300.f;
lightProjection = glm::ortho(-10.f, 10.f, -10.f, 10.f, near_plane, far_plane);
lightView = glm::lookAt(lightPos, glm::vec3(0.0f), glm::vec3(0.0, 1.0, 0.0));
lightSpaceMatrix = lightProjection * lightView;
glUseProgram(simpleDepthShader);
glUniformMatrix4fv(glGetUniformLocation(simpleDepthShader, "lightSpaceMat"), 1, GL_FALSE, glm::value_ptr(lightSpaceMatrix));
glViewport(0, 0, SHADOW_WIDTH, SHADOW_HEIGHT);
glBindFramebuffer(GL_FRAMEBUFFER, depthMapFBO);
glClear(GL_DEPTH_BUFFER_BIT);
RenderScene();
glBindFramebuffer(GL_FRAMEBUFFER, 0);
// reset viewport, and display the scene as normal
glViewport(0, 0, window.getSize().x, window.getSize().y);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUniform3fv(glGetUniformLocation(lightingShader, "lightPos_shade"), 1, &lightPos[0]);
glUniform3fv(glGetUniformLocation(lightingShader, "viewPos"), 1, &getPos()[0]);
glUniformMatrix4fv(glGetUniformLocation(lightingShader, "lightSpaceMat"), 1, GL_FALSE, glm::value_ptr(lightSpaceMatrix));
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, depthMap);
RenderScene();
I've applied the view and projection matrix to the camera to see what the light sees, and this was the result (along with the view from the depth buffer).
Here's what the scene looks like with the shadows (which the shadow for the stall doesn't even cast onto itself for some reason).
It seems that your shader doesn't fetch your shadow pixels correctly.
When you transform your vertices with your light matrix they are in the [-1, 1] range, but texture sampling is in the range [0, 1].
http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-16-shadow-mapping/
I'm currently trying to test out rendering to a framebuffer for various uses, but whenever I have an object(say a square) at a certain y-value, it appears "stretched", and then past a certain y-value or a certain x-value it seems to "thin out" and disappears. I have determined the x and y-values that it disappears at, but the coordinates seem to not have any rhyme or reason.
When I remove the framebuffer binding and render directly to the screen it draws the square perfectly fine, no matter the x or y-value.
Drawing a basic square(using immediate mode to remove possible errors) with a wide x-value looks like this:
Code here:
Window window("Framebuffer Testing", 1600, 900); //1600x900 right now
int fbowidth = 800, fboheight = 600;
mat4 ortho = mat4::orthographic(0, width, 0, height, -1.0f, 1.0f);
//trimmed out some code from shader creation that is bugless and unneccessary to include
Shader shader("basic"); shader.setUniform("pr_matrix", ortho);
Shader drawFromFBO("fbotest"); shader.setUniform("pr_matrix", ortho);
GLfloat screenVertices[] = {
0, 0, 0, 0, height, 0,
width, height, 0, width, 0, 0};
GLushort indices[] = {
0, 1, 2,
2, 3, 0 };
GLfloat texcoords[] = { //texcoords sent to the drawFromFBO shader
0, 0, 0, 1, 1, 1,
1, 1, 1, 0, 0, 0 };
IndexBuffer ibo(indices, 6);
VertexArray vao;
vao.addBuffer(new Buffer(screenVertices, 4 * 3, 3), 0);
vao.addBuffer(new Buffer(texcoords, 2 * 6, 2), 1);
GLuint fbo;
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, fbowidth, fboheight, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glBindTexture(GL_TEXTURE_2D, 0);
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture, 0);
if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
std::cout << "false" << std::endl;
glEnable(GL_TEXTURE_2D);
//the x-values mess up at ~783 thru 800 and the y-values at 0 thru ~313
while(!window.closed()) {
glClearColor(0.2f, 0.2f, 0.2f, 1.0f); //grey
window.clear(); //calls glclear for depth and color buffer
//bind framebuffer and shader
shader.enable(); //literally just calls glUseProgram(id) with the compiled shader id
glViewport(0, 0, fbowidth, fboheight);
glBindFramebuffer(GL_FRAMEBUFFER, fbo); //bind the fbo
glClearColor(1.0f, 0.0f, 1.0f, 1.0f); //set clear color to pink
glClear(GL_COLOR_BUFFER_BIT);
//render a red square to the framebuffer texture
glBegin(GL_QUADS); {
glColor3f(1.0f, 0.0f, 0.0f); //set the color to red
glVertex3f(700, 400, 0);
glVertex3f(700, 450, 0);
glVertex3f(750, 450, 0);
glVertex3f(750, 400, 0);
} glEnd();
shader.disable();
glBindFramebuffer(GL_FRAMEBUFFER, 0); //set framebuffer to the default
//render from framebuffer to screen
glViewport(0, 0, width, height);
drawFromFBO.enable();
glActiveTexture(GL_TEXTURE0);
drawFromFBO.setUniform1i("texfbo0", 0);
glBindTexture(GL_TEXTURE_2D, texture);
vao.bind();
ibo.bind();
glDrawElements(GL_TRIANGLES, ibo.getCount(), GL_UNSIGNED_SHORT, NULL);
ibo.unbind();
vao.unbind();
drawFromFBO.disable();
window.update();
}
If you want to see any thing extra, the file is located at my Github: here
I have two textures with same size attached to one fbo, and I want to render another texture into one of the attached textures, and I want to render a blue shape of the figure of the input texture to the other fbo attached texture.
the (updated) vertex shader:
#version 330
in vec2 coord;
out vec2 f_coord;
void main() {
gl_Position = vec4(coord, 0.0, 1.0);
f_coord = (1.0+coord)/2.0;
}
the (updated) fragment shader:
#version 330
uniform sampler2D my_texture;
in vec2 f_coord;
out vec4 FragData[2];
void main() {
if(texture(my_texture,f_coord).a == 0.0)
discard;
FragData[0]=texture(my_texture,f_coord);
FragData[1]=vec4(0.5, 0.5, 1.0, 1.0);
}
With this fragment shader everything works fine. The texture and the blue stamp of the texture contures are rendered properly.
Here is a screenshot:
http://s14.directupload.net/file/d/3487/kvkqdbl7_png.htm
But if I want to render the texture into gl_FragData[1] and the blue conture stamp into gl_FragData[0]
#version 330
uniform sampler2D my_texture;
in vec2 f_coord;
out vec4 FragData[2];
void main() {
if(texture(my_texture,f_coord).a == 0.0)
discard;
FragData[0]=vec4(0.5, 0.5, 1.0, 1.0);
FragData[1]=texture(my_texture,f_coord);
}
than I get two totally blue textures. The strange thing is: Both target textures are totally blue, but I have set the glViewport just to a part of the texture.
Here a screenshot:
http://s1.directupload.net/file/d/3487/9loqibdc_png.htm
The fbo attachments have the half screen size
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, glutGet(GLUT_WINDOW_WIDTH)/2, glutGet(GLUT_WINDOW_HEIGHT), 0, GL_RGBA, GL_BYTE, 0);
So I can render both textures to the screen for checking.
This is how I created the framebufferobject
void init_fbo()
{
glGenTextures(1, &fbo.texture0);
glBindTexture(GL_TEXTURE_2D, fbo.texture0);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, glutGet(GLUT_WINDOW_WIDTH)/2, glutGet(GLUT_WINDOW_HEIGHT), 0, GL_RGBA, GL_BYTE, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glGenTextures(1, &fbo.texture1);
glBindTexture(GL_TEXTURE_2D, fbo.texture1);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, glutGet(GLUT_WINDOW_WIDTH)/2, glutGet(GLUT_WINDOW_HEIGHT), 0, GL_RGBA, GL_BYTE, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glBindTexture(GL_TEXTURE_2D, 0);
glGenFramebuffers(1, &fbo.fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo.fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
fbo.texture0, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D,
fbo.texture1, 0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
I use those global struct variables
struct
{
GLuint fbo;
GLuint texture0;
GLuint texture1;
} fbo;
struct
{
GLuint program;
GLint uni_texture;
GLint att_coord;
} shader_fbo;
struct
{
GLuint program;
GLint uni_texture;
GLint att_coord;
} shader_screen;
And this is my render function
void render()
{
GLenum buffers[2];
GLfloat vertices[] = { -1.0, -1.0,
-1.0, 1.0,
1.0, -1.0,
1.0, 1.0 };
GLubyte indices[] = { 0, 1, 2,
1, 2, 3 };
/*render to mrt fbo*/
glUseProgram(shader_fbo.program);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture.texID);
glUniform1i(shader_fbo.uni_texture, 0);
glEnableVertexAttribArray(shader_fbo.att_coord);
glVertexAttribPointer(shader_fbo.att_coord,
2,
GL_FLOAT,
GL_FALSE,
0,
vertices);
glBindFramebuffer(GL_FRAMEBUFFER, fbo.fbo);
buffers[0] = GL_COLOR_ATTACHMENT0;
buffers[1] = GL_COLOR_ATTACHMENT1;
glDrawBuffers(2, buffers);
glViewport(0, 0,
texture.width, texture.height);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture.texID);
glUniform1i(shader_fbo.uni_texture, 0);
glClear(GL_COLOR_BUFFER_BIT);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, indices);
glDisableVertexAttribArray(shader_fbo.att_coord);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindTexture(GL_TEXTURE_2D, 0);
/*render both textures now to screen*/
glUseProgram(shader_screen.program);
glEnableVertexAttribArray(shader_screen.att_coord);
glVertexAttribPointer(shader_screen.att_coord,
2,
GL_FLOAT,
GL_FALSE,
0,
vertices);
/*render the first texture to the left side of the screen*/
glViewport(0, 0,
glutGet(GLUT_WINDOW_WIDTH)/2, glutGet(GLUT_WINDOW_HEIGHT));
glClear(GL_COLOR_BUFFER_BIT);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, fbo.texture0);
glUniform1i(shader_screen.uni_texture, 0);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, indices);
/*render the second texture to the right side of the screen*/
glViewport(glutGet(GLUT_WINDOW_WIDTH)/2, 0,
glutGet(GLUT_WINDOW_WIDTH)/2, glutGet(GLUT_WINDOW_HEIGHT));
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, fbo.texture1);
glUniform1i(shader_screen.uni_texture, 0);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, indices);
glutSwapBuffers();
}
I implemented a volume rendering demo application a few months ago. Everything worked fine in Windows XP-32bits. I used OpenGL -glew and SFML2.0-rc as a windowing&input library.
Now. I moved to windows 7-64bits just recently.
The program did not work out of the box, SFML seemed to crash. I changed the windowing library to GLFW, still using Glew. By going through the code i realized the very basic render to texture technique did not work anymore.
So i broke everything down to a minimal case so i could present it to you. (I also made a port to Qt5.0.2 to cross-check my assumptions : same diagnosis).
So here is the problem :
The program is supposed to render a simple unit cube with front-face culling to a texture in pass 1. Then in pass 2 i switch to back-face culling and render the same cube again. In the fragment shader (pass 2) i have the option to read the texture (from pass 1) and write it to the output : but i get a big black screen when i should see the front-face culled cube ...
Initialization code :
glGenFramebuffers(1, &raycastingFrameBuffer);
glBindFramebuffer(GL_FRAMEBUFFER, raycastingFrameBuffer);
glGenTextures(1, &cubeRenderTexture);
glBindTexture(GL_TEXTURE_2D, cubeRenderTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, viewWidth, viewHeight, 0, GL_RGBA, GL_FLOAT, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_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);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, cubeRenderTexture, 0);
GLenum DrawBuffers[1] = {GL_COLOR_ATTACHMENT0};
glDrawBuffers(1, DrawBuffers);
if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
return false;
glBindFramebuffer(GL_FRAMEBUFFER, 0);
Render passes :
// PASS ONE :
// render the unit cube (with front face culling) to texture
// we end up with a texture whose colors represent outgoing rays locations on the box
//
glBindFramebuffer(GL_FRAMEBUFFER, raycastingFrameBuffer);
glEnable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);
glViewport(0, 0, viewWidth, viewHeight);
glCullFace(GL_FRONT);
glClearColor(0.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(shaderRaycasting1.getProgramID());
glBindBuffer(GL_ARRAY_BUFFER, cube_VBO_ID);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (char*)NULL + 0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (char*)NULL + 108*sizeof(float));
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glUniformMatrix4fv(glGetUniformLocation(shaderRaycasting1.getProgramID(), "modelview"), 1, GL_TRUE, modelview.getData());
glUniformMatrix4fv(glGetUniformLocation(shaderRaycasting1.getProgramID(), "projection"), 1, GL_TRUE, projection.getData());
glDrawArrays(GL_TRIANGLES, 0, 36);
glDisableVertexAttribArray(1);
glDisableVertexAttribArray(0);
glUseProgram(0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glEnable(GL_DEPTH_TEST);
// PASS TWO :
// render the unit cube (with back face culling this time)
// we get colors representing ray entrance locations on the box
//
glViewport(0, 0, viewWidth, viewHeight);
glCullFace(GL_BACK);
glClearColor(0.0, 0.0, 0.0, 0.0);
glClearDepth(1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(shaderRaycasting2.getProgramID());
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, cubeRenderTexture);
glUniform1i(cubeRenderTextureID, 0);
glUniform1i(glGetUniformLocation(shaderRaycasting2.getProgramID(), "displayWidth"), (GLint) viewWidth);
glUniform1i(glGetUniformLocation(shaderRaycasting2.getProgramID(), "displayHeight"), (GLint) viewHeight);
glBindBuffer(GL_ARRAY_BUFFER, cube_VBO_ID);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (char*)NULL + 0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (char*)NULL + 108*sizeof(float));
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glUniformMatrix4fv(glGetUniformLocation(shaderRaycasting1.getProgramID(), "modelview"), 1, GL_TRUE, modelview.getData());
glUniformMatrix4fv(glGetUniformLocation(shaderRaycasting1.getProgramID(), "projection"), 1, GL_TRUE, projection.getData());
glDrawArrays(GL_TRIANGLES, 0, 36);
glDisableVertexAttribArray(1);
glDisableVertexAttribArray(0);
glActiveTexture(0);
glUseProgram(0);
... and finally the minimal fragment shader :
#version 330
in vec3 color;
uniform int displayWidth;
uniform int displayHeight;
uniform sampler2D cubeTex;
layout (location = 0) out vec4 outColor;
void main()
{
float viewWidth = displayWidth;
float viewHeight = displayHeight;
vec3 boxIn = color;
vec2 cubeCoord = vec2( (gl_FragCoord.x - 0.5) / viewWidth, (gl_FragCoord.y - 0.5) / viewHeight);
vec3 boxOut = texture(cubeTex, cubeCoord).rgb;
vec3 rayColor = boxOut;
outColor = vec4(rayColor, 1); // i get a black screen here ...
}
Some last words :
- Everything compiles with no warnings, no errors (same for Qt 5.0.2 port of the demo)
- I tried every possible little "tweaking" like glEnable(...), changing opengl version, using texelFetch, and what not ... obviously i can't find what's wrong with this code.
- The original code was much more complex and did run, but on XP and not on Win7.
- etc.
Did you install the original vendor drivers for your GPU as downloaded from the vendor's driver support website, or do you still have installed the crippled versions that are shipped with Windows 7?
The drivers shipping with Windows 7 do not offer modern OpenGL support. Microsoft strips them of anything OpenGL and the default OpenGL implementation of Windows-7 is just a OpenGL-1.4 emulation on top of Direct3D.
If you didn't already, then download the original drivers from your GPU's vendor and install those, then report back if this changed the outcome.