openGL single channel texture always samples 0 - c++

I'm trying to render font on screen using freetype. For that, I implemented single channel texture but it always samples 0.
cpp
unsigned char *blankData = new unsigned char[8 * 8];
for(int i = 0; i < 8 * 8; i++){
blankData[i] = 126;
}
glActiveTexture(GL_TEXTURE0);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
GLuint m_texture2D;
glGenTextures(1, &m_texture2D);
glBindTexture(GL_TEXTURE_2D, m_texture2D);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, 8, 8, 0, GL_RED, GL_UNSIGNED_BYTE, blankData);
glUniform1i(glGetUniformLocation(m_program, "texture2D"), 0);
checkGLError();
glGetError() returns GL_NO_ERROR
fragment Shader
#version 330 core
in vec2 texCoord;
in vec4 color;
uniform sampler2D texture2D;
out vec4 outColor;
void main()
{
vec4 texColor = texture(texture2D, texCoord);
outColor = vec4(texColor.r, texColor.r, texColor.r, 1.0f);
}
result
ff00ff: clear color
black: fragment shader output texcoord bottomLeft(0, 0) to topRight(1, 1)

If you are not generating mipmaps (with glGenerateMipmap) it is important to set GL_TEXTURE_MIN_FILTER. Since the default filter is GL_NEAREST_MIPMAP_LINEAR, the texture would be "Mipmap Incomplete" if you do not change the minimize function to GL_NEAREST or GL_LINEAR.
glBindTexture(GL_TEXTURE_2D, m_texture2D);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

Related

Use multiple sampler2D over one input texture in OpenGL

Now I have a noise texture generated by this website: https://aeroson.github.io/rgba-noise-image-generator/. I want to use 4 uniform samplers in my computing shader to get 4 random rgba values from a single noise texture. My computing shader source codes look like:
#version 430 core
layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
uniform sampler2D noise_r0;
uniform sampler2D noise_i0;
uniform sampler2D noise_r1;
uniform sampler2D noise_i1;
layout (binding = 0, rgba32f) writeonly uniform image2D tilde_h0k;
layout (binding = 1, rgba32f) writeonly uniform image2D tilde_h0minusk;
uniform int N = 256;
....
// Box-Muller algorithm
vec2 texCoord = vec2(gl_GlobalInvocationID.xy) / float(N); // Here every invocation refers to a pixel of output image
float noise00 = clamp(texture(noise_r0, texCoord).r, 0.001, 1.0);
float noise01 = clamp(texture(noise_i0, texCoord).r, 0.001, 1.0);
float noise02 = clamp(texture(noise_r1, texCoord).r, 0.001, 1.0);
float noise03 = clamp(texture(noise_i1, texCoord).r, 0.001, 1.0);
....
and in the main program, I use this code to upload my downloaded noise texture to the computing shader:
unsigned int tex_noise;
glGenTextures(1, &tex_noise);
glBindTexture(GL_TEXTURE_2D, tex_noise);
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_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
int w_noise, h_noise, nrChannels;
unsigned char* data = stbi_load("noise.png", &w_noise, &h_noise, &nrChannels, 0);
if (data) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w_noise, h_noise, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
}
else std::cout << "Failed to load noise texture." << std::endl;
stbi_image_free(data);
....
....
My question is: Can I set up those sampler2D's in computing shader using this code?
glUseProgram(computeProgram);
glActiveTexture(GL_TEXTURE1);
glUniform1i(glGetUniformLocation(computeProgram, "noise_r0"), 1);
glActiveTexture(GL_TEXTURE2);
glUniform1i(glGetUniformLocation(computeProgram, "noise_i0"), 2);
glActiveTexture(GL_TEXTURE3);
glUniform1i(glGetUniformLocation(computeProgram, "noise_r1"), 3);
glActiveTexture(GL_TEXTURE4);
glUniform1i(glGetUniformLocation(computeProgram, "noise_i1"), 4);
If it is wrong, what should I do to set up those sampler2D's, and make sure that the random rgba values I get from those sampler2D's are not the same? (cause if they are the same, the Box-Muller algorithm won't work).
Thanks so much for your help!
The type of the uniform is ìmage2D, not sampler2D. To load and store an image, you must bind the texture to an image unit using glBindImageTexture. See Image Load Store. e.g.:
glBindImageTexture(1, tex_noise, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F);
If you want to bind a texture to a texture unit you need to select active texture unit with glActiveTexture and then bind the texture with glBindTexture:
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, texture_object);
You can access this texture in the shader with a uniform of type sampler2D and the texture* functions:
layout(binding = 1) uniform sampler2D myTextue;
If you want to bind a texture to a image unit, you have to use glBindImageTexture:
glBindImageTexture(1, texture_object, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F);
You can access this texture in the shader with a uniform of type iamge2D and and the image* functions:
layout (binding = 1, rgba32f) writeonly uniform image2D myImage;

