I need to read depth texture data in OpenGL Compute shader.
this is texture intialize code.
glActiveTexture(GL_TEXTURE4);
glGenTextures(1, &(framebufferDesc->m_DepthTextureId));
glBindTexture(GL_TEXTURE_2D, framebufferDesc->m_DepthTextureId);
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);
glTexImage2D(
GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, renderWidth, renderHeight, 0, GL_DEPTH_COMPONENT,
GL_UNSIGNED_BYTE, nullptr);
my goal is find 'maximum' depth. 1.0 or 0xffffff.
first, i try this.
//bind texture, (c++)
glBindImageTexture(2, m_EyeDesc[nEye].m_HMDDepthTextureId, 0, GL_FALSE, 0, GL_READ_ONLY, GL_R32UI);
//access texture (glsl)
layout (local_size_x = 16, local_size_y = 16) in;
layout(binding = 0, rgba8) uniform image2D img_input;
layout(binding = 1) uniform writeonly uimage2D img_output;
layout(binding = 2, r32ui) uniform uimage2D depthMap;
void main() {
ivec2 p = ivec2(gl_GlobalInvocationID.xy), temp_p;
uint u_empty_color = 0xffffffff;
//uint u_empty_color = 4294967295;
uvec4 depth;
depth = imageLoad(depthMap, p);
if (u_empty_color == depth.x) {//hole
imageStore(img_output, p, hole);
}
}
but upper code not work.
i try something, change depth_component24 to depth_component32, 0xffffffff to 0xffffff, r32ui to r32f.
but everything is fail.
i try another way, it's work.
uniform sampler2D depthMap;
layout (local_size_x = 16, local_size_y = 16) in;
layout(binding = 0, rgba8) uniform image2D img_input;
layout(binding = 1) uniform writeonly uimage2D img_output;
void main() {
ivec2 p = ivec2(gl_GlobalInvocationID.xy), temp_p;
float u_empty_color = 1.0;
vec2 pos = vec2(gl_GlobalInvocationID.x+1, gl_GlobalInvocationID.y+1);
pos.x = pos.x / u_width;
pos.y = pos.y / u_height;
vec4 depth;
depth = texture(depthMap, pos);
if (u_empty_color == depth.x) {//hole
imageStore(img_output, p, hole);
}
}
but, i think '/' is so bad! upper code is simple, real code is so long... i call really many times.
how can i access gl_depth_component24 format? i cant?
please help me!
How can i access depth texture with imageLoad()?
You can't. Image Load/Store only works for color image formats, and there is simply no path that would ever match GL_DEPTH_COMPONENT24. However, since you only read from the image anyway, there is also no need to use Image Load/Store. As you already noticed yourself, you can simly use it as texture and access it as sampler2D from the shader.
ivec2 p = ivec2(gl_GlobalInvocationID.xy), temp_p;
[...]
vec2 pos = vec2(gl_GlobalInvocationID.x+1, gl_GlobalInvocationID.y+1);
pos.x = pos.x / u_width;
pos.y = pos.y / u_height;
Your formula is wrong. You would have to use
vec2 pos = (vec2(p) + vec2(0.5))/vec2(u_width, u_height);
to correctly sample at the texel center that way.
but, i think '/' is so bad! upper code is simple, real code is so long... i call really many times.
I hardly doubt that the division operation will be relevant here at all, it should be completely hidden in the latencies of the memory accesses. Your performance will be determined by the sampling and the writing, and the ALU operations you do inbetween will be literally for free.
However, there is absolutely no need to go through the full texture sampling path. Use texelFetch to access the unfiltered texture data with integer coordinates:
depth = texelFetch(depthMap, p, 0);
Furthermore, it is very questionable if using a compute shader and writing via image load/store has any advantages of doing a fullscreen fragment shader pass directly rendering into the target texture.
Related
I need to read depth texture data in OpenGL Compute shader.
this is texture intialize code.
glActiveTexture(GL_TEXTURE4);
glGenTextures(1, &(framebufferDesc->m_DepthTextureId));
glBindTexture(GL_TEXTURE_2D, framebufferDesc->m_DepthTextureId);
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);
glTexImage2D(
GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, renderWidth, renderHeight, 0, GL_DEPTH_COMPONENT,
GL_UNSIGNED_BYTE, nullptr);
my goal is find 'maximum' depth. 1.0 or 0xffffff.
first, i try this.
//bind texture, (c++)
glBindImageTexture(2, m_EyeDesc[nEye].m_HMDDepthTextureId, 0, GL_FALSE, 0, GL_READ_ONLY, GL_R32UI);
//access texture (glsl)
layout (local_size_x = 16, local_size_y = 16) in;
layout(binding = 0, rgba8) uniform image2D img_input;
layout(binding = 1) uniform writeonly uimage2D img_output;
layout(binding = 2, r32ui) uniform uimage2D depthMap;
void main() {
ivec2 p = ivec2(gl_GlobalInvocationID.xy), temp_p;
uint u_empty_color = 0xffffffff;
//uint u_empty_color = 4294967295;
uvec4 depth;
depth = imageLoad(depthMap, p);
if (u_empty_color == depth.x) {//hole
imageStore(img_output, p, hole);
}
}
but upper code not work.
i try something, change depth_component24 to depth_component32, 0xffffffff to 0xffffff, r32ui to r32f.
but everything is fail.
i try another way, it's work.
uniform sampler2D depthMap;
layout (local_size_x = 16, local_size_y = 16) in;
layout(binding = 0, rgba8) uniform image2D img_input;
layout(binding = 1) uniform writeonly uimage2D img_output;
void main() {
ivec2 p = ivec2(gl_GlobalInvocationID.xy), temp_p;
float u_empty_color = 1.0;
vec2 pos = vec2(gl_GlobalInvocationID.x+1, gl_GlobalInvocationID.y+1);
pos.x = pos.x / u_width;
pos.y = pos.y / u_height;
vec4 depth;
depth = texture(depthMap, pos);
if (u_empty_color == depth.x) {//hole
imageStore(img_output, p, hole);
}
}
but, i think '/' is so bad! upper code is simple, real code is so long... i call really many times.
how can i access gl_depth_component24 format? i cant?
please help me!
How can i access depth texture with imageLoad()?
You can't. Image Load/Store only works for color image formats, and there is simply no path that would ever match GL_DEPTH_COMPONENT24. However, since you only read from the image anyway, there is also no need to use Image Load/Store. As you already noticed yourself, you can simly use it as texture and access it as sampler2D from the shader.
ivec2 p = ivec2(gl_GlobalInvocationID.xy), temp_p;
[...]
vec2 pos = vec2(gl_GlobalInvocationID.x+1, gl_GlobalInvocationID.y+1);
pos.x = pos.x / u_width;
pos.y = pos.y / u_height;
Your formula is wrong. You would have to use
vec2 pos = (vec2(p) + vec2(0.5))/vec2(u_width, u_height);
to correctly sample at the texel center that way.
but, i think '/' is so bad! upper code is simple, real code is so long... i call really many times.
I hardly doubt that the division operation will be relevant here at all, it should be completely hidden in the latencies of the memory accesses. Your performance will be determined by the sampling and the writing, and the ALU operations you do inbetween will be literally for free.
However, there is absolutely no need to go through the full texture sampling path. Use texelFetch to access the unfiltered texture data with integer coordinates:
depth = texelFetch(depthMap, p, 0);
Furthermore, it is very questionable if using a compute shader and writing via image load/store has any advantages of doing a fullscreen fragment shader pass directly rendering into the target texture.
I'm trying to implement deferred rendering within an engine I'm developing as a personal learning, and I cannot get to understand what I'm doing wrong when it comes to render all the textures in the GBuffer to check if the implementation is okay.
The thing is that I currently have a framebuffer with 3 color attachments for the different textures of the GBuffer (color, normal and position), which I initialize as follows:
glCreateFramebuffers(1, &id);
glBindFramebuffer(GL_FRAMEBUFFER, id);
std::vector<uint> textures;
textures.resize(3);
glCreateTextures(GL_TEXTURE_2D, 3, textures.data());
for(size_t i = 0; i < 3; ++i)
{
glBindTexture(GL_TEXTURE_2D, textures[i]);
if(i == 0) // For Color Buffer
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
else
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, width, height, 0, GL_RGBA, GL_FLOAT, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_TEXTURE_2D, textures[i], 0);
}
GLenum color_buffers[3] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2 };
glDrawBuffers((GLsizei)textures.size(), color_buffers);
uint depth_texture;
glCreateTextures(GL_TEXTURE_2D, 1, &depth_texture);
glBindTexture(GL_TEXTURE_2D, depth_texture);
glTexStorage2D(GL_TEXTURE_2D, 1, GL_DEPTH24_STENCIL8, width, height);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, depth_texture, 0);
bool fbo_status = glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE;
ASSERT(fbo_status, "Framebuffer Incompleted!");
glBindFramebuffer(GL_FRAMEBUFFER, 0);
This is not reporting any errors and it seems to work since the framebuffer of the forward renderer renders properly. Then, when rendering, I run the next code after binding the framebuffer and clearing the color and depth buffers:
camera_buffer->Bind();
camera_buffer->SetData("ViewProjection", glm::value_ptr(viewproj_mat));
camera_buffer->SetData("CamPosition", glm::value_ptr(glm::vec4(view_position, 0.0f)));
camera_buffer->Unbind();
for(Entity& entity : scene_entities)
{
shader->Bind();
Texture* texture = entity.GetTexture();
BindTexture(0, texture);
shader->SetUniformMat4("u_Model", entity.transform);
shader->SetUniformInt("u_Albedo", 0);
shader->SetUniformVec4("u_Material.AlbedoColor", entity->AlbedoColor);
shader->SetUniformFloat("u_Material.Smoothness", entity->Smoothness);
glBindVertexArray(entity.VertexArray);
glDrawElements(GL_TRIANGLES, entity.VertexArray.index_buffer.count, GL_UNSIGNED_INT, nullptr);
// Shader, VArray and Textures Unbindings
}
So with this code I manage to render the 3 textures created by using the ImGui::Image function, by switching the texture index between 0, 1 or 2 as the next:
ImGui::Image((ImTextureID)(fbo->textures[0]), viewport_size, ImVec2(0, 1), ImVec2(1, 0));
Now, the color texture (at index 0) works perfectly, as the next image shows:
But when rendering the normals and position textures (indexes 2 and 3), I have no result:
Does anybody sees what I'm doing wrong? Because I've been hours and hours with this and I cannot see it. I ran this on RenderDoc and I couldn't see anything wrong, the textures displayed in RenderDoc are the same than in the engine.
The vertex shader I use when rendering the entities is the next:
layout(location = 0) in vec3 a_Position;
layout(location = 1) in vec2 a_TexCoord;
layout(location = 2) in vec3 a_Normal;
out IBlock
{
vec2 TexCoord;
vec3 FragPos;
vec3 Normal;
} v_VertexData;
layout(std140, binding = 0) uniform ub_CameraData
{
mat4 ViewProjection;
vec3 CamPosition;
};
uniform mat4 u_ViewProjection = mat4(1.0);
uniform mat4 u_Model = mat4(1.0);
void main()
{
vec4 world_pos = u_Model * vec4(a_Position, 1.0);
v_VertexData.TexCoord = a_TexCoord;
v_VertexData.FragPos = world_pos.xyz;
v_VertexData.Normal = transpose(inverse(mat3(u_Model))) * a_Normal;
gl_Position = ViewProjection * u_Model * vec4(a_Position, 1.0);
}
And the fragment one is the next, they are both pretty simple:
layout(location = 0) out vec4 gBuff_Color;
layout(location = 1) out vec3 gBuff_Normal;
layout(location = 2) out vec3 gBuff_Position;
in IBlock
{
vec2 TexCoord;
vec3 FragPos;
vec3 Normal;
} v_VertexData;
struct Material
{
float Smoothness;
vec4 AlbedoColor;
};
uniform Material u_Material = Material(1.0, vec4(1.0));
uniform sampler2D u_Albedo, u_Normal;
void main()
{
gBuff_Color = texture(u_Albedo, v_VertexData.TexCoord) * u_Material.AlbedoColor;
gBuff_Normal = normalize(v_VertexData.Normal);
gBuff_Position = v_VertexData.FragPos;
}
It is not clear from the question what exactly might be happening here, as lots of GL states - both at the time the rendering to the gbuffer, and at that time the gbuffer texture is rendered for visualization - are just unknown. However, from the images given in the question, one can not conclude that the actual color output for attachments 1 and 2 is not working.
One issue which comes to mind is alpha blending. The color values processed by the per-fragment operations after the vertex shader are always working with RGBA values - although the value of the A channel only matters if you enabled blending and use a blend function which somehow depends on the source alpha.
If you declare a custom fragment shader output as float, vec2, vec3, the remaining components stay undefined (undefined value, not undefined behavior). This does not impose a problem unless some other operations you do depend on those values.
What we also have here is a GL_RGBA16F output format (which is the right choice, because none of the 3-component RGB formats are required as color-renderable by the spec).
What might happen here is either:
Alpha blending is already turned on during rendering into the g-buffer. The fragment shader's alpha output happens to be zero, so that it appears as 100% transparent and the contents of the texture are not changed.
Alpha blending is not used during rendering into the g-buffer, so the correct contents end up in the texture, the alpha channel just happens to end up with all zeros. Now the texture might be visualized with alpha blending enbaled, ending up in a 100% transparent view.
If it is the first option, turn off blending when rendering the into the g-buffer. It would not work with deferred shading anyway. You might still run into the second option then.
If this is the second option, there is no issue at all - the lighting passes which follow will read the data they need (and ultimately, you will want to put useful information into the alpha channel to not waste it and be able to reduce the number of attachments). It is just your visualization (which I assume is for debug purposed only) is wrong. You can try to fix the visualization.
As a side note: Storing the world space position in the G-Buffer is a huge waste of bandwidth. All you need to be able to reconstruct the world space position is the depth value and the inverse of your view and projection matrices. Also storing world space position in GL_RGB16F will very easily run into precision issues if you move your camera away from world space origin.
I'm trying to implement ray casting based volume rendering and therefore I'd need to pass a float Array to the fragment shader as a Texture (Sampler3D).
I've got a volume datastructure containing all the voxels. Each voxel contains a density value. So for processing I stored the values into a float Array.
//initialize glew, initialize glfw, create window, etc.
float* density;
density = new float[volume->size()];
for (int i = 0; i < volume->size(); i++){
density[i] = volume->voxel(i).getValue();
}
Then I tried creating and binding the textures.
glGenTextures(1, &textureHandle);
glBindTexture(GL_TEXTURE_3D, textureHandle);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_REPEAT);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexImage3D(GL_TEXTURE_3D, 0, GL_LUMINANCE, volume->width(),
volume->height(), volume->depth(), 0, GL_LUMINANCE, GL_FLOAT, density);
In my render loop I try to load the Texture to the uniform Sampler3D.
glClearColor(0.4f, 0.2f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glActiveTexture(GL_TEXTURE0);
GLint gSampler = glGetUniformLocation(shader->shaderProgram, "volume");
glUniform1i(gSampler, 0);
cube->draw();
So the basic idea is to calculate the current position and direction for ray casting in the Vertex Shader.
in vec3 position;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
uniform vec4 cameraPos;
out vec3 pos;
out vec3 dir;
void main(){
gl_Position = projection * view * model * vec4(position, 1.0);
pos = position;
dir = pos - (inverse(model) * cameraPos).xyz;
}
That seems to work well, so far so good. The fragment shader looks like this. I take some samples along the ray and the one with the largest density value will be taken as a color for red, green and blue.
#version 330 core
in vec3 pos;
in vec3 dir;
uniform sampler3D volume;
out vec4 color;
const float stepSize = 0.008;
const float iterations = 1000;
void main(){
vec3 rayDir = normalize(dir);
vec3 rayPos = pos;
float src;
float dst = 0;
float density = 0;
for(int i = 0; i < iterations; i++){
src = texture(volume, rayPos).r;
if(src > density){
density = src;
}
rayPos += rayDir * stepSize;
//check whether rays are within bounds. if not -> break.
}
color = vec4(density, density, density, 1.0f);
}
Now I've tried inserting some small debug assertions.
if(src != 0){
rayPos = vec3(1.0f);
break;
}
But src seems to be 0 at every iteration of every pixel. Which gets me to the conclusion that the Sampler isn't correctly set. Debugging the C++ code I get the correct values for the density array right before I pass it to the shader, so I guess there must be some opengl function missing. Thanks in advance!
glTexImage3D(GL_TEXTURE_3D, 0, GL_LUMINANCE, volume->width(), volume->height(), volume->depth(), 0, GL_LUMINANCE, GL_FLOAT, density);
Unless this density is on the range [0, 1], then this is almost certainly not doing what you intend.
GL_LUMINANCE, when used as an internal format (the third parameter to glTexImage3D, means that each pixel in OpenGL's texture data will contain a single normal integer value. So if you want a floating-point value, you're kinda out of luck.
The proper way to do this is to explicitly declare the type and pixel size of the data. Luminance was removed from the core OpenGL profile back in 3.1, so the way to do that today is to use GL_R32F as your internal format. That declares that each pixel contains one value, and that value is a 32-bit float.
If you really need to broadcast the value across the RGB channels, you can use texture swizzling to accomplish that. You can set a swizzle mask to broadcast the red component to any other channel you like.
glActiveTexture(GL_TEXTURE0);
GLint gSampler = glGetUniformLocation(shader->shaderProgram, "volume");
glUniform1i(gSampler, 0);
I've heard that binding the texture is also a good idea. You know, if you actually want to read from it ;)
I am having problems getting the correct texture coordinate to sample my shadow map. Looking at my code, the problem appears to be from incorrect matrices. This is the fragment shader for the rendering pass where I do shadows:
in vec2 st;
uniform sampler2D colorTexture;
uniform sampler2D normalTexture;
uniform sampler2D depthTexture;
uniform sampler2D shadowmapTexture;
uniform mat4 invProj;
uniform mat4 lightProj;
uniform vec3 lightPosition;
out vec3 color;
void main () {
vec3 clipSpaceCoords;
clipSpaceCoords.xy = st.xy * 2.0 - 1.0;
clipSpaceCoords.z = texture(depthTexture, st).x * 2.0 - 1.0;
vec4 position = invProj * vec4(clipSpaceCoords,1.0);
position.xyz /= position.w;
//At this point, position.xyz seems to be what it should be, the world space coordinates of the pixel. I know this because it works for lighting calculations.
vec4 lightSpace = lightProj * vec4(position.xyz,1.0);
//This line above is where I think things go wrong.
lightSpace.xyz /= lightSpace.w;
lightSpace.xyz = lightSpace.xyz * 0.5 + 0.5;
float lightDepth = texture(shadowmapTexture, lightSpace.xy).x;
//Right here lightDepth seems to be incorrect. The only explanation I can think of for this is if there is a problem in the above calculations leading to lightSpace.xy.
float shadowFactor = 1.0;
if(lightSpace.z > lightDepth+0.0005) {
shadowFactor = 0.2;
}
color = vec3(lightDepth);
}
I have removed all the code irrelevant to shadowing from this shader (Lighting, etc). This is the code I use to render the final pass:
glCullFace(GL_BACK);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
postShader->UseShader();
postShader->SetUniform1I("colorTexture", 0);
postShader->SetUniform1I("normalTexture", 1);
postShader->SetUniform1I("depthTexture", 2);
postShader->SetUniform1I("shadowmapTexture", 3);
//glm::vec3 cp = camera->GetPosition();
postShader->SetUniform4FV("invProj", glm::inverse(camera->GetCombinedProjectionView()));
postShader->SetUniform4FV("lightProj", lights[0].camera->GetCombinedProjectionView());
//Again, if I had to guess, these two lines above would be part of the problem.
postShader->SetUniform3F("lightPosition", lights[0].x, lights[0].y, lights[0].z);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, frameBuffer->GetColor());
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, frameBuffer->GetNormals());
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, frameBuffer->GetDepth());
glActiveTexture(GL_TEXTURE3);
glBindTexture(GL_TEXTURE_2D, lights[0].shadowmap->GetDepth());
this->BindPPQuad();
glDrawArrays(GL_TRIANGLES, 0, 6);
In case it is relevant to my problem, here is how I generate the depth framebuffer attachments for the depth and shadow maps:
void FrameBuffer::Init(int textureWidth, int textureHeight) {
glGenFramebuffers(1, &fbo);
glGenTextures(1, &depth);
glBindTexture(GL_TEXTURE_2D, depth);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, textureWidth, textureHeight, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth, 0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
Where is the problem in my math or my code, and what can I do to fix it?
After some experimentation, I have found that my problem does not lie in my matrices, but in my clamping. It seems that I get strange values when I use GL_CLAMP or GL_CLAMP_TO_EDGE, but I get almost correct values when I use GL_CLAMP_TO_BORDER. There are more problems, but they do not seem to be matrix related as I thought.
I am trying to implement Accumulation Motion Blur with modern OpenGL (Yes, I know it is slow and arguably realistic,in case Nicol Bolas is going to question...But that's what I need). My source of reference is OpenGL SuperBible-5.
It doesn't work for me.There is no blur in the output.I am passing 6 textures into fragment shader and it seems like they all have the same frame.
Also, I am getting debug log from OpenGL with the following message:
Severity:Medium, Message: Pixel-patch performance warning:Pixel transfer is synchronized with 3D rendering.
To me it looks like the PBO fails to blit pixels from backbuffer into the texture,or to acquire those from backbuffer.
Here is my setup:
GLint dataSize = _viewportW * _viewportH * 4 * sizeof(GLfloat);
void* data = (void*)malloc(dataSize);
memset(data, 0x00, dataSize);
glGenBuffers(1,&_pbo1);
glBindBuffer(GL_PIXEL_PACK_BUFFER,_pbo1);
glBufferData(GL_PIXEL_PACK_BUFFER,dataSize,data,GL_DYNAMIC_COPY);
glBindBuffer(GL_PIXEL_PACK_BUFFER , 0);
_blurTexs.resize(mbSamplesNum);
for(GLint i = 0; i <mbSamplesNum; ++i) {
glGenTextures(1, &_blurTexs[i]);
glActiveTexture(GL_TEXTURE0 + i);
glBindTexture(GL_TEXTURE_2D, _blurTexs[i]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexStorage2D(GL_TEXTURE_2D,1, GL_RGBA8, _viewportW, _viewportH);
glTexSubImage2D(GL_TEXTURE_2D,0,0,0,_viewportW,_viewportH,GL_RGBA,GL_UNSIGNED_BYTE,data);
glBindTexture(GL_TEXTURE_2D,0);
}
And here is the render loop:
// HERE DRAW STUFF INTO BACKBUFFER.....
glBindBuffer(GL_PIXEL_PACK_BUFFER, _pbo1);
glReadPixels(0, 0, _viewportW, _viewportH, GL_RGBA, GL_UNSIGNED_BYTE, BUFFER_OFFSET(0));
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
// Next bind the PBO as the unpack buffer, then push the pixels straight into the texture
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, _pbo1);
// Setup texture unit for new blur, this gets imcremented every frame
GLuint curIndex =GetBlurTarget0();
glBindTexture(GL_TEXTURE_2D,_blurTexs[curIndex]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, _viewportW, _viewportH, 0, GL_RGBA, GL_UNSIGNED_BYTE, BUFFER_OFFSET(0));
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
// Draw full screen quad with blur shader and all blur textures:
_progManager->BindPipeline(ACCUM_PIPELINE);
GLuint fragProg =GetProg();
GLuint t0= GetBlurTarget0();
GLuint t1= GetBlurTarget1();
GLuint t2= GetBlurTarget2();
GLuint t3= GetBlurTarget3();
GLuint t4= GetBlurTarget4();
GLuint t5= GetBlurTarget5();
glActiveTexture(GL_TEXTURE0 );
glBindTexture(GL_TEXTURE_2D,_blurTexs[t0]);
glActiveTexture(GL_TEXTURE1 );
glBindTexture(GL_TEXTURE_2D,_blurTexs[t1]);
glActiveTexture(GL_TEXTURE2 );
glBindTexture(GL_TEXTURE_2D,_blurTexs[t2]);
glActiveTexture(GL_TEXTURE3 );
glBindTexture(GL_TEXTURE_2D,_blurTexs[t3]);
glActiveTexture(GL_TEXTURE4 );
glBindTexture(GL_TEXTURE_2D,_blurTexs[t4]);
glActiveTexture(GL_TEXTURE5 );
glBindTexture(GL_TEXTURE_2D,_blurTexs[t5]);
_screenQuad->Draw();
glBindTexture(GL_TEXTURE_2D,0);
AdvanceBlurTaget();
_progManager->UnBindPipeline();
Here is my fragment shader :
#version 420 core
// This is the output color
out vec4 color;///layout (location = 0)
const int numFrames =6;
layout(binding=0)uniform sampler2D textureUnit0;
layout(binding=1)uniform sampler2D textureUnit1;
layout(binding=2)uniform sampler2D textureUnit2;
layout(binding=3)uniform sampler2D textureUnit3;
layout(binding=4)uniform sampler2D textureUnit4;
layout(binding=5)uniform sampler2D textureUnit5;
void main(void)
{
vec2 texelSize = 1.0 / vec2(textureSize(textureUnit0, 0));
vec2 screenTexCoords = gl_FragCoord.xy * texelSize;
// 0 is the newest image and 5 is the oldest
vec4 blur0 = texture(textureUnit0, texelSize);
vec4 blur1 = texture(textureUnit1, texelSize);
vec4 blur2 = texture(textureUnit2, texelSize);
vec4 blur3 = texture(textureUnit3, texelSize);
vec4 blur4 = texture(textureUnit4, texelSize);
vec4 blur5 = texture(textureUnit5, texelSize);
vec4 summedBlur = blur0 + blur1 + blur2 + blur3 + blur4 + blur5;
color = summedBlur / numFrames;
}
UPDATE
Ok,Ok, MY BAD....
Silly mistake in the fragment shader:
vec2 screenTexCoords = gl_FragCoord.xy * texelSize;
// 0 is the newest image and 5 is the oldest
vec4 blur0 = texture(textureUnit0, screenTexCoords );
vec4 blur1 = texture(textureUnit1, screenTexCoords );
vec4 blur2 = texture(textureUnit2, screenTexCoords );
vec4 blur3 = texture(textureUnit3, screenTexCoords );
vec4 blur4 = texture(textureUnit4, screenTexCoords );
vec4 blur5 = texture(textureUnit5, screenTexCoords );
I mistakenly passed texelSize for UV instead of screenTexCoords .