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 .
Related
I have a scalar field of values which I have mapped to a 3D texture( image_texture ). And then given a plane gPlaneParams , I have to render the texture of the scalar-field along it.
What I'm doing:
I send 4 points which span the window dimensions using two triangles to the shaders. I bind the texture using a sampler in the fragment shader. Below is the fragment shader code.
#version 330 core
uniform sampler3D text_sampler;
uniform vec4 gPlaneParams;
in vec4 inPos;
void main()
{
vec4 Pos = inPos;
// position input is a square[-1,1]^2
// and needs to be mapped the plane ax+by+cz=d, where a,b,c,d are the plane parameters;
//where x,y,z belongs to [0,1]^3
if (gPlaneParams.z!=0){
Pos.z = (gPlaneParams.w - gPlaneParams.x*Pos.x - gPlaneParams.y*Pos.y)/gPlaneParams.z;
}
else{
if (gPlaneParams.x!=0){
Pos.z=Pos.x;
Pos.x = (gPlaneParams.w - gPlaneParams.y*Pos.y - gPlaneParams.z*Pos.z)/gPlaneParams.x;
}
else if (gPlaneParams.y!=0){
Pos.z=Pos.y;
Pos.y = (gPlaneParams.w - gPlaneParams.x*Pos.x - gPlaneParams.z*Pos.z)/gPlaneParams.y;
}
}
gl_FragColor=vec4(1.0,0,0,0)*texture3D(text_sampler,(Pos.xyz+1)/2);
}
In my C++ code, I bind the texture as follows:
glGenTextures(1,textureID);
glBindTexture(GL_TEXTURE_3D,textureID[0]);
glTexImage3D(GL_TEXTURE_3D, 0, GL_RGB,object_size[0],object_size[1],object_size[2], 0, GL_RGB, GL_UNSIGNED_INT, image_texture1);
glTexParameterf(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_3D,GL_TEXTURE_WRAP_R,GL_CLAMP_TO_EDGE);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_3D,textureID[0]);
bool err=glIsTexture(textureID[0]);
cout<<"Texture bound?"<<err<<endl;
Unfortunately, this does not render any output. Can someone help me figure out what I'm doing wrong?
I have done everything else correctly
The 4 Vertices and 2 triangles are properly bound (I can render them by giving them constant colours)
The image texture is contiguous in memory image_texture = (unsigned int*) malloc(object_size[0] *object_size[1] *object_size[2]*3* sizeof(unsigned int));
All my inputs to the shader are successfully bound.:
gSamplerLocation = glGetUniformLocation(ShaderProgram, "text_sampler");
gPLaneLoc = glGetUniformLocation(ShaderProgram, "gPlaneParams");
glUniform1i(gSamplerLocation, 0);
glUniform4f(gPLaneLoc,plane_params[0],plane_params[1],plane_params[2],plane_params[3]);
I am having a problem with my SSAO implementation. Whenever I get close to a surface the edges of the screen appear to darken and this causes a large performance drop.
It has come to my knowledge that the darkening might be happening on the noise texture. But I have tried changing the positions texture to GL_REPEAT, GL_CLAMP_TO_EDGE and it still doesnt reduce the problem.
Any ideas? Here is the code..
gPosition Setup
// The attachment is added in as follows
new FboAttachment(width, height, GL_RGB16F, GL_RGB, GL_FLOAT, GL_COLOR_ATTACHMENT0, false, true)
// attachment is created like this
// This function will create an fbo attachment
inline void Create()
{
// Generate a texture and sets its data and information
glGenTextures(1, &_texture); // Generate the colour texture
glBindTexture(GL_TEXTURE_2D, _texture); // Bind the texture map
glTexImage2D(GL_TEXTURE_2D, 0, _internal_format, _width, _height, 0, _format, _type, 0); // Store the texture data to a buffer
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); // Set the linear filter for min
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, _mipmapping == true ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR); // Set the linear filter for mag
/*
* If border clamping is enabled then set the border colour (mainly used for shadow mapping to remove peter panning)
*/
if (_border_clamping)
{
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 border[4] = { 1,0,0,0 };
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border);
}
/*
* If mipmapping enabled then generate mipmaps for this FBO texture.
*/
if (_mipmapping)
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); // set the minimum texture mip level
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 4); // set the maximum texture mip level
glGenerateMipmap(GL_TEXTURE_2D); // generate a mipmap for the shadowmap
}
// Send this generated texture to the framebufferobject
glFramebufferTexture2D(GL_FRAMEBUFFER, _attachment, GL_TEXTURE_2D, _texture, 0); // Assign the texture to the frame buffer as an attachment
// Check for any problems with the frame buffer object
if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
std::cout << "Error : FBO Could not be created!" << std::endl;
}
SSAO Setup
// Initialise the post effect
inline void Create(std::vector<GLuint> shader_programs, size_t width, size_t height, GLuint sample_res)
{
_shader_programs = shader_programs; // Assign shader pointers
_sample_res = sample_res; // Assign sample resolution value
_rect = new Rect((double)width, (double)height, 1.0f, true);
// Create two frame buffers, one for ssao colour and another for ssao blur
_fbos.push_back(new Fbo(width, height, { new FboAttachment(width, height, GL_RED, GL_RGB, GL_FLOAT, GL_COLOR_ATTACHMENT0) }, false));
_fbos.push_back(new Fbo(width, height, { new FboAttachment(width, height, GL_RED, GL_RGB, GL_FLOAT, GL_COLOR_ATTACHMENT0) }, false));
//////////////////////////////////////////////////////////////////////////////////////////////////////////
std::uniform_real_distribution<GLfloat> rand_floats(0.0f, 1.0f); // Generate random floats between 0.0 and 1.0
std::default_random_engine rand_generator; // A generator for randomising floats
// Create temp iterator var
for (unsigned int i = 0; i < 64; ++i) // Iterate through each sample...
{
glm::vec3 sample(rand_floats(rand_generator) * 2.0f - 1.0f,
rand_floats(rand_generator) * 2.0f - 1.0f,
rand_floats(rand_generator)); // the third parameter was wrong on this line
sample = glm::normalize(sample); // Normalise the sample
sample *= rand_floats(rand_generator); // Seed the randomisation
float scale = (float)i / 64.0f; // Get pixel position in NDC about the resolution size
scale = Math::lerpf(0.1f, 1.0f, scale * scale); // Interpolate the scale
sample *= scale; // Scale the s and t values
_ssao_kernals.push_back(sample); // Assign sample to the kernal array
_u_samples.push_back(glGetUniformLocation(shader_programs[0], ("samples[" + std::to_string(i) + "]").c_str())); // Get each sample uniform location
}
// generate noise texture
for (unsigned int i = 0; i < 16; i++)
{
glm::vec3 noise(rand_floats(rand_generator) * 2.0 - 1.0, rand_floats(rand_generator) * 2.0 - 1.0, 0.0f); // rotate around z-axis (in tangent space)
ssaoNoise.push_back(noise);
}
glGenTextures(1, &noiseTexture);
glBindTexture(GL_TEXTURE_2D, noiseTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, 4, 4, 0, GL_RGB, GL_FLOAT, &ssaoNoise[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_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glUseProgram(_shader_programs[0]); // Use the first shader pass
glUniform1i(glGetUniformLocation(shader_programs[0], "gPosition"), 0); // The positions texture in the gbuffer
glUniform1i(glGetUniformLocation(shader_programs[0], "gNormal"), 1); // The normals texture in the gbuffer
glUniform1i(glGetUniformLocation(shader_programs[0], "texNoise"), 2); // The albedospec texture in the gbuffer
_u_projection = glGetUniformLocation(shader_programs[0], "proj"); // Get projection uniform
glUseProgram(_shader_programs[1]); // Use the second shader pass
glUniform1i(glGetUniformLocation(shader_programs[1], "ssaoInput"), 0); // the positions texture in the gbuffer
}
SSAO Binding
inline virtual void Render()
{
_fbos[0]->Bind(); // bind ssao texture
glClear(GL_COLOR_BUFFER_BIT); // clear colour data on the screen
glUseProgram(_shader_programs[0]); // Use the first shader pass
for (unsigned int i = 0; i < SSAO_SAMPLE_RESOLUTION; ++i) // For each ssao sample...
glUniform3fv(_u_samples[i], 1, glm::value_ptr(_ssao_kernals[i])); // Assign kernal uniform data
glUniformMatrix4fv(_u_projection, 1, GL_FALSE, glm::value_ptr(Content::_map->GetCamera()->GetProjectionMatrix())); // Assign camera projection uniform data
glActiveTexture(GL_TEXTURE0); // Set active texture to index 0
glBindTexture(GL_TEXTURE_2D, _g_buffer_data->GetAttachments()[0]->_texture); // Bind positions
glActiveTexture(GL_TEXTURE1); // Set active texture to index 1
glBindTexture(GL_TEXTURE_2D, _g_buffer_data->GetAttachments()[1]->_texture); // Bind normals
glActiveTexture(GL_TEXTURE2); // Set active texture to index 2
glBindTexture(GL_TEXTURE_2D, noiseTexture); // Bind the noise texture
_screen_rect->Render(1); // Render to screen rectangle
_fbos[0]->Unbind();
// Blur ssao texture
_fbos[1]->Bind();
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(_shader_programs[1]); // Use the second shader pass
glActiveTexture(GL_TEXTURE0); // Bind active texture to index 0
glBindTexture(GL_TEXTURE_2D, _fbos[0]->GetAttachments()[0]->_texture); // Bind the final colour
_screen_rect->Render(1); // Render to screen rectangle
_fbos[1]->Unbind();
}
SSAO Fragment Shader
#version 330 core
out float FragColor;
in vec2 _texcoord;
uniform sampler2D gPosition;
uniform sampler2D gNormal;
uniform sampler2D texNoise;
uniform vec3 samples[64];
int kernelSize = 64;
float radius = 0.5;
float bias = 0.025;
const vec2 noiseScale = vec2(1920.0 / 4.0, 1080.0 / 4.0);
uniform mat4 proj;
void main()
{
vec3 fragPos = texture(gPosition, _texcoord).xyz;
vec3 normal = normalize(texture(gNormal, _texcoord).rgb);
vec3 randomVec = normalize(texture(texNoise, _texcoord * noiseScale).xyz);
vec3 tangent = normalize(randomVec - normal * dot(randomVec, normal));
vec3 bitangent = cross(normal, tangent);
mat3 TBN = mat3(tangent, bitangent, normal);
float occlusion = 0.0;
for(int i = 0; i < kernelSize; ++i)
{
// get sample position
vec3 sample = TBN * samples[i]; // from tangent to view-space
sample = fragPos + sample * radius;
// project sample position (to sample texture) (to get position on screen/texture)
vec4 offset = vec4(sample, 1.0);
offset = proj * offset; // from view to clip-space
offset.xyz /= offset.w; // perspective divide
offset.xyz = offset.xyz * 0.5 + 0.5; // transform to range 0.0 - 1.0
// get sample depth
float sampleDepth = texture(gPosition, offset.xy).z; // get depth value of kernel sample
// range check & accumulate
float rangeCheck = smoothstep(0.0, 1.0, radius / abs(fragPos.z - sampleDepth));
occlusion += (sampleDepth >= sample.z + bias ? 1.0 : 0.0) * rangeCheck;
}
occlusion = 1.0 - (occlusion / kernelSize);
FragColor = pow(occlusion, 5.0);
}
What could be the reason of this problem?
Problem Fixed
GL_CLAMP_TO_EDGE fixed it
In a nutshell
In a single shader pass I'm applying a couple of different model transformation matrices in the Vertex Shader and writing the results into different position vectors.
Then I do some simple arithmetic with the different results in the Vertex Shader.
//Vertex Shader
in layout(location=0) vec3 position;
in layout(location=1) vec3 vertexColor;
...
out vec3 result1;
out vec3 result2;
out vec3 result3;
out vec3 color;
void main()
{
gl_Position = transformationMatrix * vec4(position, 1.0);
vec4 pos1 = transformationMatrix1 * vec4(position, 1.0);
vec4 pos2 = transformationMatrix2 * vec4(position, 1.0);
...
result1 = pos1.xyz * pos2.xyz / 0.012313879834;
result2 = (pos2.xyz + pos1.xyz) * 1.5;
result3 = ....;
color = vertexColor;
}
The results of that math I want to pass through the Fragment Shader (so the values are interpolated nicely like colors are) ...
// Fragment shader
in vec3 color;
in vec3 result1;
in vec3 result2;
in vec3 result3;
layout(location = 0) out vec4 theColor;
layout(location = 1) out vec3 output1;
layout(location = 2) out vec3 output2;
layout(location = 3) out vec3 output3;
void main()
{
theColor = vec4(color, 1.0);
output1 = result1;
output2 = result2;
}
... to finally read them back, so that I can continue working with the data on the CPU. I need the data read back to be precise (float 32) and optimally not normalized to [0, 1].
Regarding this I have a couple of questions:
Initially I thought it would be possible to facilitate this using the GL_COLOR_ATTACHMENTi, but I haven't been able to figure out how. Is it possible? If so, how would I go about it?
How would a solution using the Image Load/Store functionality since OpenGL 4.2 look like? Are there potential pitfalls that I need to be aware of?
EDIT: I got it to work with the Color Attachments after all. See below for a solution that worked for me.
Found a solution to work with the Color Attachments after all. The client-side code looks like the following, the Shaders didn't need any change iirc:
void initializeGL()
{
....
// Generate textures.
glGenTextures(3, textures.data());
for (GLuint id : textureIds)
{
// Bind texture and specify size and nature ...
glBindTexture(GL_TEXTURE_2D, id);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, m_width, m_height, 0, GL_RGB, GL_FLOAT, nullptr);
}
glBindTexture(GL_TEXTURE_2D, 0);
....
// Attach texture images to Framebuffer.
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, otherTextureId, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, textureIds[0], 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, textureIds[1], 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3, GL_TEXTURE_2D, textureIds[2], 0);
// Specify color buffers that will be written to.
const GLenum buffers[] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3};
glDrawBuffers(4, buffers);
....
}
void renderGL()
{
....
// Copy images into corresponding buffers in the main memory.
glReadBuffer(GL_COLOR_ATTACHMENT1);
glReadPixels(0, 0, m_width, m_height, GL_RGB, GL_FLOAT, texture1.data());
glReadBuffer(GL_COLOR_ATTACHMENT2);
glReadPixels(0, 0, m_width, m_height, GL_RGB, GL_FLOAT, texture2.data());
glReadBuffer(GL_COLOR_ATTACHMENT3);
glReadPixels(0, 0, m_width, m_height, GL_RGB, GL_FLOAT, texture3.data());
....
}
Any feedback would still be appreciated.
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 want to render a terrain and apply colors depending on height.
I'm writing a Qt project, so use QGlShaderProgram.
My terrain grid is from (0,0,0) to (1000,0,1000) and vertices are placed every 100 length units. I wanted to transfer the data to the shader using an uniform array.
I still have problems sending data to the shader.
call from C++/Qt:
QGLShaderProgram mShader;
QVector< GLfloat> mHeightMap (10*10, some_data);
GLfloat mXStepSize = 100;
GLfloat mZStepSize = 100;
// ..
mShader.link();
mShader.bind();
mShader.setUniformValueArray( "heights",
&(mHeightMap[0]), // one line after another
mHeightMap.size(), 1 );
mShader.setUniformValue( "x_res", (GLint) mXStepSize);
mShader.setUniformValue( "z_res", (GLint) mZStepSize);
shader source:
uniform sampler2D heights;
uniform int x_res;
uniform int z_res;
void main(void)
{
vec4 tmp = gl_Vertex;
vec4 h;
float x_coord = gl_Vertex[0] * 0.001;
float z_coord = gl_Vertex[2] * 0.001;
// interprete as 2D:
int element = int( (x_coord + float(x_res)*z_coord) );
h = texture2D( heights, vec2(x_coord, z_coord));
gl_FrontColor = gl_Color;
gl_FrontColor[1] = h[ element]; // set color by height
tmp.y = h[ element]; // write height to grid
gl_Position = gl_ModelViewProjectionMatrix * tmp;
}
Where is my mistake?
How should I load the data to the shader and then access it there?
You want to pass it as a texture, you must first convert your array map (mHeightMap) in a opengl texture using glTexImage2D.
look at this , it might be what your looking for: https://gamedev.stackexchange.com/questions/45188/how-can-i-pass-an-array-of-floats-to-the-fragment-shader-using-textures
Edit: You might want to tweak some of it, but it's the idea:
//Create texture:
glint texture;
glActiveTexture(GL_TEXTURE0);
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, 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, Width, Height, 0, GL_RGBA,
GL_UNSIGNED_BYTE, &(mHeightMap.constData()[data_start]));
//pass it to shader
glint uniformId = glGetUniformid(shader, "height");
glActiveTexture(GL_TEXTURE0);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, texture);
glUniform1i(uniformId, 0); // 0 is the texture number
(the code seems to work now)
I figured most of it out, with the help of izissise. I used GL_TEXTURE_RECTANGLE instead of GL_TEXTURE_2D.
Still it uses only the red channel (this might be optimized).
this is my Initialization:
QGLShaderProgram mShader;
QVector< GLfloat> mHeightMap (width * height * state_count,
some_data);
mShader.link();
// init texture
glActiveTexture(GL_TEXTURE0);
glGenTextures(1, &mShaderTexture);
glBindTexture(GL_TEXTURE_RECTANGLE, mShaderTexture);
and sending data to shader (this may be repeated as often as wanted):
mShader.bind();
// ..
glTexImage2D(GL_TEXTURE_RECTANGLE, 0, GL_RED,
width, depth, 0,
GL_RED, GL_FLOAT,
&(mHeightMap.constData()[mHeightMapPos])); // set portion of vector as array to texture / sampler
glActiveTexture(GL_TEXTURE0);
glEnable(GL_TEXTURE_RECTANGLE);
glBindTexture(GL_TEXTURE_RECTANGLE, mShaderTexture);
mShader.setUniformValue( "max_height", (GLfloat) (250.0) );
mShader.setUniformValue( "x_steps", (GLint) width);
mShader.setUniformValue( "z_steps", (GLint) height);
// ..
mShader.release();
as well as the shader source:
uniform int x_steps;
uniform int z_steps;
uniform sampler2DRect heights;
uniform float max_height;
void main(void)
{
vec4 tmp = gl_Vertex;
vec4 h;
float x_coord = gl_Vertex[0] * 0.001 * float(x_steps-1);
float z_coord = gl_Vertex[2] * 0.001 * float(z_steps-1);
h = texture2DRect( heights, ivec2(int(x_coord), int(z_coord)) );
tmp.y = max_height * (h.r);
gl_FrontColor = gl_Color;
gl_FrontColor[1] = h.r;
gl_Position = gl_ModelViewProjectionMatrix * tmp;
}