Issues writing to Framebuffer (Color attachments always black)

I'm trying to use a framebuffer as a Geometry Buffer for deferred shading. I'm having issues with writing and reading from the framebuffer's color attachments.
All I am trying to do is verify that my framebuffer's color attachments have some data. I do this by binding one of the color attachments and drawing a fullscreen quad. Each color attachment results in a fully black screen even though I've verified that my uniform variables are receiving the data they need.
My framebuffer is setup as follows:
glGenFramebuffers(1, &FBOID);
glBindFramebuffer(GL_FRAMEBUFFER, FBOID);
int WIDTH = windowDetails->width;
int HEIGHT = windowDetails->height;
glGenTextures(1, &gPosition);
glBindTexture(GL_TEXTURE_2D, gPosition);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, WIDTH, HEIGHT, 0, GL_RGBA, 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_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, gPosition, 0);
glGenTextures(1, &gAlbedo);
glBindTexture(GL_TEXTURE_2D, gAlbedo);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, WIDTH, HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, gAlbedo, 0);
glGenTextures(1, &gNormal);
glBindTexture(GL_TEXTURE_2D, gNormal);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, WIDTH, HEIGHT, 0, GL_RGBA, GL_FLOAT, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, gNormal, 0);
glGenTextures(1, &gEffects);
glBindTexture(GL_TEXTURE_2D, gEffects);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, WIDTH, HEIGHT, 0, GL_RGB, GL_FLOAT, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3, GL_TEXTURE_2D, gEffects, 0);
GLuint attachments[4] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3 };
glDrawBuffers(4, attachments);
glGenRenderbuffers(1, &zBuffer);
glBindRenderbuffer(GL_RENDERBUFFER, zBuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, WIDTH, HEIGHT);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, zBuffer);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
{
std::cout << "Framebuffer not complete !" << std::endl;
}
Every frame, I will bind this framebuffer and draw to it using my geometry shader. Then I will bind a test shader to check if the contents of the color attachements have some data by binding all of the color attachments to their own texture unit and passing one of them to the test shader:
glDisable(GL_BLEND); // No blend for deffered rendering
glEnable(GL_DEPTH_TEST); // Enable depth testing for scene render
glBindFramebuffer(GL_FRAMEBUFFER, FBOID); // Start drawing to FBO
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(gShader);
SubmittedGeometry& geometry = defferedGeometry[0];
glm::mat4 projViewModel = projection * view * geometry.transform;
glm::mat4& prevProjViewModel = prevProjViewModels.count(geometry.handle) <= 0 ? projViewModel : prevProjViewModels.at(geometry.handle);
prevProjViewModels.insert({ geometry.handle, projViewModel });
glUniformMatrix4fv(matModelLoc, geometry.transform);
glUniformMatrix4fv(matProjViewLoc, projViewModel);
glUniformMatrix4fv(matPrevProjeViewLoc, prevProjViewModel);
// Bind albedo textures
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, albedoTexID);
glUniform1i(albedoLoc, 0);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, normalTexID);
glUniform1i(normalLoc, 1);
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, roughnessTexID);
glUniform1i(rougnessLoc, 2);
glActiveTexture(GL_TEXTURE3);
glBindTexture(GL_TEXTURE_2D, metalnessTexID);
glUniform1i(metalnessLoc, 3);
glActiveTexture(GL_TEXTURE4);
glBindTexture(GL_TEXTURE_2D, aoTexID);
glUniform1i(aoLoc, 4);
glBindVertexArray(geometry.vaoID);
glDrawElements(GL_TRIANGLES, geometry.indices, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
glBindFramebuffer(GL_FRAMEBUFFER, 0); // Done drawing to FBO
// Test FBO color attachments
glUseProgram(testShaderID);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, gPosition);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, gAlbedo);
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, gNormal);
glActiveTexture(GL_TEXTURE3);
glBindTexture(GL_TEXTURE_2D, gEffects);
glUniform1i(testTextureLoc, 1);
quad->Draw();
Assigning the testTexture sampler with 0, 1, 2, or 3 all result in a black screen.
Geometry Shader:
VERTEX SHADER
#version 420
layout (location = 0) in vec3 vPosition;
layout (location = 1) in vec3 vNormal;
layout (location = 2) in vec2 vTextureCoordinates;
layout (location = 3) in vec3 vBiNormal;
layout (location = 4) in vec3 vTangent;
uniform mat4 uMatModel;
uniform mat4 uMatView;
uniform mat4 uMatProjection;
uniform mat4 uMatProjViewModel;
uniform mat4 uMatPrevProjViewModel;
out vec3 mViewPosition;
out vec2 mTextureCoordinates;
out vec3 mNormal;
out vec4 mFragPosition;
out vec4 mPrevFragPosition;
void main()
{
// Translate to view space
vec4 viewFragmentPosition = uMatView * uMatModel * vec4(vPosition, 1.0f);
mViewPosition = viewFragmentPosition.xyz;
mTextureCoordinates = vTextureCoordinates;
// Apply transformation to normal
mat3 matNormal = transpose(inverse(mat3(uMatView * uMatModel)));
mNormal = matNormal * vNormal;
mFragPosition = uMatProjViewModel * vec4(vPosition, 1.0f);
mPrevFragPosition = uMatPrevProjViewModel * vec4(vPosition, 1.0f);
gl_Position = uMatProjection * viewFragmentPosition;
};
FRAGMENT SHADER
#version 420
layout (location = 0) out vec4 gPosition;
layout (location = 1) out vec4 gAlbedo;
layout (location = 2) out vec4 gNormal;
layout (location = 3) out vec3 gEffects;
in vec3 mViewPosition;
in vec2 mTextureCoordinates;
in vec3 mNormal;
in vec4 mFragPosition;
in vec4 mPrevFragPosition;
uniform sampler2D uAlbedoTexture1;
uniform sampler2D uNormalTexture;
uniform sampler2D uRoughnessTexture;
uniform sampler2D uMetalnessTexture;
uniform sampler2D uAmbientOcculsionTexture;
const float nearPlane = 1.0f;
const float farPlane = 1000.0f;
float LinearizeDepth(float depth);
vec3 ComputeTextureNormal(vec3 viewNormal, vec3 textureNormal);
void main()
{
vec3 normal = normalize(texture(uNormalTexture, mTextureCoordinates).rgb * 2.0f - 1.0f); // Sample normal texture and convert values in range from -1.0 to 1.0
vec2 fragPos = (mFragPosition.xy / mFragPosition.w) * 0.5f + 0.5f;
vec2 prevFragPos = (mPrevFragPosition.xy / mPrevFragPosition.w) * 0.5f + 0.5f;
gPosition = vec4(mViewPosition, LinearizeDepth(gl_FragCoord.z)); // Set position with adjusted depth
gAlbedo.rgb = vec3(texture(uAlbedoTexture1, mTextureCoordinates)); // Sample and assign albedo rgb colors
gAlbedo.a = vec3(texture(uRoughnessTexture, mTextureCoordinates)).r; // Sample and assign roughness value
gNormal.rgb = ComputeTextureNormal(mNormal, normal); // Assign normal
gNormal.a = vec3(texture(uMetalnessTexture, mTextureCoordinates)).r; // Sample and assign metalness value
gEffects.r = vec3(texture(uAmbientOcculsionTexture, mTextureCoordinates)).r;
gEffects.gb = fragPos - prevFragPos;
}
float LinearizeDepth(float depth)
{
float z = depth * 2.0f - 1.0f;
return (2.0f * nearPlane * farPlane) / (farPlane + nearPlane - z * (farPlane - nearPlane));
}
vec3 ComputeTextureNormal(vec3 viewNormal, vec3 textureNormal)
{
// Get partial derivatives
vec3 dPosX = dFdx(mViewPosition);
vec3 dPosY = dFdy(mViewPosition);
vec2 dTexX = dFdx(mTextureCoordinates);
vec2 dTexY = dFdy(mTextureCoordinates);
// Convert normal to tangent space
vec3 normal = normalize(viewNormal);
vec3 tangent = normalize(dPosX * dTexY.t - dPosY * dTexX.t);
vec3 binormal = -normalize(cross(normal, tangent));
mat3 TBN = mat3(tangent, binormal, normal);
return normalize(TBN * textureNormal);
}
And my test shader code is:
VERTEX SHADER
#version 420
layout (location = 0) in vec3 vPosition;
layout (location = 1) in vec2 vTextureCoordinates;
out vec2 mTextureCoordinates;
void main()
{
mTextureCoordinates = vTextureCoordinates; // Pass out texture coords
gl_Position = vec4(vPosition, 1.0f);
};
FRAGMENT SHADER
#version 420
in vec2 mTextureCoordinates;
out vec4 oColor;
uniform sampler2D testTexture;
void main()
{
vec3 color = texture(testTexture, mTextureCoordinates).rgb;
oColor = vec4(color, 1.0f);
}
I've made sure that glCheckFramebufferStatus is always complete and that all of my uniform variables are being passed correctly in to the shader
Turns out my code here is correct. My issue was that I was crossing the wrong vectors so my camera's view matrix was wrong.

