I’m trying to implement image based lighting in my renderer, but when I try to (pre) render my irradiance map, the whole screen becomes black on startup. It works once and once it doesn’t.
The odd thing about it is that, everything works just fine when I just stream the original cube map into the irradiance map.
And the code’s below.
irradiance.glsl
@vertex
#version 330 core
layout(location=0)in vec3 aVertex;
out vec3 vFragPos;
uniform mat4 uViewMatrix;
uniform mat4 uProjectionMatrix;
void main() {
vFragPos = aVertex;
gl_Position = uProjectionMatrix * uViewMatrix * vec4(vFragPos, 1.0);
}
@fragment
#version 330 core
#define PI 3.14159265359
#define SAMPLE_COUNT 512u
in vec3 vFragPos;
layout(location=0)out vec3 oAlbedo;
uniform samplerCube uCubeMap;
uniform float uRoughness;
vec3 importanceSampleGGX(vec2 Xi, vec3 N, float roughness) {
float roughness2 = roughness * roughness;
float phi = 2.0 * PI * Xi.x;
float cosTheta = sqrt((1.0 - Xi.y) / (1.0 + (roughness2 * roughness2 - 1.0) * Xi.y));
float sinTheta = sqrt(1.0 - cosTheta * cosTheta);
vec3 H;
H.x = sinTheta * cos(phi);
H.y = sinTheta * sin(phi);
H.z = cosTheta;
vec3 up = abs(N.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0);
vec3 tangent = normalize(cross(up, N));
vec3 bitangent = cross(N, tangent);
return tangent * H.x + bitangent * H.y + N * H.z;
}
float radicalInverse_VdC(uint bits) {
bits = (bits << 16u) | (bits >> 16u);
bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u);
bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u);
bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u);
bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u);
return float(bits) * 2.3283064365386963e-10; // / 0x100000000
}
vec2 hammersley(uint i, uint N) {
return vec2(float(i) / float(N), radicalInverse_VdC(i));
}
void main() {
vec3 N = normalize(vFragPos);
vec4 irradiance = vec4(0.0);
for(uint sample=0u; sample<SAMPLE_COUNT; sample++) {
vec2 xi = hammersley(sample, SAMPLE_COUNT);
vec3 H = importanceSampleGGX(xi, N, uRoughness);
vec3 V = N;
vec3 L = normalize(2.0 * dot(V, H) * H - V);
float NdotL = max(0.0, dot(N, L));
if(NdotL > 0.0) {
irradiance.xyz += texture(uCubeMap, L).xyz * NdotL;
irradiance.w += NdotL;
}
}
irradiance.xyz /= irradiance.w;
oAlbedo = irradiance.xyz; //black screen at random
//oAlbedo = texture(uCubeMap, vFragPos).xyz; //works fine
}
IrradianceTexture.h
#include "../../resource/mesh/Mesh.h"
#include "../../resource/mesh/CubeMesh.h"
#include "../../resource/texture/CubeMapTexture.h"
#include "../../resource/Shader.h"
#include "../../util/Math.h"
#include "../../util/Matrix4.h"
#include "../../util/Vector3.h"
class IrradianceTexture : public CubeMapTexture {
public:
IrradianceTexture(CubeMapTexture *cubeMap, int quadSize) {
//CREATE CUBE
Mesh *cube = new CubeMesh(2, true);
cube->bind();
Shader *shader = new Shader("shaders/irradiance.glsl");
shader->bind();
Shader::setUniform(shader->getUniformLocation("uCubeMap"), 0);
Shader::setUniform(shader->getUniformLocation("uProjectionMatrix"), Matrix4::perspective(90, 1, 0.1, 10));
int viewMatrixLocation = shader->getUniformLocation("uViewMatrix");
int roughnessLocation = shader->getUniformLocation("uRoughness");
//CREATE FRAMEBUFFER AND THE CUBEMAP
unsigned int framebuffer;
glGenFramebuffers(1, &framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
glBindTexture(GL_TEXTURE_CUBE_MAP, texture);
for(unsigned int i=0; i<6; i++) {
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB16F, quadSize, quadSize, 0, GL_RGB, GL_FLOAT, nullptr);
}
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
//RENDER THE CUBEMAP
Matrix4 viewMatrices[6] = {
Matrix4::transform(Vector3(0), Vector3( 0, -90, 180), Vector3(1)),
Matrix4::transform(Vector3(0), Vector3( 0, 90, 180), Vector3(1)),
Matrix4::transform(Vector3(0), Vector3(-90, 0, 0), Vector3(1)),
Matrix4::transform(Vector3(0), Vector3( 90, 0, 0), Vector3(1)),
Matrix4::transform(Vector3(0), Vector3( 0, 180, 180), Vector3(1)),
Matrix4::transform(Vector3(0), Vector3( 0, 0, 180), Vector3(1))
};
glDisable(GL_DEPTH_TEST);
glDisable(GL_BLEND);
glDisable(GL_CULL_FACE);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
glActiveTexture(GL_TEXTURE0);
cubeMap->bind();
unsigned int mipmapLevels = 5;
for(unsigned int level=0; level<mipmapLevels; level++) {
glViewport(0, 0, quadSize*Math::pow(0.5, level), quadSize*Math::pow(0.5, level));
Shader::setUniform(roughnessLocation, (float)level / (mipmapLevels - 1));
for(unsigned int i=0; i<6; i++) {
Shader::setUniform(viewMatrixLocation, viewMatrices[i]);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, texture, level);
glDrawElements(GL_TRIANGLES, cube->getIndexCount(), GL_UNSIGNED_INT, 0);
}
}
//CLEAN UP
delete cube;
delete shader;
glDeleteFramebuffers(1, &framebuffer);
}
};
I just want to add that, I’ll use IBL specular irradiance map mipmap level 4 as diffuse irradiance map, so I won’t have to render same texture again.