I want to blur the edges of a image the approach i took was to render the image to a frame buffer and than apply gaussian blur to it.
than i tried to overlay the actual image on top of the blurred image but this approach does not seem to work.
As this does not give a blur effect around the edges but the blurred image moves away.
Please suggest me the ways i can achieve this or if you can show me how this can be done in the fragment shader.
The code
// Generate frame buffers
glGenFramebuffers(2, pingpongFBO);
glGenTextures(2, pingpongBuffer);
for (unsigned int i = 0; i < 2; i++)
{
glBindFramebuffer(GL_FRAMEBUFFER, pingpongFBO[i]);
glBindTexture(GL_TEXTURE_2D, pingpongBuffer[i]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, SCR_WIDTH, SCR_HEIGHT, 0, GL_RGBA,
GL_FLOAT, NULL);
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_S, GL_CLAMP_TO_EDGE);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,pingpongBuffer[i],0);
}
// blur the image
bool horizontal = true, first_iteration = true;
float blurValue = 6;
GLint drawFrameBuffer;
int amount = blurValue;
shaderBlur.use();
shaderBlur.setInt("image", 0);
glDisable(GL_DEPTH_TEST);
glActiveTexture(GL_TEXTURE0);
glBindFramebuffer(GL_FRAMEBUFFER, pingpongFBO[horizontal]);
glClearColor(1.0, 1.0, 1.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT);
glBindFramebuffer(GL_FRAMEBUFFER, pingpongFBO[!horizontal]);
glClearColor(1.0, 1.0, 1.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT);
for (unsigned int i = 0; i < amount; i++)
{
shaderBlur.setInt("horizontal", horizontal);
glBindFramebuffer(GL_FRAMEBUFFER, pingpongFBO[horizontal]);
if (first_iteration)
{
glBindTexture(GL_TEXTURE_2D, image.textureID);
glGenerateMipmap(GL_TEXTURE_2D);
}
else
{
glBindTexture(GL_TEXTURE_2D, pingpongBuffer[!horizontal]);
glGenerateMipmap(GL_TEXTURE_2D);
}
renderQuadInner();
horizontal = !horizontal;
if (first_iteration)
first_iteration = false;
}
// Map the image
shader.use();
shader.setInt("u_tex", 0);
glBindFramebuffer(GL_FRAMEBUFFER, 0); // the default frame buffer
glClearColor(0.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT);
glBindTexture(GL_TEXTURE_2D, pingpongBuffer[horizontal]); // the blurred image
renderQuad();
glBindTexture(GL_TEXTURE_2D, image.textureID); // the actual image
renderQuad();
The blur shader
#version 330 core
out vec4 FragColor;
in vec2 TexCoords;
uniform sampler2D image;
uniform bool horizontal;
float offset[3] = float[]( 0.0, 1.3846153846, 3.2307692308 );
uniform float weight[3] = float[] (0.2270270270, 0.316216162, 0.0702702703);
void main()
{
vec2 tex_offset = 3.0 / textureSize(image, 0); // gets size of single texel
vec4 result = texture(image, TexCoords).rgba * weight[0];
vec2 uv = TexCoords.xy;
if(horizontal)
{
for(int i = 1; i < 3; ++i)
{
result += texture(image, TexCoords + vec2(tex_offset.x * i, 0.0)).rgba * weight[i];
result += texture(image, TexCoords - vec2(tex_offset.x * i, 0.0)).rgba * weight[i];
}
}
else
{
for(int i = 1; i < 3; ++i)
{
result += texture(image, TexCoords + vec2(0.0, tex_offset.y * i)).rgba * weight[i];
result += texture(image, TexCoords - vec2(0.0, tex_offset.y * i)).rgba * weight[i];
}
}
FragColor = vec4(result);
}
Related
I'm using OpenGL shader and trying to print the color values.
So, I used glReadPixels function. It is working with GL_UNSIGNED_BYTE but not with GL_FLOAT.
Is there anything else should I do?
This is my code.
void settingFrameBuffers()
{
glGenFramebuffers(NUM_FBO, fbo);
glGenTextures(NUM_FBO, tex);
for (int i = 0; i < NUM_FBO; i++)
{
glBindFramebuffer(GL_FRAMEBUFFER, fbo[i]);
glBindTexture(GL_TEXTURE_2D, tex[i]);
if (i == 0) glActiveTexture(GL_TEXTURE0);
else if (i == 1) glActiveTexture(GL_TEXTURE1);
else if (i == 2) glActiveTexture(GL_TEXTURE2);
else if (i == 3) glActiveTexture(GL_TEXTURE3);
else if (i == 4) glActiveTexture(GL_TEXTURE4);
else if (i == 5) glActiveTexture(GL_TEXTURE5);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, width, height, 0, GL_RGBA, GL_FLOAT, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex[i], 0);
GLuint dbo;
glGenRenderbuffers(1, &dbo);
glBindRenderbuffer(GL_RENDERBUFFER, dbo);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, dbo);
glDrawBuffer(GL_COLOR_ATTACHMENT0);
}
}
void printWholeMassToConsole()
{
GLfloat* data =new GLfloat[4 * width*height];
glBindFramebuffer(GL_FRAMEBUFFER, fbo[otFb]);
//glReadPixels(0, 0, width, height, GL_RGBA, GL_FLOAT, data);
glReadnPixels(0, 0, width, height, GL_RGBA, GL_FLOAT, sizeof(data), data);
float sumR = 0;
float sumG = 0;
float sumB = 0;
for (int i = 0; i < 4 * width*height; i += 4)
{
if (i > 0) break;
sumR += data[i];
sumG += data[i + 1];
sumB += data[i + 2];
}
float sum = sumR + sumG + sumB;
float possibleDiff = 3.0*width*height*0.5;
//if (abs(wholeMass - sum) <= possibleDiff) cout << "O - ";
//else cout << "X - ";
printf("mass : %d\t %d\t %d\t %d\n", sum, sumR, sumG, sumB);
free(data);
}
This is the first shader.
// vertex shader
#version 450
in vec4 position;
in vec2 texCoord;
out vec2 fragTexCoord;
void main()
{
gl_Position = position;
fragTexCoord = texCoord;
}
// fragment shader
#version 450
in vec2 fragTexCoord;
out vec4 FragColor;
void main()
{
FragColor = vec4(0.5, 0.0, 0.0, 1.0);
}
This is the second shader.
// vertex shader
#version 450
in vec4 position;
in vec2 texCoord;
out vec2 fragTexCoord;
void main()
{
gl_Position = position;
fragTexCoord = texCoord;
}
// fragment shader
#version 450
in vec2 fragTexCoord;
uniform sampler2D tex;
out vec4 FragColor;
void main()
{
FragColor = texture(tex, fragTexCoord);
}
It draws something on otFb framebuffer through the first shader and then otFb texture is mapped on the main framebuffer.
When I use glReadPixels with GL_FLOAT, the program is terminated by itself, when glReadnPixels with GL_FLOAT, the program print garbage values.
I used so many times to search, but I could not find the solutions.
Or is there any different way that I can try?
Try changing the first parameter of the framebuffer binding function call(the second line of code in your printWholeMassToConsole function) i.e.:
glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo[otFb]);
Hope it works.
I create a framebuffer object to render scene as depth values to render shadow maps , after the scene initialized and all shaders compiled I add the directional light and create the FBO using this code:
glGenFramebuffers(1, &depthMapFBO);
glBindFramebuffer(GL_FRAMEBUFFER, depthMapFBO);
glGenTextures(1, &depthMap);
glBindTexture(GL_TEXTURE_2D, depthMap);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16, SHADOW_WIDTH, SHADOW_HEIGHT, 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0);
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);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthMap, 0);
glDrawBuffers(1, GL_NONE);
glReadBuffer(GL_NONE);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
then in the render loop I render the scene on the generated framebuffer with the depth shader then render the scene again regularly on the screen after unbinding the FBO, this is the code :
glBindFramebuffer(GL_FRAMEBUFFER, depthMapFBO);
glViewport(0, 0, SHADOW_WIDTH, SHADOW_HEIGHT);
glEnable(GL_CULL_FACE);
glCullFace(GL_FRONT);
glClear(GL_DEPTH_BUFFER_BIT);
double delta = GetCurrentTime() - firstFrame;
glm::mat4 lightSpaceProjection = glm::ortho(-10.0f, 10.0f, -10.0f, 10.0f, -10.0f, 10.0f);
glm::mat4 lightSpaceView = glm::lookAt(-sun->direction, glm::vec3(0, 0, 0), glm::vec3(0, 1, 0));
lightSpaceMatrix = lightSpaceProjection * lightSpaceView;
directDepthShader.use();
GLuint lsm = glGetUniformLocation(directDepthShader.getProgramID(), "lightSpaceMatrix");
glUniformMatrix4fv(lsm, 1, GL_FALSE, glm::value_ptr(lightSpaceMatrix));
for (mesh_it it = phongMeshes.begin(); it != phongMeshes.end(); it++) {
it->get()->renderDepth(directDepthShader, delta);
}
glCullFace(GL_BACK);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
the first function called before the rendering loop and the FBO generated and has an ID but the problem is the rendering function ignored it although I bind it with its ID which is not minus or even not zero to the extent that if I remove the code which create and adjust the framebuffer nothing changes in the rendering result, I am in that problem for a week !!
Edit:
Vertex shader for depth:
#version 300 es
precision mediump float;
layout (location = 0) in vec3 position;
layout (location = 4) in ivec4 BoneIDs;
layout (location = 5) in vec4 Weights;
const int MAX_BONES = 100;
uniform mat4 model;
uniform bool skinned;
uniform mat4 gBones[MAX_BONES];
uniform mat4 lightSpaceMatrix;
void main(){
vec4 nPos;
if(skinned){
mat4 BoneTransform = gBones[BoneIDs[0]] * Weights[0];
BoneTransform += gBones[BoneIDs[1]] * Weights[1];
BoneTransform += gBones[BoneIDs[2]] * Weights[2];
BoneTransform += gBones[BoneIDs[3]] * Weights[3];
nPos=BoneTransform * vec4(position, 1.0);
}
else
nPos = vec4(position, 1.0);
gl_Position = lightSpaceMatrix * model * nPos;
}
the renderDepth() for each mesh using the the depth shader program:
void Mesh::renderDepth(Shader& shader, double& delta) {
if (isSkinned) {
glUniform1i(glGetUniformLocation(shader.getProgramID(), "skinned"), 1);
vector<Matrix4f> Transforms;
BoneTransform(delta, Transforms);
for (uint j = 0; j < Transforms.size(); j++) {
Transforms[j] = Transforms[j].Transpose();
GLuint bonesLoc = glGetUniformLocation(shader.getProgramID(), (const GLchar*) ("gBones[" + ToString(j) + "]").c_str());
glUniformMatrix4fv(bonesLoc, 1, GL_FALSE, (const GLfloat*) Transforms[j]);
}
}
for (uint i = 0; i < m_Entries.size(); i++) {
glUniformMatrix4fv(glGetUniformLocation(shader.getProgramID(), "model"), 1, GL_FALSE, glm::value_ptr(m_Entries[i].matrix));
glBindVertexArray(m_Entries[i].m_VAO);
glDrawElements(GL_TRIANGLES, m_Entries[i].NumIndices, GL_UNSIGNED_INT, NULL);
glBindVertexArray(0);
}
}
I can't get shadow mapping to work in my application. I try to render a quad bike and view its shadow on a floor beneath it.
Here's some of my code.
Texture creation:
// Create a depth texture
glGenTextures(1, &depth_texture);
glBindTexture(GL_TEXTURE_2D, depth_texture);
// Allocate storage for the texture data
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32 ,1600, 900, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
// Set the default filtering modes
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// Set up wrapping modes
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glBindTexture(GL_TEXTURE_2D, 0);
// Create FBO to render depth into
glGenFramebuffers(1, &depth_fbo);
glBindFramebuffer(GL_FRAMEBUFFER, depth_fbo);
// Attach the depth texture to it
glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
depth_texture, 0);
// Disable color rendering as there are no color attachments
glDrawBuffer(GL_NONE);
//check fbo status
GLenum result = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if(result != GL_FRAMEBUFFER_COMPLETE)
throw std::runtime_error("shadow mapping framebuffer error");
//bind default framebuffer
glBindFramebuffer(GL_FRAMEBUFFER, 0);
render to depth texture:
progShadow.Use();
glBindFramebuffer(GL_FRAMEBUFFER, depth_fbo);
glClear(GL_DEPTH_BUFFER_BIT);
glm::mat4 shadowProjection = glm::frustum(-1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 100.0f);
glm::mat4 shadowView = glm::lookAt(light.position, glm::vec3(0,0,0), glm::vec3(0,1,0));
glm::mat4 shadowModel(1);
if(g_rotate)
shadowModel = glm::rotate((float)clock() / (float)CLOCKS_PER_SEC, glm::vec3(0,1,0));
glm::mat4 shadowMVP = shadowProjection * shadowView * shadowModel;
progShadow.SetUniform("MVPMatrix", shadowMVP);
quadBike.Draw();
I also use a "test" shader program that renders my depth texture. Here's what it looks like.
So I guess I'm good until now.
Now I render the scene normally.
glBindTexture(GL_TEXTURE_2D, depth_texture);
prog.Use();//main program
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glm::mat4 shadowBias = glm::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);
glm::mat4 ShadowBiasMVP = shadowBias * shadowMVP;
prog.SetUniform("ShadowBiasMVP", ShadowBiasMVP);
//draw quadBike and floor
...
Relevant parts of my vertex shader:
#version 430
...
out vec4 shadowCoord;
void main()
{
gl_Position = ProjectionMatrix * CameraMatrix * ModelMatrix * vec4(vertex, 1.0);
shadowCoord = ShadowBiasMVP * vec4(vertex, 1.0);
...
}
Relevant parts of my fragment shader:
#version 430
...
uniform sampler2D shadowMap;
in vec4 shadowCoord;
void main()
{
...
float visibility = 1.0;
if ( texture(shadowMap, shadowCoord.xy).z < shadowCoord.z)
visibility = 0.0;
...
}
Now the problem is that I get a scene that is fully dark as if it was all covered by shadow. Only when the light is really close to the quad bike, it renders it normally. (the depth texture is visible on the right side because it's rendered with a different program. I use it for testing)
What am I doing wrong?
You should read a grayscale depthtexture at the first component.
texture(shadowMap, shadowCoord.xy).r or
texture(shadowMap, shadowCoord.xy).x
The Shadow Coordinates should be dehomogenized (divided by w) after interpolation.
-> in fragment shader: shadowPos = shadowPos/shadowPos.w;
If no other techniques like polygon offset is used you need to substract a bias from the shadow depth value to prevent self shadowing.
Here is an example function to calculate shadows in fragment shader. Note: It is part of a deferred renderer, that is why matrix multiplication is done in the fragment shader.
float calculateShadow(vec3 position){
vec4 shadowPos = depthBiasMV * vec4(position,1);
shadowPos = shadowPos/shadowPos.w;
float bias = 0.0012;
float visibility = 1.0f;
if ((shadowPos.x < 0 || shadowPos.x > 1 || shadowPos.y < 0 || shadowPos.y > 1 || shadowPos.z < 0 || shadowPos.z > 1)){
visibility = 1.0f;
}else{
float shadowDepth = texture(depthTex, shadowPos.xy).r;
if(shadowDepth<shadowPos.z-bias)
visibility = 0.0f;
}
return visibility;
}
Shader used: http://www.gamerendering.com/2008/12/20/radial-blur-filter/
My issue is this: The whole scene only takes up a quarter of the screen space (which is a rectangle of these coordinates: width/2,0 width,height/2), and it seems to have been literally clipped (not scaled). It also rendered it with Y inverted (but I was able to fix this by removing the - sign from line 9's gl_Position.y).
I used this tutorial to do the post-processing, with the exception of using basic glBegin(GL_QUADS) instead of vertex arrays.
EDIT 2: I have tried using another shader (http://www.geeks3d.com/20110428/shader-library-swirl-post-processing-filter-in-glsl/), and it worked perfectly fine. No clipping.
EDIT: Here is the source of the shaders (I did some minor edits):
Fragment shader:
#version 140
// This texture should hold the image to blur.
// This can perhaps be a previous rendered scene.
uniform sampler2D tex;
// texture coordinates passed from the vertex shader
varying vec2 uv;
// some const, tweak for best look
const float sampleDist = 1.0;
const float sampleStrength = 20.2;
void main(void)
{
// some sample positions
float samples[10] =
float[](-0.08,-0.05,-0.03,-0.02,-0.01,0.01,0.02,0.03,0.05,0.08);
// 0.5,0.5 is the center of the screen
// so substracting uv from it will result in
// a vector pointing to the middle of the screen
vec2 dir = 0.5 - uv;
// calculate the distance to the center of the screen
float dist = sqrt(dir.x*dir.x + dir.y*dir.y);
// normalize the direction (reuse the distance)
//dir = dir/dist;
dir /= dist;
// this is the original colour of this fragment
// using only this would result in a nonblurred version
vec4 color = texture2D(tex,uv);
vec4 sum = color;
// take 10 additional blur samples in the direction towards
// the center of the screen
for (int i = 0; i < 10; i++)
{
sum += texture2D( tex, uv + dir * samples[i] * sampleDist );
}
// we have taken eleven samples
sum *= 1.0/11.0;
// weighten the blur effect with the distance to the
// center of the screen ( further out is blurred more)
float t = dist * sampleStrength;
t = clamp( t ,0.0,1.0); //0 <= t <= 1
//Blend the original color with the averaged pixels
gl_FragColor = mix( color, sum, t );
}
Vertex shader:
#version 140
varying vec2 uv;
// this vertex shader is from AMD RenderMonkey
void main(void)
{
gl_Position = vec4( gl_Vertex.xy, 0.0, 1.0 );
gl_Position = sign( gl_Position );
// Texture coordinate for screen aligned (in correct range):
uv = (vec2( gl_Position.x, gl_Position.y ) + vec2(1.0 )) / vec2( 2.0 );
}
Post-processor:
#include "std/opengl.h"
#include "postprocess.h"
Post::Post(Pos2D res) {
this->res = res;
glActiveTexture(GL_TEXTURE0);
glGenTextures(1, &this->texture);
glBindTexture(GL_TEXTURE_2D, this->texture);
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_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, res.x, res.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glBindTexture(GL_TEXTURE_2D, 0);
glGenRenderbuffers(1, &this->rbo);
glBindRenderbuffer(GL_RENDERBUFFER, this->rbo);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, res.x, res.y);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
glGenFramebuffers(1, &this->fbo);
glBindFramebuffer(GL_FRAMEBUFFER, this->fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, this->texture, 0);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, this->rbo);
GLenum status;
if ((status = glCheckFramebufferStatus(GL_FRAMEBUFFER)) != GL_FRAMEBUFFER_COMPLETE) {
fprintf(stderr, "Framebuffer error! %i", status);
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
Post::~Post() {
glDeleteRenderbuffers(1, &this->rbo);
glDeleteTextures(1, &this->texture);
glDeleteFramebuffers(1, &this->fbo);
}
void Post::update(Pos2D res) {
this->res = res;
glBindTexture(GL_TEXTURE_2D, this->texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, res.x, res.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glBindTexture(GL_TEXTURE_2D, 0);
glBindRenderbuffer(GL_RENDERBUFFER, this->rbo);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, res.x, res.y);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
}
void Post::bind() {
glBindFramebuffer(GL_FRAMEBUFFER, this->fbo);
}
void Post::unbind() {
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
void Post::render(Shader* shader) {
glClear(GL_COLOR_BUFFER_BIT);
glClearColor(0.0, 0.0, 0.0, 1.0);
shader->run();
auto tex = glGetUniformLocation(shader->program_handle, "tex");
glBindTexture(GL_TEXTURE_2D, this->texture);
glUniform1i(tex, 0);
glBegin(GL_QUADS);
glTexCoord2f(0.0, 0.0);
glVertex2f(0, 0);
glTexCoord2f(0.0, 1.0);
glVertex2f(0, this->res.y);
glTexCoord2f(1.0, 1.0);
glVertex2f(this->res.x, this->res.y);
glTexCoord2f(1.0, 0.0);
glVertex2f(this->res.x, 0);
glEnd();
glBindTexture(GL_TEXTURE_2D, 0);
glUseProgram(0);
}
Screenshot of the issue (as you can see, it's cut off):
Screenshot when I disable the shader (as you can see, it can render to the whole window, it is not clipped):
the problem comes from the way you define your vertex coordinates:
glTexCoord2f(0.0, 0.0);
glVertex2f(0, 0);
glTexCoord2f(0.0, 1.0);
glVertex2f(0, this->res.y);
glTexCoord2f(1.0, 1.0);
glVertex2f(this->res.x, this->res.y);
glTexCoord2f(1.0, 0.0);
glVertex2f(this->res.x, 0);
instead of using the window resolution as vertex coordinates, try drawing a quad with the following vertices: ( -1, -1 ), ( -1, 1 ), ( 1, 1 ) and ( 1, -1 ) - that would result in a full-screen quad in opengl's native coordinate system. in your vertex shader, it looks to me like your're trying to use the sign function to transform the vertex coords into this coordinate system:
gl_Position = vec4( gl_Vertex.xy, 0.0, 1.0 );
gl_Position = sign( gl_Position );
but of course then you'll get a quad with the corner points ( 0, 0 ), ( 0, 1 ), ( 1, 1 ) and ( 1, 0 ) instead, which explains why it only fills part of the screen.
And as a result, the texture coordinates that you calculate in your shader with this line:
uv = (vec2( gl_Position.x, gl_Position.y ) + vec2(1.0 )) / vec2( 2.0 );
are also wrong, resulting in the 'clipped' look you're experiencing - your texcoords range from 0.5 to 1, instead of 0 to 1. By the way, you explicitly define texcoords with glTexCoord2f anyway, and those are correct - so there's no need to calculate them again in the shader, just use the built-in gl_MultiTexcoord.
I am seeing a strange issue with a multi pass, multi RT ping-pong render
I am using 3 shaders and an FBO, I get no errors at any stage. I am using opengl 4, so I am not using glBegin/glEnd, I use my own matrices for transformation and i am using vertex buffers for rendering
The general idea of this test is to render 3 different colours to three separate fbo attachments (I realise that it is not efficient rendering the vbo twice in the first pass but this is just to help me understand a problem in some other source) I then bind a separate set of textures to the fbo and use the first set as the samplers. The final pass is to blend the results into the back buffer
What is odd is that the output is both quads appear red, when the first should be red and the second green (as these values come from the second shader).
If i change the function SamplePix in the second shader to always take from the second sampler both appear green, and if lookups up from the third then all appears yellow, but it seems to only read from one.
For now I can't seem to explain why I can read from each sampler ok but the loop doesn't seem to lookup correctly (in shader 2)
Also if I switch to rendering the texture sampled in shader 2 i see a black quad in the second pass (image 2)
Hopefully someone can throw some light on the problem. (I have also tried adding a sync fence object after the first pass but this didn't make a difference)
Texture Sample:
// initial setup of shaders and vertex buffers ommitted for now (in separate source files)
// fbo setup like so
const int DepthLayers = 3;
bool InitFBO()
{
// width and height 768pixels
for (int j=0; j<DepthLayers; j++)
{
const int idx = j + (DepthLayers*i);
glGenTextures(1, &g_FBOManager.m_fboTex[ idx ]);
glBindTexture(GL_TEXTURE_2D, g_FBOManager.m_fboTex[ idx ]);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
//no mipmaps
glTexParameterf(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);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, g_XMLSettings->WWidth(), g_XMLSettings->WHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
//depth
glGenTextures(1, &g_FBOManager.m_fboDepthTex[ idx ]);
glBindTexture(GL_TEXTURE_2D, g_FBOManager.m_fboDepthTex[ idx ]);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
//no mipmaps
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
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_DEPTH_TEXTURE_MODE, GL_INTENSITY);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE/* GL_COMPARE_R_TO_TEXTURE*/);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
glTexImage2D( GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32, g_XMLSettings->WWidth(), g_XMLSettings->WHeight(), 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0);
glBindTexture(GL_TEXTURE_2D, g_FBOManager.m_fboDepthTex[idx]);
pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,GL_TEXTURE_2D, g_FBOManager.m_fboDepthTex[idx], 0);
glBindTexture(GL_TEXTURE_2D, g_FBOManager.m_fboTex[idx]);
// attach a texture to FBO color attachment point
pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, g_FBOManager.m_fboTex[idx], 0);
// check FBO status
pglBindFramebufferEXT( GL_FRAMEBUFFER_EXT, g_FBOManager.FboId(i) );
if(!CheckFramebufferStatus())
{
return false;
}
}
BindFrameBuffer(-1); // unbind fbo
if (GLGETERROR("1", fileBuf, lineBuf)) ; // check for glErrors
return true; // all ok
}
// code to init second set of textures before the render loop
const int w = g_XMLSettings->WWidth(); //res: 768 square
const int h = g_XMLSettings->WHeight();
glGenTextures(bufCount, &ttex[0]);
for (int i=0; i<bufCount; ++i)
{
glBindTexture(GL_TEXTURE_2D, ttex[i]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
}
const int bufCount = 3;
void EnableTexture1()
{
glActiveTextureARB(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, g_BackTexture);
glUniform1iARB(g_pPassAShader->m_clr_idx, 0);
}
void RenderLoop()
{
GLenum buffers[] = { GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_COLOR_ATTACHMENT2_EXT };
glColor4f(0.0f, 0.0f, 0.0f, 0.0f);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
glUseProgramObjectARB(g_pPassAShader->m_glContext);
EnableTexture1();
//... code omitted to set transform matrix and supply to shader
if (!BindFrameBuffer(0))
assert(0);
const GLuint DTex = g_FBOManager.GetDepthTexture(0);
glBindTexture(GL_TEXTURE_2D, DTex);
pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,GL_TEXTURE_2D, DTex, 0);
for (UINT i=0; i<bufCount; ++i)
{
glBindTexture(GL_TEXTURE_2D, g_FBOManager.GetTexture(i));
pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + i, GL_TEXTURE_2D, g_FBOManager.GetTexture(i), 0);
if (!CheckFramebufferStatus())
assert(0);
}
glDrawBuffers(bufCount,buffers);
// this is very important! if we don't clear it won't get written to
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glDisable(GL_BLEND);
EnableTexture1();
RenderVertexCache(0);
//... code omitted to set transform matrix and supply to shader
// render the second quad to other FBO tex
RenderVertexCache(0);
DisableShader(0);
BindFrameBuffer(-1); // unbinds fbo
//pass 2
if (!BindFrameBuffer(0))
assert(0);
// bind other set of textures to the fbo
for (UINT i=0; i<bufCount; ++i)
{
glBindTexture(GL_TEXTURE_2D,ttex[i]);
pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + i, GL_TEXTURE_2D, ttex[i], 0);
if (!CheckFramebufferStatus())
assert(0);
}
glDrawBuffers(bufCount,buffers);
// this is very important! if we don't clear it won't get written to
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
// bind our set from prev pass to the samplers as input
glUseProgramObjectARB(g_pPassBShader->m_glContext);
for (UINT i=0; i<bufCount; ++i)
{
glActiveTextureARB(GL_TEXTURE0+i);
glBindTexture(GL_TEXTURE_2D,g_FBOManager.GetTexture(i));
glUniform1iARB(g_pPassBShader->m_intex_idx[i], i);
}
VertexBufferManager2::RenderUsingOrthoEx(g_pPassBShader); // renders a full screen quad
DisableShader(0);
BindFrameBuffer(-1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// pass 3
glUseProgramObjectARB(g_pPassCShader->m_glContext);
for (UINT i=0; i<bufCount; ++i)
{
glActiveTextureARB(GL_TEXTURE0+i);
glBindTexture(GL_TEXTURE_2D, ttex[i]);
glUniform1iARB(g_pPassCShader->m_intex_idx[i], i);
}
VertexBufferManager2::RenderUsingOrthoEx(g_pPassCShader);
if (GLGETERROR("at1", fileBuf, lineBuf)) ; // reports any glErrors
}
// the three shaders (fragment shaders only)
// vertex shaders transfer uv's and transform vertices (version set to 410 in all)
// shader for pass1
//--------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------
#version 410
uniform sampler2D g_ClrMap;
in vec2 g_InterpUV; // supplied by vshader
out vec4 g_FBOLayers[ 3 ];
void main(void)
{
vec4 tex = texture(g_ClrMap, g_InterpUV); // if we set fbo from texture only first texture renders
g_FBOLayers[0] = vec4(1,0,0,.5);
g_FBOLayers[1] = vec4(0,1,0,1);
g_FBOLayers[2] = vec4(1,1,0,1);
}
// shader pass 2
//--------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------
#version 410
uniform sampler2D g_inLayers0;
uniform sampler2D g_inLayers1;
uniform sampler2D g_inLayers2;
in vec2 g_InterpUV ;
out vec4 g_FBOLayers[ 3 ];
vec2 fTextureSize;
vec4 SamplePix(in int buf, in vec2 tCoords, in float lod)
{
if (buf==1)
return textureLod(g_inLayers1, tCoords, lod);
else if (buf==2)
return textureLod(g_inLayers2, tCoords, lod);
return textureLod(g_inLayers0, tCoords, lod);
}
void main(void)
{
ivec2 iCoords = ivec2(int(gl_FragCoord.x),int(gl_FragCoord.y));
ivec2 iTextureSize = textureSize(g_inLayers0,0);
fTextureSize = vec2(float(iTextureSize.x), float(iTextureSize.y));
vec2 coords = vec2(gl_FragCoord.x/iTextureSize.x,gl_FragCoord.y/iTextureSize.y);
for(int i=0; i<3; ++i)
{
g_FBOLayers[i] = vec4(0.,0.,0.,0.);
}
int j = 0;
for(; j < 2; ++j)
{
g_FBOLayers[j] = SamplePix(j,coords,0);
}
}
// shader pass 3
//--------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------
#version 410
uniform sampler2D g_inLayers0;
uniform sampler2D g_inLayers1;
uniform sampler2D g_inLayers2;
in vec2 g_InterpUV ;
out vec4 g_PixColour;
vec4 tFetch(in int buf, in ivec2 tCoords, in int lod)
{
if (buf==1)
return texelFetch(g_inLayers1, tCoords, lod);
if (buf==2)
return texelFetch(g_inLayers2, tCoords, lod);
return texelFetch(g_inLayers0, tCoords, lod);
}
void main(void)
{
ivec2 iCoords = ivec2(int(gl_FragCoord.x),int(gl_FragCoord.y));
ivec2 iTextureSize = textureSize(g_inLayers0,0);
vec2 coords = vec2(gl_FragCoord.x/iTextureSize.x,gl_FragCoord.y/iTextureSize.y);
vec4 colour = vec4(0.,0.,0.,0.);
int i = 0;
for(; i <2; ++i) // 3rd texture omitted for now
{
vec4 texel = tFetch(i,iCoords,0);
if(texel.a + colour.a <= 1.0)
{
colour.rgb += (texel.rgb*texel.a);
colour.a += texel.a;
}
else
{
texel.a -= (texel.a + colour.a) - 1.0;
colour.rgb += (texel.rgb*texel.a);
colour.a += texel.a;
break;
}
}
g_PixColour = colour;
}