Texture colors replaced by purple tones

I try to display a texture on a quad but the colors was replaced by some purple.
The code is inspired from "learnopengl" website but I didn't find what I failed.
Here the shaders.
vertSrc:cstring = """
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aTexCoord;
out vec2 texCoord;
uniform mat4 projection;
void main()
{
gl_Position = projection * vec4(aPos, 1.0f);
texCoord = aTexCoord;
}
"""
fragSrc:cstring = """
#version 330 core
out vec4 FragColor;
in vec2 texCoord;
uniform sampler2D matTexture;
void main()
{
FragColor = texture(matTexture, texCoord);
}
"""
The opengl code for the texture.
glGenTextures(1, addr textureID)
glBindTexture(GL_TEXTURE_2D, textureID)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, texWidth, texHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, addr imageData[0])
glGenerateMipmap(GL_TEXTURE_2D)
The image loading thanks to the stb_image library.
var
textureID:OGLuint
texWidth:OGLint
texHeight:OGLint
channelCount:OGLint
imageData = stbi_load("Test/2d-rendering-test./stack.png", addr texWidth, addr texHeight, addr channelCount, 0)
And the opengl code in the main loop.
glBindTexture(GL_TEXTURE_2D, textureID)
If you are curious here a complete nim file who displays the issue.
https://bitbucket.org/Neotry/2d-rendering-test./src/master/WIPtest.nim
The Portable Network Graphics (PNG) file may contain 32-bit RGBA colors.
Force the stbi_load to generate an image with 4 color channels, by explicitly pass 4 to the last parameter:
imageData = stbi_load("Test/2d-rendering-test./stack.png",
addr texWidth, addr texHeight, addr channelCount, 4)
See stb_image.h:
Basic usage (see HDR discussion below for HDR usage):
int x,y,n;
unsigned char *data = stbi_load(filename, &x, &y, &n, 0);
// ... process data if not NULL ...
// ... x = width, y = height, n = # 8-bit components per pixel ...
// ... replace '0' with '1'..'4' to force that many components per pixel
// ... but 'n' will always be the number that it would have been if you said 0
stbi_image_free(data)
Finally the format parameter of glTexImage2D has to be GL_RGBA or GL_BGRA. For the internal format can be kept GL_RGB:
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, texWidth, texHeight, 0, GL_RGBA,
GL_UNSIGNED_BYTE, addr imageData[0])

