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/
Related
So, i have this assignment about double pass rendering to compute shadows and I am trying to store the depth value of each of the objects of a scene and rendering them as a texture in another object.
I am using OpenGL, I don't really know where the error could be, but when analyzing a capture with RenderDoc, it says that the FBO (FrameBufferObject) is unused and also interprets what should be my 1st pass, a depth only pass, as a color pass.
/*-This is how I create the FBO and the texture to render the depth-*/
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
// Create texture for Depth image (first pass)
glGenTextures(1, &depthTexture);
glBindTexture(GL_TEXTURE_2D, depthTexture);
// Give pixel data to opengl
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, 1024, 1024, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, nullptr);
// WITH PCF for anti-aliasing shadow edges
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
glGenFramebuffers(1, &FBO);
glBindFramebuffer(GL_FRAMEBUFFER, FBO);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D,
depthTexture, 0);
glDrawBuffer(GL_NONE);
glReadBuffer(GL_NONE);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
/*---------------------------END------------------------------------*/
/*---This is how I render all the objects (1st and second pass)-----*/
glViewport(0, 0, 1024, 1024);
glClearColor(0.3f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
cube.FirstPass(light.getPos());
plane.FirstPass(light.getPos());
cone1.FirstPass(light.getPos());
cone2.FirstPass(light.getPos());
glFlush();
glFinish();
glViewport(0, 0, WIDTH, HEIGHT);
glClearColor(0.3f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
cube.display(&cam, light.getPos());
plane.display(&cam, light.getPos());
viewport.display(&cam, light.getPos());
cone1.display(&cam, light.getPos());
cone2.display(&cam, light.getPos());
/*---------------------------END------------------------------------*/
/*---------This is how I do First Pass---------*/
//Here goes first pass
glBindFramebuffer(GL_FRAMEBUFFER, sceneManager.getFBO());
glClear(GL_DEPTH_BUFFER_BIT);
glUseProgram(DepthPass.shader);
glm::mat4 mtx = glm::perspective(glm::radians(60.0f), 1024.0f / 1024.0f, 5.0f, 40.0f);
DepthPass.setMat("M", mtx * glm::lookAt(glm::vec3(lightPos.x, lightPos.y, lightPos.z), glm::vec3(0.0, 0.0, 0.0), glm::vec3(0.0, 1.0, 0.0)) *
getModelToWorld());
glBindVertexArray(vao);
// Draw
glDrawArrays(GL_TRIANGLES, 0, ModelVertices.size());
glBindFramebuffer(GL_FRAMEBUFFER, 0);
/*---------------------------END------------------------------------*/
/*--This is what I pass to the shader that shows the depth texture--*/
DepthPass.setFloat("near", 5.0f);
DepthPass.setFloat("far", 40.0);
DepthPass.setInt("IsViewport", 1);
glActiveTexture(GL_TEXTURE0);
//GetDepthTexture() returns a handle of the texture created before
glBindTexture(GL_TEXTURE_2D, sceneManager.GetDepthTexture());
std::string textureName = "depthTexture";
DepthPass.setInt(textureName.c_str(), sceneManager.GetDepthTexture());
/*---------------------------END------------------------------------*/
I need some help with rendering inverted scene to framebuffer. I want to make a mirror effect.
What i have in result:
Initializing frame buffer:
GLuint FramebufferName = 0;
glGenFramebuffers(1, &FramebufferName);
glBindFramebuffer(GL_FRAMEBUFFER, FramebufferName);
GLuint renderedTexture;
glGenTextures(1, &renderedTexture);
glBindTexture(GL_TEXTURE_2D, renderedTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, SCREEN_WIDTH, SCREEN_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, 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);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, renderedTexture, 0);
glDrawBuffer(GL_COLOR_ATTACHMENT0);
glReadBuffer(GL_NONE);
Draw scene to frame buffer:
mView = camera.getViewMatrix();
mProjection = perspective(45.0f, 4.0f / 3.0f, 0.1f, 300.0f) * scale(mat4(1.0f), vec3(1.0f, -1.0f, 1.0f));
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, FramebufferName);
glViewport(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glCullFace(GL_FRONT);
glEnable(GL_CULL_FACE);
mWorld = rotate(mWorld, -15.0f, vec3(1, 0, 0));
mWorld = rotate(mWorld, -30.0f, vec3(0, 1, 0));
cubemap.Draw(mView, mProjection, mWorld);
glDisable(GL_CULL_FACE);
glEnable(GL_DEPTH_TEST);
glUseProgram(program);
mWorld = translate(mat4(1.0f), vec3(0, -10, 0));
glUniformMatrix4fv(mvp_object, 1, GL_FALSE, value_ptr(mProjection * mView * mWorld * scale(mat4(1.0f), vec3(10.0f))));
cannon.Draw(program);
mWorld = mat4(1.0f);
mWorld = translate(mat4(1.0f), vec3(50, -10, 0));
mWorld = rotate(mWorld, 90.0f, vec3(0, 1, 0));
glUniformMatrix4fv(mvp_object, 1, GL_FALSE, value_ptr(mProjection * mView * mWorld * scale(mat4(1.0f), vec3(10.0f))));
cannon.Draw(program);
mWorld = mat4(1.0f);
mWorld = translate(mat4(1.0f), vec3(0, -10, 50));
mWorld = rotate(mWorld, 140.0f, vec3(0, 1, 0));
glUniformMatrix4fv(mvp_object, 1, GL_FALSE, value_ptr(mProjection * mView * mWorld * scale(mat4(1.0f), vec3(10.0f))));
cannon.Draw(program);
glDisable(GL_DEPTH_TEST);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
I saw some tutorials where used glScalef(1.0, -1.0, 1.0) to invert scene.
glScalef was used in old versions of opengl. How can i invert scene in new versions of opengl?
I've multiplied projection matrix on scale(mat4(1.0f), vec3(1.0, -1.0, 1.0)) for this effect. Is it right?
Here is the vertex shader written in GLSL.
void main(void)
{
// Clean up inaccuracies
vec2 Pos = sign(gl_Vertex.xy);
gl_Position = vec4(Pos.xy, 0.0, 1.0);
// Image-space
gl_TexCoord[0].xy = vec2(-Pos.x, Pos.y) * 0.5 + 0.5; // x texture coord is inverted
}
Pos refers to screen aligned quad for framebuffer output.
Fragment shader
uniform sampler2D framebufferSampler;
void main(void)
{
gl_FragColor = texture2D(framebufferSampler, gl_TexCoord[0].xy);
}
Screen aligned quad can be drawn
glBegin(GL_QUADS)
{
glVertex2f(-1.0f, -1.0f);
glVertex2f(1.0f, -1.0f);
glVertex2f(1.0f, 1.0f);
glVertex2f(-1.0f, 1.0f);
}
glEnd();
or using vertex arrays.
GLfloat vertices[] = {
-1.0f, -1.0f,
1.0f, -1.0f,
1.0f, 1.0f,
-1.0f, 1.0f
};
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(2, GL_FLOAT, 0, (void*)vertices);
glDrawArrays(GL_QUADS, 0, 4);
glDisableClientState(GL_VERTEX_ARRAY);
texture that is used to be wraped to the quad, is the framebuffer info with previous rendered content (multipass shader technique).
You can also do so with others 2D texture coords or images instead of framebuffer and screen align quads.
Original image.
Inverted image.
More info can be found in Learn OpenGL.
I have been trying to get shadow mapping to work for quite some time now and I am still no closer than I was a month ago. I am beginning to think it may be an issue with my GL drivers because I haven't been able to see any side effects such as "light acne."
I was told to start using a sampler2DShadow instead of a sampler2D and this is what I did. However, whenever I sample the map using texture(...) the result is always 0. Why would this be happening?
I have tried entering manual depthCoord values and I still get 0. Could this be a result of the shadowMap itself (i.e the way it has been setup?) or is it a driver issue?
Framebuffer Setup
FramebufferName = 0;
glGenFramebuffers(1, &FramebufferName);
glBindFramebuffer(GL_FRAMEBUFFER, FramebufferName);
glGenTextures(1, &depthTexture);
glBindTexture(GL_TEXTURE_2D, depthTexture);
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_EDGE );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
glTexImage2D(GL_TEXTURE_2D, 0,GL_DEPTH_COMPONENT, 512, 512, 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0);
glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depthTexture, 0);
glDrawBuffer(GL_NONE);
glReadBuffer(GL_NONE);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
Fragment Shader
uniform sampler2DShadow shadowMap;
in vec4 depthCoord;
void main(){
//The final color after lighting is stored as 'FinalColor'
float visibility = 1.0;
if (texture(shadowMap, depthCoord.xyz) == 0.0){
visibility = 0.1;
}
color = vec4(finalColor.rgb * visibility, 1.0);
}
Rendering Code
glm::vec3 lightInvDir = glm::vec3(0,-10,-10);
glm::mat4 depthProjectionMatrix = glm::ortho<float>(-10,10,-10,10,-10,20);
glm::mat4 depthViewMatrix = glm::lookAt(lightInvDir, glm::vec3(0,0,0), glm::vec3(0,1,0));
glm::mat4 depthModelMatrix = glm::mat4(1.0);
glm::mat4 depthMVP = depthProjectionMatrix * depthViewMatrix * depthModelMatrix;
glm::mat4 biasMatrix(
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
);
glm::mat4 depthBiasMVP = biasMatrix*depthMVP;
/* Shadow */
subShader->useShader();
glViewport(0,0,512,512);
glUniformMatrix4fv(glGetUniformLocation(subShader->getShader(),"depthMVP"), 1, GL_FALSE, &depthMVP[0][0]);
glBindFramebuffer(GL_FRAMEBUFFER, Shadows::framebuffer());
renderBuffer(objBuffer);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
/* Clear */
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
/* Shader */
objShader->useShader();
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, Shadows::shadowmap());
glUniform1f(glGetUniformLocation(objShader->getShader(),"shadowMap"),0);
/* Render Scene */
glUniformMatrix4fv(glGetUniformLocation(objShader->getShader(),"depthBiasMVP"), 1, GL_FALSE, &depthBiasMVP[0][0]);
glViewport(0,0,640,480);
glUniform1f(glGetUniformLocation(objShader->getShader(),"renderingPass"),1.0);
renderBuffer(objBuffer);
The majority of this code has been learned from sites such as (http://www.opengl-tutorial.org/) with modifications based on (http://www.fabiensanglard.net/shadowmapping/index.php) and the red book.
I'm drawing a lot of points to the screen, and I am trying to get them to render to a texture for post processing before then rendering the texture back to the screen. Currently I'm trying to just pass through and get the texture rendering but it appears to be rendering nothing.
My fragment shader works (without render to texture - used bellow in mEllipseTextureProgram) and the only change I have made is to include
out vec3 color;
to render to the texture itself (and obviously change to color= rather than gl_FragColor=). The second program referenced below (mScreenProgram) is as follows:
Vertex Shader:
#version 330 compatibility
in vec2 vUV;
out vec2 UV;
void main()
{
gl_Position = gl_Vertex;
UV = vUV;
}
Fragment Shader:
#version 330 core
in vec2 UV;
out vec3 color;
uniform sampler2D renderedTexture;
void main(){
color = texture( renderedTexture, UV ).xyz;
}
I set up my render to texture stuff like this:
glGenFramebuffers(1, &mGaussianFrameBuffer);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mGaussianFrameBuffer);
glGenTextures(1, &mGaussianRenderTexture);
glBindTexture(GL_TEXTURE_2D, mGaussianRenderTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
1024,
768,
0, GL_RGBA, GL_UNSIGNED_BYTE,
NULL);
glBindTexture(GL_TEXTURE_2D, 0);
glFramebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mGaussianRenderTexture, 0);
glGenTextures(1, &mGaussianDepthBuffer);
glBindTexture(GL_TEXTURE_2D, mGaussianDepthBuffer);
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_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT,
1024,
768,
0, GL_DEPTH_COMPONENT, GL_FLOAT,
NULL);
glBindTexture(GL_TEXTURE_2D, 0);
glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, mGaussianDepthBuffer, 0);
which returns a successful GL_FRAMEBUFFER_COMPLETE.
Here are the three concerning rendering functions:
void Draw()
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
//gluPerspective(45, 1024.0/768.0, 3.0, 20000);
perspectiveGL(45, 1024.0/768.0, 1.0, 20000);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glPushMatrix();
gluLookAt(cameraData[0],cameraData[1], cameraData[2],
cameraData[3],cameraData[4], cameraData[5],
0,1,0);
glEnable(GL_DEPTH_TEST);
glClearColor( 0.2f, 0.2f, 0.9f, 0.0f );
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// OTHER STUFF POTENTIALLY DRAW HERE IN DIFFERENT WAYS
glUseProgram(mEllipseTextureProgram);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mGaussianFrameBuffer);
GLuint attachments[1] = {GL_COLOR_ATTACHMENT0};
glDrawBuffers(1, attachments);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
DrawEllipseToTexture();
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glUseProgram(mScreenProgram);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
DrawTextureToScreen();
}
void DrawEllipseToTexture()
{
glEnableClientState(GL_VERTEX_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, mVBO);
glVertexPointer(3, GL_FLOAT, 0, 0);
glEnable(GL_PROGRAM_POINT_SIZE);
glEnable(GL_POINT_SPRITE);
glEnable( GL_TEXTURE_2D );
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, mBMP);
glProgramUniform1i(mEllipseTextureProgram, mTextureLocation, 0);
glBindBuffer(GL_ARRAY_BUFFER, mUV);
glEnableVertexAttribArray(mTexCoordLocation);
glVertexAttribPointer(mTexCoordLocation, 2, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, mSpacial);
glEnableVertexAttribArray(mSpacialLocation);
glVertexAttribPointer(mSpacialLocation, 1, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, mNormals);
glEnableVertexAttribArray(mNormalLocation);
glVertexAttribPointer(mNormalLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, mVerticalSpat);
glEnableVertexAttribArray(mMajorLocation);
glVertexAttribPointer(mMajorLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, mHorizontalSpat);
glEnableVertexAttribArray(mMinorLocation);
glVertexAttribPointer(mMinorLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable( GL_BLEND );
glDrawArrays(GL_POINTS, 0, mNumberPoints);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glDisable( GL_TEXTURE_2D );
glDisableVertexAttribArray(mSpacialLocation);
glDisable(GL_POINT_SPRITE);
glDisable( GL_POINT_SMOOTH );
glDisable(GL_PROGRAM_POINT_SIZE);
glDisableClientState(GL_VERTEX_ARRAY);
}
void DrawTextureToScreen()
{
glEnableClientState(GL_VERTEX_ARRAY);
glEnable( GL_TEXTURE_2D );
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, mGaussianRenderTexture);
glProgramUniform1i(mScreenProgram, mGaussianTextureLocation, 0);
GLfloat vertices[] = { -1, -1, 2,
1, -1, 2,
1, 1, 2,
-1, 1, 2 };
GLfloat uv[] = { 0, 0,
1, 0,
1, 1,
0, 1,};
glVertexPointer(3, GL_FLOAT, 0, vertices);
glEnableVertexAttribArray(mGaussianUV);
glVertexAttribPointer(mGaussianUV, 2, GL_FLOAT, GL_FALSE, 0, uv);
glDrawArrays(GL_TRIANGLES, 0, 4);
glDisable ( GL_TEXTURE_2D );
glDisableClientState(GL_VERTEX_ARRAY);
}
I still don't know what was wrong with my solution above (to which I tried a lot of variations) - but following this tutorial got it working: Tutorial
I usually use `out vec4 color', I am not sure whether it will work after you setting your texture type is GL_RGBA and then return vec3 for each fragment.
And I didnt see you set glViewport() in your code which means there is no specify affine transformation to mapping the screen position (x,y) from NDC to Screen space. If you don't have a viewport during fbo render, that definitely gives you nothing.
I am same as you struggling in the similar situation. Read the functions you don't know from GL documentation instead of blog is a much better way to understand things correctly...
: )
I want to do volume rendering using programmable pipeline (using glsl) and no fixed pipelines. I implement it with 2 passes with 2 shader programs, exitPointProg and rayCastProg. the first pass is to get the exit points (i.e. the back face) of a cube bounding box which will be used as a texture in the next pass which doing the raycasting. the idea to do the raycasting volume rendering comes from here. I think I have done the most of the things right cause I have implemented this with fixed pipeline combined with the programmable pipeline. the things that confused me is that I achieved the result with the very first frame, and with a flash the display on the screen turn totally white (I set the glClearColor(1.0f, 1.0f, 1.0f, 1.0f). I think there maybe some wrong with the switch of the shader programs or the FBO. here is what I do in the render() function.
1st pass, render to a fbo with exitPoints texture bound to it to get the exit points of cube bounding box, using shader program exitPointProg.
2ed pass, mapped the exitPoints texture (bound to GL_TEXTURE1) into the shader program rayCastProg as a uniform sampler2D variable which will used in the shader.
here is the setupFBO and render and two subroutines:
the setupFBO() function:
void SimpleRayCasting::setupFBO()
{
GLuint textureHandles[1];
glGenTextures(1, textureHandles);
entryPoints = textureHandles[0];
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, exitPoints);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
glTexImage2D(GL_TEXTURE_2D, 0,GL_RGBA16F, width, height, 0, GL_RGBA, GL_FLOAT, NULL);
GLuint depthRenderBuffer;
glGenRenderbuffers(1, &depthRenderBuffer);
glBindRenderbuffer(GL_RENDERBUFFER, depthRenderBuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height);
glGenFramebuffers(1, &frameBuffer);
glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
exitPoints, 0/* level */);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER,
depthRenderBuffer);
checkFramebufferState(__FILE__, __LINE__);
GLenum drawbufs[] = {GL_COLOR_ATTACHMENT0};
glDrawBuffers(1, drawbufs);
glBindFramebuffer(GL_FRAMEBUFFER,0);
}
the render() function:
void SimpleRayCasting::render()
{
getExitPoints();
GLUtils::checkForOpenGLError(__FILE__,__LINE__);
rayCasting();
GLUtils::checkForOpenGLError(__FILE__,__LINE__);
}
the getExitPoints() function:
void SimpleRayCasting::getExitPoints()
{
// render to the texture
glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
glEnable(GL_DEPTH_TEST);
glViewport(0, 0, width, height);
// checkFramebufferState(__FILE__, __LINE__);
glClearColor(0.2f, 0.2f, 0.2f, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
exitPointsProg.use();
// note that the model will recalculated.
model = mat4(1.0f);
model *= glm::rotate(angle , vec3(0.0f,1.0f,0.0f));
model *= glm::rotate(90.0f, vec3(1.0f, 0.0f, 0.0f));
model *= glm::translate(vec3(-0.5f, -0.5f, -0.5f));
view = glm::lookAt(vec3(0.0f,0.0f,2.0f), vec3(0.0f,0.0f,0.0f), vec3(0.0f,1.0f,0.0f));
projection = mat4(1.0f);
projection = glm::perspective(60.0f, (float)width/(float)height,0.01f, 400.0f);
setMatrices(exitPointsProg);
glEnable(GL_CULL_FACE);
glCullFace(GL_FRONT);
drawBoundBox();
glDisable(GL_CULL_FACE);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
the rayCasting function:
void SimpleRayCasting::rayCasting()
{
// Directly render to the screen
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glEnable(GL_DEPTH_TEST);
glViewport(0, 0, width, height);
glClearColor(1.0f, 1.0f, 1.0f, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
rayCastProg.use();
model = mat4(1.0f);
model *= glm::rotate(angle, vec3(0.0f,1.0f,0.0f));
model *= glm::rotate(90.0f, vec3(1.0f, 0.0f, 0.0f));
model *= glm::translate(vec3(-0.5f, -0.5f, -0.5f));
view = glm::lookAt(vec3(0.0f,0.0f,2.0f), vec3(0.0f,0.0f,0.0f), vec3(0.0f,1.0f,0.0f));
projection = mat4(1.0f);
projection = glm::perspective(60.0f, (float)width/(float)height,0.01f, 400.0f);
setMatrices(rayCastProg);
rayCastProg.setUniform("StepSize", stepSize);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, exitPoints);
rayCastProg.setUniform("ExitPoints", 1);
glActiveTexture(GL_TEXTURE4);
glBindTexture(GL_TEXTURE_3D, volume_to);
rayCastProg.setUniform("VolumeTex", 4);
glActiveTexture(GL_TEXTURE5);
glBindTexture(GL_TEXTURE_1D, transferFunc_to);
rayCastProg.setUniform("TransferFunc", 5);
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
drawBoundBox();
glDisable(GL_CULL_FACE);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
I am using a class inherited from QGLWidget in Qt. As I have mentioned early, I got the right result with just the 1st frame and quickly it flash away and turn totally white. I don't know what's wrong with this, is there something wrong with the switch of the shader program or the FBO thing? I have been working on this a long time and can't figure it out, any help will be appreciated!
edit to ask
is there any demo or tutorial demonstrate how to use multiple glsl shader programs with FBO?