Deferred Shading OpenGL implementation

I'm currently trying to implement deferred shading in OpenGL 3.2 and have a problem that I just can't seem to solve no matter what I try.
I implemented it in two steps(geometry pass and lighting pass) like one would expect. After compiling and running it the screen shows the scene I prepared almost like one would expect it to look like. The colors of the objects are correct and they are also positioned where and how I wanted them to be.
The thing is, that the light calculations seem to have no influence on the color, what so ever. After a lot of hours I found out, that the textures for the positions and normals seem to contain the same content like the color texture.
If one changes the last line in the lighting fragment shader from fragColor = lightIntensity * color; to fragColor = lightIntensity * norm; or fragColor = lightIntensity * pos; it has absolutely no impact on how the screen is rendered.
I have tried a lot to figure out what is going wrong but honestly have no idea what it could be.
It would be awesome if someone could help me.
My render method looks like this:
void render()
{
//geometry pass
gBuffer->bindForWriting();
geometryShader->use(true);
calculateGBuffer();
//lighting pass
gBuffer->bindForReading(lightShader->programID());
lightShader->use(true);
drawOnScreen();
}
The initialization of the gBuffer object is like this:
void GBuffer::initializeFBO(int viewWidth, int viewHeight)
{
//initialize fbo and corresponding textures;
glGenFramebuffers(1, &fbo_ID);
glBindFramebuffer(GL_FRAMEBUFFER, fbo_ID);
glGenTextures(1, &colorTexture_ID);
glBindTexture(GL_TEXTURE_2D, colorTexture_ID);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, viewWidth, viewHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTexture_ID, 0);
glGenTextures(1, &posTexture_ID);
glBindTexture(GL_TEXTURE_2D, posTexture_ID);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, viewWidth, viewHeight, 0, GL_RGB, GL_FLOAT, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, posTexture_ID, 0);
glGenTextures(1, &normTexture_ID);
glBindTexture(GL_TEXTURE_2D, normTexture_ID);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, viewWidth, viewHeight, 0, GL_RGB, GL_FLOAT, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, normTexture_ID, 0);
GLuint attachments[3] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2 };
glDrawBuffers(3, attachments);
glGenRenderbuffers(1, &depthBuffer_ID);
glBindRenderbuffer(GL_RENDERBUFFER, depthBuffer_ID);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, viewWidth, viewHeight);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthBuffer_ID);
//Check Status
if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
qDebug() << "error while initializing framebuffer" << glCheckFramebufferStatus(GL_FRAMEBUFFER);
else{
qDebug() << "framebuffer successfully created";
initialized = true;
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
The methods bindForReading and bindForWriting:
void GBuffer::bindForWriting()
{
glBindFramebuffer(GL_FRAMEBUFFER, fbo_ID);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
void GBuffer::bindForReading(GLuint programID)
{
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, colorTexture_ID);
GLuint samplerTexture_ID = glGetUniformLocation(programID, "colorTexture");
glUniform1i(samplerTexture_ID, 0);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, posTexture_ID);
samplerTexture_ID = glGetUniformLocation(programID, "positionTexture");
glUniform1i(samplerTexture_ID, 1);
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, normTexture_ID);
samplerTexture_ID = glGetUniformLocation(programID, "normTexture");
glUniform1i(samplerTexture_ID, 2);
}
And at last the 4 Shaders:
Geometry Vertex Shader:
#version 150
#extension GL_ARB_separate_shader_objects : enable
uniform mat4 MVPMatrix;
uniform mat4 modelMatrix;
in vec4 in_position;
in vec4 in_color;
in vec2 in_texcoord;
in vec3 in_norm;
out vec4 color_varying;
out vec3 frag_position;
out vec3 norm_vec;
out vec2 texcoord_varying;
void main()
{
gl_Position = MVPMatrix * in_position;
vec4 worldPosition = (modelMatrix * in_position);
frag_position = worldPosition.xyz;
norm_vec = in_norm;
color_varying = in_color;
texcoord_varying = in_texcoord;
}
Geometry Fragment Shader:
#version 150
#extension GL_ARB_explicit_attrib_location : enable
in vec4 color_varying;
in vec3 frag_position;
in vec3 norm_vec;
in vec2 texcoord_varying;
layout (location = 0) out vec4 fragColor;
layout (location = 1) out vec3 fragPosition;
layout (location = 2) out vec3 frag_norm_vec;
uniform sampler2D myTexture;
void main()
{
vec4 texel = texture(myTexture, texcoord_varying);
fragColor = texel * color_varying;
fragPosition = frag_position;
frag_norm_vec = normalize(norm_vec);
}
Lighting VertexShader:
#version 150
#extension GL_ARB_explicit_attrib_location : enable
layout (location = 0) in vec2 in_position;
out vec2 texCoord;
void main()
{
gl_Position = vec4(in_position, 0, 1.0f);
texCoord = in_position;
if(texCoord.x == -1.0f)
texCoord.x = 0.0f;
if(texCoord.y == -1.0f)
texCoord.y = 0.0f;
}
Lighting Fragment Shader(without lighting calculation to make it shorter)
#version 150
#extension GL_ARB_separate_shader_objects : enable
out vec4 fragColor;
in vec2 texCoord;
uniform sampler2D colorTexture;
uniform sampler2D positionTexture;
uniform sampler2D normTexture;
void main()
{
//extract fragment data from fbo
vec3 pos = texture(positionTexture, texCoord).rgb;
vec3 norm = texture(normTexture, texCoord).rgb;
vec4 color = texture(colorTexture, texCoord);
fragColor = lightIntensity * color;
}
Sry for the code spamming but I can't narrow down the error.
The problem is most likely in your order of operations here:
gBuffer->bindForReading(lightShader->programID());
lightShader->use(true);
where, in bindForReading(), you have calls like this one:
samplerTexture_ID = glGetUniformLocation(programID, "positionTexture");
glUniform1i(samplerTexture_ID, 1);
The glUniform*() calls set uniform values on the currently active program. Since you make the lightShader active after you make these calls, the uniform values will be set on the previously active program, which probably doesn't even have these uniforms.
Simply changing the order of these calls might already fix this:
lightShader->use(true);
gBuffer->bindForReading(lightShader->programID());
Also, you're using GL_RGB16F as the format of two of your buffers. The OpenGL implementation you use may support this, but this is not a format that is required to be color-renderable in the spec. If you want your code to work across platforms, you should use GL_RGBA16F, which is guaranteed to be color-renderable.

Pointlight Shadow Cube Mapping

So i managed to create shadow maps for a directional light (extended at infinity). Now i am trying to create point light shadow cube map, so the shadows spread in the direction of the light->fragment. I created a new FBO like so:
//gen new fbo
glGenFramebuffers(1, &framebuffer_object);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_object);
//gen color texture
glGenTextures(1, &texture_color);
glBindTexture(GL_TEXTURE_2D, texture_color);
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);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexImage2D(GL_TEXTURE_2D, 0,GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
//gen cubemap
glGenTextures(1, &shadow_cubemap);
glBindTexture(GL_TEXTURE_2D_ARRAY, shadow_cubemap);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_DEPTH_TEXTURE_MODE, GL_INTENSITY);
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, GL_DEPTH_COMPONENT, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0);
glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, GL_DEPTH_COMPONENT, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0);
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, GL_DEPTH_COMPONENT, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0);
glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, GL_DEPTH_COMPONENT, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0);
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, GL_DEPTH_COMPONENT, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0);
glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, GL_DEPTH_COMPONENT, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0);
//bind color texture
unsigned int attachment_index_color_texture = 0;
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0+attachment_index_color_texture, texture_color,0);
//add attachments
std::vector<GLenum> drawbuffers;
drawbuffers.push_back(GL_COLOR_ATTACHMENT0+attachment_index_color_texture);
glDrawBuffers(drawbuffers.size(),&drawbuffers[0]);
//check the fbo state
if(glCheckFramebufferStatus(GL_FRAMEBUFFER)!=GL_FRAMEBUFFER_COMPLETE){
std::cout<<"Error.FBO not integral."<<std::endl;
std::cin.get();
std::terminate();
}
//Unbind
glBindFramebuffer(GL_FRAMEBUFFER,0);
This function is called upon reshaping(so you could say at init time) reshape is called once at program start.
Next i create my light_view matrixes , each view for a different cube face, and my projection matrix like so :
//view matrix for +x
lightView_matrix[0]=glm::lookAt(light_position,light_position+glm::vec3(1,0,0),glm::vec3(0,1,0));
//view_matrix for -x
lightView_matrix[1]=glm::lookAt(light_position,light_position+glm::vec3(-1,0,0),glm::vec3(0,1,0));
//view_matrix for +z
lightView_matrix[2]=glm::lookAt(light_position,light_position+glm::vec3(0,0,1),glm::vec3(0,1,0));
//view_matrix for -z
lightView_matrix[3]=glm::lookAt(light_position,light_position+glm::vec3(0,0,-1),glm::vec3(0,1,0));
//view_matrix for +y
lightView_matrix[4]=glm::lookAt(light_position,light_position+glm::vec3(0,1,0),glm::vec3(0,0,-1));
//view_matrix for -y
lightView_matrix[5]=glm::lookAt(light_position,light_position+glm::vec3(0,-1,0),glm::vec3(0,0,1));
lightProjection_matrix = glm::perspective(90.0f, 1.0f, 0.5f, 140.0f);
Is the projection matrix ok? Should it be perspective when doing a cubemap instead of ortographic like i did for a directional light? I don't know if the values are ok : here is what i have, the width and height of the texture is 1366 x 768 which is my window size, my entire scene is from -70 to 70 on the z axis so 140 total,i chose a fov of pi/4 .
Moving on, to the first pass - hopefully generating the 6 faces of the cubemap:
cube_fbo.bind();
{
for(int i=0;i<6;i++){
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, cube_fbo.shadow_cubemap, 0);
//clear screen
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//use shader
glUseProgram(program_shader);
//send uniform values
glUniformMatrix4fv(glGetUniformLocation(program_shader,"light_view_matrix"),1,false,glm::value_ptr(lightView_matrix[i]));
glUniformMatrix4fv(glGetUniformLocation(program_shader,"light_projection_matrix"),1,false,glm::value_ptr(lightProjection_matrix));
//draw my objects with textures,i also have an alpha texture hence the has_alpha in the shaders (will post below )
}
}
//unbind fbo
cube_fbo.unbind();
Now the second pass which should draw the shadows based on the fragment position(should i do this in the drawing function or in the shader? )
{
//clear screen
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(program_shadow);
//send uniform values
glUniformMatrix4fv(glGetUniformLocation(program_shadow,"view_matrix"),1,false,glm::value_ptr(view_matrix));
glUniformMatrix4fv(glGetUniformLocation(program_shadow,"projection_matrix"),1,false,glm::value_ptr(projection_matrix));
glUniformMatrix4fv(glGetUniformLocation(program_shadow,"light_view_matrix"),1,false,glm::value_ptr(light_view_matrix));
glUniformMatrix4fv(glGetUniformLocation(program_shadow,"light_projection_matrix"),1,false,glm::value_ptr(light_projection_matrix));
glUniformMatrix4fv(glGetUniformLocation(program_shadow,"BiasMatrix"),1,false,glm::value_ptr(BiasMatrix));
glUniform3f(glGetUniformLocation(program_shadow,"light_position"),light_position.x,light_position.y,light_position.z);
//sphere at light position for reference------------------------
glUniformMatrix4fv(glGetUniformLocation(program_shadow,"model_matrix"),1,false,glm::value_ptr(light_model_matrix));
lab::drawSolidSphere(2,6,6);
//glEnable(GL_CULL_FACE);
//glCullFace(GL_BACK);
//ground----------------------------
glUniformMatrix4fv(glGetUniformLocation(program_shadow,"model_matrix"),1,false,glm::value_ptr(ground_model_matrix));
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, ground_texture);
glUniform1i( glGetUniformLocation(program_shadow, "textura1"), 1 );
glUniform1i( glGetUniformLocation(program_shadow, "has_alpha"), 0);
//glDisable(GL_CULL_FACE);
//send cubemap texture(GLuint bound in the first part (shadow_cubemap))
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_CUBE_MAP, cube_fbo[0].getCubeMapTexture());
glUniform1i(glGetUniformLocation(program_shadow, "textura_depth"), 2);
glBindVertexArray(ground_vao);
glDrawElements(GL_TRIANGLES, ground_num_indices, GL_UNSIGNED_INT, 0);
//bamboo(s)----------------------------
glActiveTexture(GL_TEXTURE0+1);
glBindTexture(GL_TEXTURE_2D, bamboo_texture_color);
glActiveTexture(GL_TEXTURE0+2);
glBindTexture(GL_TEXTURE_2D, bamboo_texture_alpha);
glUniform1i( glGetUniformLocation(program_shadow, "textura1"), 1 );
glUniform1i( glGetUniformLocation(program_shadow, "textura2"), 2 );
glUniform1i( glGetUniformLocation(program_shadow, "has_alpha"), 1);
//send cubemap texture
glActiveTexture(GL_TEXTURE3);
glBindTexture(GL_TEXTURE_2D, cube_fbo[0].getCubeMapTexture());
glUniform1i(glGetUniformLocation(program_shadow, "textura_depth"), 3);
glBindVertexArray(bamboo_vao);
for(int i=0;i<10;i++) for(int j=0;j<10;j++) {
if(j==5){
glUniformMatrix4fv(glGetUniformLocation(program_shadow,"model_matrix"),1,false,glm::value_ptr(bamboo_model_matrix[i*10+j]));
glDrawElements(GL_TRIANGLES, bamboo_num_indices, GL_UNSIGNED_INT, 0);
}
}
}
As you can see in this last part i draw from the camera position and pass to the shader the cubemap generate from the first pass. I have a few misunderstandings and probably some mistakes untill this point.
What do i return from the first pass (from the shader), when i did shadow mapping for a directional light i returned the depth (glFragcoord.z) but now i have to return a vec3 direction ? How do i compute that.Do i need something else to pass to the shader?
Is the second part ok ? Do i just draw the objects and pass the cube map to the shader and let him calculate which fragment is where in relation to the light ? If so , how do i compute this ?
Here is my shader for the first pass(so generate the cubemap from the 6 light views):
#version 330 /*VERTEX SHADER*\
layout(location = 0) in vec3 in_position;
layout(location = 2) in vec2 in_texcoord;
uniform mat4 model_matrix;
uniform mat4 light_view_matrix,light_projection_matrix;
out vec2 texcoord;
out vec4 v_position;
void main(){
texcoord = in_texcoord;
gl_Position = light_projection_matrix*light_view_matrix*model_matrix*vec4(in_position,1);
}
#version 330 /*FRAGMENT SHADER*\
layout(location = 0) out vec4 out_color;
//layout(location = 1) out float depth;
uniform sampler2D textura1;
uniform sampler2D textura2;
uniform int has_alpha;
in vec2 texcoord;
in vec4 v_position;
void main(){
vec3 tex1 = texture(textura1, texcoord).xyz;
vec3 tex2 = texture(textura2, texcoord).xyz;
if(has_alpha>0.5) if((tex2.r<0.1) && (tex2.g<0.1) && (tex2.b<0.1)) discard;
out_color = vec4(tex1, 1);
}
And the shader for the second pass (tried to calculate shadow by getting the vec3 from pixel position in world space - light position in world space)
#version 330 core /*VERTEX SHADER*\
layout(location = 0) in vec3 in_position;
layout(location = 1) in vec3 in_normal;
layout(location = 2) in vec2 in_texcoord;
out vec3 lightPosw;
out vec3 pixelPosw;
out vec2 texcoord;
uniform mat4 model_matrix,view_matrix,projection_matrix;
uniform vec3 light_position;
void main(){
texcoord=in_texcoord;
gl_Position = projection_matrix*view_matrix*model_matrix*vec4(in_position,1);
lightPosw= (model_matrix * vec4(light_position,1)).xyz;
pixelPosw = (model_matrix * vec4(in_position, 1)).xyz;
}
#version 330 core /*FRAGMENT SHADER*\
in vec3 lightPosw;
in vec3 pixelPosw;
in vec2 texcoord;
out vec4 out_color;
uniform samplerCube textura_depth;
uniform sampler2D textura1,textura2;
uniform mat4 view_matrix,model_matrix;
uniform int has_alpha;
void main(){
vec3 lightToPixel=pixelPosw-lightPosw;
vec3 tex1 = texture(textura1, texcoord).xyz;
vec3 tex2 = texture(textura2, texcoord).xyz;
if(has_alpha>0.5) if((tex2.r<0.1) && (tex2.g<0.1) && (tex2.b<0.1)) discard;
float shadowDepth = texture(textura_depth, normalize(lightToPixel));
float shadowFactor=1.0;
if(length(lightToPixel) < shadowDepth)
shadowFactor=0.5;
out_color = vec4(tex1*shadowFactor,1);
}
Sorry for the wall of code, i wanted to post all the relevant stuff so i can get better help. My problem is , everything renders semi-black, because i set the output color in the fragment shader to 0.5, if I wouldn't , then it all renders black.