diff --git a/assets/shaders/background_fragment.glsl b/assets/shaders/background_fragment.glsl index 8fe56f9..61b6c44 100644 --- a/assets/shaders/background_fragment.glsl +++ b/assets/shaders/background_fragment.glsl @@ -7,10 +7,10 @@ uniform samplerCube environmentMap; void main() { vec3 envColor = texture(environmentMap, WorldPos).rgb; - - // HDR tonemap and gamma correct - envColor = envColor / (envColor + vec3(1.0)); - envColor = pow(envColor, vec3(1.0/2.2)); - - FragColor = vec4(envColor, 1.0); + + // HDR tonemap and gamma correct + envColor = envColor / (envColor + vec3(1.0)); + envColor = pow(envColor, vec3(1.0/2.2)); + + FragColor = vec4(envColor, 1.0); } \ No newline at end of file diff --git a/assets/shaders/background_vertex.glsl b/assets/shaders/background_vertex.glsl index bd8346b..03e5e1a 100644 --- a/assets/shaders/background_vertex.glsl +++ b/assets/shaders/background_vertex.glsl @@ -8,7 +8,7 @@ out vec3 WorldPos; void main() { - WorldPos = aPos; + WorldPos = aPos; mat4 rotView = mat4(mat3(view)); vec4 clipPos = projection * rotView * vec4(WorldPos, 1.0); diff --git a/assets/shaders/brdf_fragment.glsl b/assets/shaders/brdf_fragment.glsl index 7f3c680..7e4b52f 100644 --- a/assets/shaders/brdf_fragment.glsl +++ b/assets/shaders/brdf_fragment.glsl @@ -3,24 +3,24 @@ out vec2 FragColor; in vec2 TexCoords; const float PI = 3.14159265359; -// ---------------------------------------------------------------------------- + // http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html // efficient VanDerCorpus calculation. 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 + 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)); } -// ---------------------------------------------------------------------------- + vec3 ImportanceSampleGGX(vec2 Xi, vec3 N, float roughness) { float a = roughness*roughness; @@ -36,78 +36,78 @@ vec3 ImportanceSampleGGX(vec2 Xi, vec3 N, float roughness) H.z = cosTheta; // from tangent-space H vector to world-space sample vector - vec3 up = abs(N.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0); + 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); vec3 sampleVec = tangent * H.x + bitangent * H.y + N * H.z; return normalize(sampleVec); } -// ---------------------------------------------------------------------------- + float GeometrySchlickGGX(float NdotV, float roughness) { - // note that we use a different k for IBL - float a = roughness; - float k = (a * a) / 2.0; + // note that we use a different k for IBL + float a = roughness; + float k = (a * a) / 2.0; - float nom = NdotV; - float denom = NdotV * (1.0 - k) + k; + float nom = NdotV; + float denom = NdotV * (1.0 - k) + k; - return nom / denom; + return nom / denom; } -// ---------------------------------------------------------------------------- + float GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness) { - float NdotV = max(dot(N, V), 0.0); - float NdotL = max(dot(N, L), 0.0); - float ggx2 = GeometrySchlickGGX(NdotV, roughness); - float ggx1 = GeometrySchlickGGX(NdotL, roughness); + float NdotV = max(dot(N, V), 0.0); + float NdotL = max(dot(N, L), 0.0); + float ggx2 = GeometrySchlickGGX(NdotV, roughness); + float ggx1 = GeometrySchlickGGX(NdotL, roughness); - return ggx1 * ggx2; + return ggx1 * ggx2; } -// ---------------------------------------------------------------------------- + vec2 IntegrateBRDF(float NdotV, float roughness) { - vec3 V; - V.x = sqrt(1.0 - NdotV*NdotV); - V.y = 0.0; - V.z = NdotV; + vec3 V; + V.x = sqrt(1.0 - NdotV*NdotV); + V.y = 0.0; + V.z = NdotV; - float A = 0.0; - float B = 0.0; + float A = 0.0; + float B = 0.0; - vec3 N = vec3(0.0, 0.0, 1.0); - - const uint SAMPLE_COUNT = 1024u; - for(uint i = 0u; i < SAMPLE_COUNT; ++i) - { - // generates a sample vector that's biased towards the - // preferred alignment direction (importance sampling). - vec2 Xi = Hammersley(i, SAMPLE_COUNT); - vec3 H = ImportanceSampleGGX(Xi, N, roughness); - vec3 L = normalize(2.0 * dot(V, H) * H - V); + vec3 N = vec3(0.0, 0.0, 1.0); - float NdotL = max(L.z, 0.0); - float NdotH = max(H.z, 0.0); - float VdotH = max(dot(V, H), 0.0); + const uint SAMPLE_COUNT = 1024u; + for(uint i = 0u; i < SAMPLE_COUNT; ++i) { - if(NdotL > 0.0) - { - float G = GeometrySmith(N, V, L, roughness); - float G_Vis = (G * VdotH) / (NdotH * NdotV); - float Fc = pow(1.0 - VdotH, 5.0); + // generates a sample vector that's biased towards the + // preferred alignment direction (importance sampling). + vec2 Xi = Hammersley(i, SAMPLE_COUNT); + vec3 H = ImportanceSampleGGX(Xi, N, roughness); + vec3 L = normalize(2.0 * dot(V, H) * H - V); - A += (1.0 - Fc) * G_Vis; - B += Fc * G_Vis; - } - } - A /= float(SAMPLE_COUNT); - B /= float(SAMPLE_COUNT); - return vec2(A, B); + float NdotL = max(L.z, 0.0); + float NdotH = max(H.z, 0.0); + float VdotH = max(dot(V, H), 0.0); + + if(NdotL > 0.0) { + + float G = GeometrySmith(N, V, L, roughness); + float G_Vis = (G * VdotH) / (NdotH * NdotV); + float Fc = pow(1.0 - VdotH, 5.0); + + A += (1.0 - Fc) * G_Vis; + B += Fc * G_Vis; + } + } + A /= float(SAMPLE_COUNT); + B /= float(SAMPLE_COUNT); + return vec2(A, B); } -// ---------------------------------------------------------------------------- + void main() { - vec2 integratedBRDF = IntegrateBRDF(TexCoords.x, TexCoords.y); - FragColor = integratedBRDF; + vec2 integratedBRDF = IntegrateBRDF(TexCoords.x, TexCoords.y); + FragColor = integratedBRDF; } \ No newline at end of file diff --git a/assets/shaders/brdf_vertex.glsl b/assets/shaders/brdf_vertex.glsl index 915f836..5596582 100644 --- a/assets/shaders/brdf_vertex.glsl +++ b/assets/shaders/brdf_vertex.glsl @@ -1,4 +1,5 @@ #version 330 core + layout (location = 0) in vec3 aPos; layout (location = 1) in vec2 aTexCoords; diff --git a/assets/shaders/cubemap_vertex.glsl b/assets/shaders/cubemap_vertex.glsl index a022916..f701e07 100644 --- a/assets/shaders/cubemap_vertex.glsl +++ b/assets/shaders/cubemap_vertex.glsl @@ -1,4 +1,5 @@ #version 330 core + layout (location = 0) in vec3 aPos; out vec3 WorldPos; diff --git a/assets/shaders/equirectangular_to_cubemap_fragment.glsl b/assets/shaders/equirectangular_to_cubemap_fragment.glsl index f399b59..29dc8b8 100644 --- a/assets/shaders/equirectangular_to_cubemap_fragment.glsl +++ b/assets/shaders/equirectangular_to_cubemap_fragment.glsl @@ -1,31 +1,33 @@ #version 330 core + out vec4 FragColor; -in vec3 WorldPos; +in vec3 WorldPos; uniform sampler2D equirectangularMap; const vec2 invAtan = vec2(0.1591, 0.3183); + vec2 SampleSphericalMap(vec3 v) { - vec2 uv = vec2(atan(v.z, v.x), asin(v.y)); - uv *= invAtan; - uv += 0.5; - return uv; + vec2 uv = vec2(atan(v.z, v.x), asin(v.y)); + uv *= invAtan; + uv += 0.5; + return uv; } void main() -{ - vec2 uv = SampleSphericalMap(normalize(WorldPos)); - vec3 color = texture(equirectangularMap, uv).rgb; +{ + vec2 uv = SampleSphericalMap(normalize(WorldPos)); + vec3 color = texture(equirectangularMap, uv).rgb; // reinhard tone mapping - vec3 mapped = color / (color + vec3(1.0)); + vec3 mapped = color / (color + vec3(1.0)); - // gamma correction + // gamma correction //float gamma = 2.2; - //mapped = pow(mapped, vec3(1.0 / gamma)); - + //mapped = pow(mapped, vec3(1.0 / gamma)); + color = mapped; - FragColor = vec4(color, 1.0); + FragColor = vec4(color, 1.0); } \ No newline at end of file diff --git a/assets/shaders/fragment.glsl b/assets/shaders/fragment.glsl index 00f72fa..4877010 100644 --- a/assets/shaders/fragment.glsl +++ b/assets/shaders/fragment.glsl @@ -29,66 +29,66 @@ uniform sampler2D brdfLUT; float shadow_factor(vec4 frag_pos_light_space); float distribGGX(float NoH, float a) { - float a2 = a * a; - float f = (NoH * a2 - NoH) * NoH + 1.0; - return a2 / (PI * f * f); + float a2 = a * a; + float f = (NoH * a2 - NoH) * NoH + 1.0; + return a2 / (PI * f * f); } vec3 fresnelSchlick(float u, vec3 f0) { - return f0 + (vec3(1.0) - f0) * pow(1.0 - u, 5.0); + return f0 + (vec3(1.0) - f0) * pow(1.0 - u, 5.0); } vec3 fresnelSchlickRoughness(float cosTheta, vec3 F0, float roughness) { - return F0 + (max(vec3(1.0 - roughness), F0) - F0) * pow(clamp(1.0 - cosTheta, 0.0, 1.0), 5.0); -} + return F0 + (max(vec3(1.0 - roughness), F0) - F0) * pow(clamp(1.0 - cosTheta, 0.0, 1.0), 5.0); +} float geometrySmith(float NoV, float NoL, float a) { - float a2 = a * a; - float GGXL = NoV * sqrt((-NoL * a2 + NoL) * NoL + a2); - float GGXV = NoL * sqrt((-NoV * a2 + NoV) * NoV + a2); - return 0.5 / (GGXV + GGXL); + float a2 = a * a; + float GGXL = NoV * sqrt((-NoL * a2 + NoL) * NoL + a2); + float GGXV = NoL * sqrt((-NoV * a2 + NoV) * NoV + a2); + return 0.5 / (GGXV + GGXL); } void main() { - vec3 l = normalize(lightDir); - vec3 v = normalize(viewPos - fragPos); - vec3 n = frag_normal; - vec3 h = normalize(v + l); + vec3 l = normalize(lightDir); + vec3 v = normalize(viewPos - fragPos); + vec3 n = frag_normal; + vec3 h = normalize(v + l); - float light_intensity = 1; + float light_intensity = 1; - float perceptualRoughness2 = max(perceptualRoughness, 0.089); - float roughness = perceptualRoughness2 * perceptualRoughness2; + float perceptualRoughness2 = max(perceptualRoughness, 0.089); + float roughness = perceptualRoughness2 * perceptualRoughness2; - vec3 f0 = 0.16 * reflectance * reflectance * (1.0 - metallic) + baseColor * metallic; + vec3 f0 = 0.16 * reflectance * reflectance * (1.0 - metallic) + baseColor * metallic; - float NoV = abs(dot(n, v)) + 1e-5; - float NoL = clamp(dot(n, l), 0.0, 1.0); - float NoH = clamp(dot(n, h), 0.0, 1.0); - float LoH = clamp(dot(l, h), 0.0, 1.0); + float NoV = abs(dot(n, v)) + 1e-5; + float NoL = clamp(dot(n, l), 0.0, 1.0); + float NoH = clamp(dot(n, h), 0.0, 1.0); + float LoH = clamp(dot(l, h), 0.0, 1.0); - vec3 color = vec3(0); + vec3 color = vec3(0); float shadow = shadow_factor(frag_pos_light_space); - // Direct lighting - { - float D = distribGGX(NoH, roughness); - vec3 F = fresnelSchlick(LoH, f0); - float V = geometrySmith(NoV, NoL, roughness); + // Direct lighting + { + float D = distribGGX(NoH, roughness); + vec3 F = fresnelSchlick(LoH, f0); + float V = geometrySmith(NoV, NoL, roughness); - vec3 specular = (F * D * V) / (4.0 * NoV * NoL + 0.0001); + vec3 specular = (F * D * V) / (4.0 * NoV * NoL + 0.0001); - vec3 diffuse = (1 - F) * (1 - metallic) * baseColor / PI; + vec3 diffuse = (1 - F) * (1 - metallic) * baseColor / PI; - color = (1 - shadow) * (diffuse + specular) * lightColor * light_intensity * NoL; - } + color = (1 - shadow) * (diffuse + specular) * lightColor * light_intensity * NoL; + } - // Ambient lighting with IBL + // Ambient lighting with IBL vec3 ambient; - { + { vec3 F = fresnelSchlickRoughness(NoV, f0, roughness); vec3 irradiance = texture(irradianceMap, n).rgb; @@ -105,32 +105,33 @@ void main() float ao = 1; ambient = ((1 - F) * (1 - metallic) * diffuse + specular) * ao; - } + } color = color + ambient; - color = color / (color + vec3(1.0)); // HDR tonemapping - color = pow(color, vec3(1.0/2.2)); // gamma correct + color = color / (color + vec3(1.0)); // HDR tonemapping + color = pow(color, vec3(1.0/2.2)); // gamma correct - FragColor = vec4(color, 1.0); + FragColor = vec4(color, 1.0); } float shadow_factor(vec4 frag_pos_light_space) { - vec3 proj_coords = frag_pos_light_space.xyz / frag_pos_light_space.w; - proj_coords = proj_coords * 0.5 + 0.5; + vec3 proj_coords = frag_pos_light_space.xyz / frag_pos_light_space.w; + proj_coords = proj_coords * 0.5 + 0.5; - float closest_depth = texture(shadow_map, proj_coords.xy).r; - float current_depth = proj_coords.z; + float closest_depth = texture(shadow_map, proj_coords.xy).r; + float current_depth = proj_coords.z; - float bias = 0.005; - float shadow = 0; - vec2 delta = 1.0 / textureSize(shadow_map, 0); - for (int i = -1; i < 2; i++) - for (int j = -1; j < 2; j++) { - float closest_depth = texture(shadow_map, proj_coords.xy + vec2(i, j) * delta).r; - shadow += (current_depth - bias > closest_depth) ? 1.0 : 0.0; - } - shadow /= 9; - return shadow; + float bias = 0.005; + float shadow = 0; + vec2 delta = 1.0 / textureSize(shadow_map, 0); + for (int i = -1; i < 2; i++) + for (int j = -1; j < 2; j++) { + float closest_depth = texture(shadow_map, proj_coords.xy + vec2(i, j) * delta).r; + shadow += (current_depth - bias > closest_depth) ? 1.0 : 0.0; + } + + shadow /= 9; + return shadow; } \ No newline at end of file diff --git a/assets/shaders/fragment_temp.glsl b/assets/shaders/fragment_temp.glsl deleted file mode 100644 index e4bd242..0000000 --- a/assets/shaders/fragment_temp.glsl +++ /dev/null @@ -1,105 +0,0 @@ -#version 330 core - -struct Light { - vec3 direction; - vec3 ambient; - vec3 diffuse; - vec3 specular; -}; - -out vec4 FragColor; - -in vec3 frag_normal; -in vec3 fragPos; -in vec4 frag_pos_light_space; - -uniform sampler2D shadow_map; -uniform vec3 viewPos; - -uniform float perceptualRoughness; // [0, 1] -uniform float metallic; // [0, 1] -uniform float reflectance; // [0, 1] -uniform vec3 baseColor; - -uniform Light light; - -float shadow_factor(vec4 frag_pos_light_space) -{ - vec3 proj_coords = frag_pos_light_space.xyz / frag_pos_light_space.w; - proj_coords = proj_coords * 0.5 + 0.5; - - float closest_depth = texture(shadow_map, proj_coords.xy).r; - float current_depth = proj_coords.z; - - float bias = 0.005; - float shadow = 0; - vec2 delta = 1.0 / textureSize(shadow_map, 0); - for (int i = -1; i < 2; i++) - for (int j = -1; j < 2; j++) { - float closest_depth = texture(shadow_map, proj_coords.xy + vec2(i, j) * delta).r; - shadow += (current_depth - bias > closest_depth) ? 1.0 : 0.0; - } - shadow /= 9; - return shadow; -} - -float D_GGX(float NoH, float a) { - float a2 = a * a; - float f = (NoH * a2 - NoH) * NoH + 1.0; - return a2 / (PI * f * f); -} - -vec3 F_Schlick(float u, vec3 f0) { - return f0 + (vec3(1.0) - f0) * pow(1.0 - u, 5.0); -} - -float V_SmithGGXCorrelated(float NoV, float NoL, float a) { - float a2 = a * a; - float GGXL = NoV * sqrt((-NoL * a2 + NoL) * NoL + a2); - float GGXV = NoL * sqrt((-NoV * a2 + NoV) * NoV + a2); - return 0.5 / (GGXV + GGXL); -} - -float Fd_Lambert() { - return 1.0 / PI; -} - -void main() -{ - // NOTE: frag_normal is normalized by the vertex shader -/* - vec3 l = normalize(light.direction); - vec3 v = viewDir; - vec3 n = frag_normal; - vec3 h = normalize(v + l); - vec3 diffuseColor = (1.0 - metallic) * baseColor.rgb; - vec3 f0 = 0.16 * reflectance * reflectance * (1.0 - metallic) + baseColor * metallic; - - float NoV = abs(dot(n, v)) + 1e-5; - float NoL = clamp(dot(n, l), 0.0, 1.0); - float NoH = clamp(dot(n, h), 0.0, 1.0); - float LoH = clamp(dot(l, h), 0.0, 1.0); - - float roughness = perceptualRoughness * perceptualRoughness; - - float D = D_GGX(NoH, roughness); - vec3 F = F_Schlick(LoH, f0); - float V = V_SmithGGXCorrelated(NoV, NoL, roughness); - - // specular BRDF - vec3 Fr = (D * V) * F; - - //vec3 energyCompensation = 1.0 + f0 * (1.0 / dfg.y - 1.0); - //// Scale the specular lobe to account for multiscattering - //Fr *= pixel.energyCompensation; - - // diffuse BRDF - vec3 Fd = diffuseColor * Fd_Lambert(); - - // apply lighting... - - float shadow = shadow_factor(frag_pos_light_space); -*/ - vec3 result = vec3(1, 0, 0); // Fd + Fr * (1 - shadow); - FragColor = vec4(result, 1.0); -} diff --git a/assets/shaders/fragment_temp_2.glsl b/assets/shaders/fragment_temp_2.glsl deleted file mode 100644 index cca6958..0000000 --- a/assets/shaders/fragment_temp_2.glsl +++ /dev/null @@ -1,113 +0,0 @@ -#version 330 core - -// https://github.com/Nadrin/PBR/blob/master/data/shaders/glsl/pbr_fs.glsl - -#define PI 3.1415926538 - -out vec4 FragColor; - -in vec3 frag_normal; -in vec3 fragPos; -in vec4 frag_pos_light_space; - -uniform sampler2D shadow_map; -uniform vec3 viewPos; - -uniform float perceptualRoughness; // [0, 1] -uniform float metallic; // [0, 1] -uniform float reflectance; // [0, 1] -uniform vec3 baseColor; - -uniform vec3 lightDir; -uniform vec3 lightColor; - -float shadow_factor(vec4 frag_pos_light_space); - -float D_GGX(float NoH, float a) { - float a2 = a * a; - float f = (NoH * a2 - NoH) * NoH + 1.0; - return a2 / (PI * f * f); -} - -vec3 F_Schlick(float u, vec3 f0) { - return f0 + (vec3(1.0) - f0) * pow(1.0 - u, 5.0); -} - -float V_SmithGGXCorrelated(float NoV, float NoL, float a) { - float a2 = a * a; - float GGXL = NoV * sqrt((-NoL * a2 + NoL) * NoL + a2); - float GGXV = NoL * sqrt((-NoV * a2 + NoV) * NoV + a2); - return 0.5 / (GGXV + GGXL); -} - -float Fd_Lambert() -{ - return 1.0 / PI; -} - -void main() -{ - vec3 l = normalize(lightDir); - vec3 v = normalize(viewPos - fragPos); - vec3 n = frag_normal; - vec3 h = normalize(v + l); - - float light_intensity = 1; - - vec3 albedo = baseColor; - vec3 diffuseColor = (1.0 - metallic) * baseColor; - - vec3 f0 = 0.16 * reflectance * reflectance * (1.0 - metallic) - + baseColor * metallic; - - float NoV = abs(dot(n, v)) + 1e-5; - float NoL = clamp(dot(n, l), 0.0, 1.0); - float NoH = clamp(dot(n, h), 0.0, 1.0); - float LoH = clamp(dot(l, h), 0.0, 1.0); - - float roughness = perceptualRoughness * perceptualRoughness; - - float D = D_GGX(NoH, roughness); - vec3 F = F_Schlick(LoH, f0); - float V = V_SmithGGXCorrelated(NoV, NoL, roughness); - - // specular BRDF - float denominator = 4.0 * max(dot(n, v), 0.0) * max(dot(n, l), 0.0) + 0.0001; // + 0.0001 to prevent divide by zero - vec3 Fr = (D * V) * F / denominator; - - vec3 radiance = lightColor; - vec3 light = ((vec3(1.0) - F) * (1.0 - metallic) * albedo / PI + Fr) * radiance * NoL; - - float shadow = shadow_factor(frag_pos_light_space); - - vec3 ambient = vec3(0.03) * albedo; - vec3 color = (ambient + light) * (1 - shadow); - -/* - // HDR tonemapping - color = color / (color + vec3(1.0)); - // gamma correct - color = pow(color, vec3(1.0/2.2)); -*/ - FragColor = vec4(color, 1.0); -} - -float shadow_factor(vec4 frag_pos_light_space) -{ - vec3 proj_coords = frag_pos_light_space.xyz / frag_pos_light_space.w; - proj_coords = proj_coords * 0.5 + 0.5; - - float closest_depth = texture(shadow_map, proj_coords.xy).r; - float current_depth = proj_coords.z; - - float bias = 0.005; - float shadow = 0; - vec2 delta = 1.0 / textureSize(shadow_map, 0); - for (int i = -1; i < 2; i++) - for (int j = -1; j < 2; j++) { - float closest_depth = texture(shadow_map, proj_coords.xy + vec2(i, j) * delta).r; - shadow += (current_depth - bias > closest_depth) ? 1.0 : 0.0; - } - shadow /= 9; - return shadow; -} \ No newline at end of file diff --git a/assets/shaders/irradiance_convolution_fragment.glsl b/assets/shaders/irradiance_convolution_fragment.glsl index ab80a56..cdc3909 100644 --- a/assets/shaders/irradiance_convolution_fragment.glsl +++ b/assets/shaders/irradiance_convolution_fragment.glsl @@ -7,37 +7,37 @@ uniform samplerCube environmentMap; const float PI = 3.14159265359; void main() -{ +{ // The world vector acts as the normal of a tangent surface - // from the origin, aligned to WorldPos. Given this normal, calculate all - // incoming radiance of the environment. The result of this radiance - // is the radiance of light coming from -Normal direction, which is what - // we use in the PBR shader to sample irradiance. - vec3 N = normalize(WorldPos); + // from the origin, aligned to WorldPos. Given this normal, calculate all + // incoming radiance of the environment. The result of this radiance + // is the radiance of light coming from -Normal direction, which is what + // we use in the PBR shader to sample irradiance. + vec3 N = normalize(WorldPos); - vec3 irradiance = vec3(0.0); - - // tangent space calculation from origin point - vec3 up = vec3(0.0, 1.0, 0.0); - vec3 right = normalize(cross(up, N)); - up = normalize(cross(N, right)); - - float sampleDelta = 0.025; - float nrSamples = 0.0; - for(float phi = 0.0; phi < 2.0 * PI; phi += sampleDelta) - { - for(float theta = 0.0; theta < 0.5 * PI; theta += sampleDelta) - { - // spherical to cartesian (in tangent space) - vec3 tangentSample = vec3(sin(theta) * cos(phi), sin(theta) * sin(phi), cos(theta)); - // tangent space to world - vec3 sampleVec = tangentSample.x * right + tangentSample.y * up + tangentSample.z * N; + vec3 irradiance = vec3(0.0); - irradiance += texture(environmentMap, sampleVec).rgb * cos(theta) * sin(theta); - nrSamples++; - } - } - irradiance = PI * irradiance * (1.0 / float(nrSamples)); - - FragColor = vec4(irradiance, 1.0); + // tangent space calculation from origin point + vec3 up = vec3(0.0, 1.0, 0.0); + vec3 right = normalize(cross(up, N)); + up = normalize(cross(N, right)); + + float sampleDelta = 0.025; + float nrSamples = 0.0; + for(float phi = 0.0; phi < 2.0 * PI; phi += sampleDelta) + { + for(float theta = 0.0; theta < 0.5 * PI; theta += sampleDelta) + { + // spherical to cartesian (in tangent space) + vec3 tangentSample = vec3(sin(theta) * cos(phi), sin(theta) * sin(phi), cos(theta)); + // tangent space to world + vec3 sampleVec = tangentSample.x * right + tangentSample.y * up + tangentSample.z * N; + + irradiance += texture(environmentMap, sampleVec).rgb * cos(theta) * sin(theta); + nrSamples++; + } + } + irradiance = PI * irradiance * (1.0 / float(nrSamples)); + + FragColor = vec4(irradiance, 1.0); } \ No newline at end of file diff --git a/assets/shaders/prefilter_fragment.glsl b/assets/shaders/prefilter_fragment.glsl index 2cb466c..b88d1c0 100644 --- a/assets/shaders/prefilter_fragment.glsl +++ b/assets/shaders/prefilter_fragment.glsl @@ -6,101 +6,101 @@ uniform samplerCube environmentMap; uniform float roughness; const float PI = 3.14159265359; -// ---------------------------------------------------------------------------- + float DistributionGGX(vec3 N, vec3 H, float roughness) { - float a = roughness*roughness; - float a2 = a*a; - float NdotH = max(dot(N, H), 0.0); - float NdotH2 = NdotH*NdotH; + float a = roughness*roughness; + float a2 = a*a; + float NdotH = max(dot(N, H), 0.0); + float NdotH2 = NdotH*NdotH; - float nom = a2; - float denom = (NdotH2 * (a2 - 1.0) + 1.0); - denom = PI * denom * denom; + float nom = a2; + float denom = (NdotH2 * (a2 - 1.0) + 1.0); + denom = PI * denom * denom; - return nom / denom; + return nom / denom; } -// ---------------------------------------------------------------------------- + // http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html // efficient VanDerCorpus calculation. 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 + 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)); } -// ---------------------------------------------------------------------------- + vec3 ImportanceSampleGGX(vec2 Xi, vec3 N, float roughness) { float a = roughness*roughness; - + float phi = 2.0 * PI * Xi.x; float cosTheta = sqrt((1.0 - Xi.y) / (1.0 + (a*a - 1.0) * Xi.y)); float sinTheta = sqrt(1.0 - cosTheta*cosTheta); - + // from spherical coordinates to cartesian coordinates - halfway vector vec3 H; H.x = cos(phi) * sinTheta; H.y = sin(phi) * sinTheta; H.z = cosTheta; - + // from tangent-space H vector to world-space sample vector 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); - + vec3 sampleVec = tangent * H.x + bitangent * H.y + N * H.z; return normalize(sampleVec); } -// ---------------------------------------------------------------------------- + void main() -{ - vec3 N = normalize(WorldPos); - - // make the simplifying assumption that V equals R equals the normal - vec3 R = N; - vec3 V = R; +{ + vec3 N = normalize(WorldPos); - const uint SAMPLE_COUNT = 1024u; - vec3 prefilteredColor = vec3(0.0); - float totalWeight = 0.0; - - for(uint i = 0u; i < SAMPLE_COUNT; ++i) - { - // generates a sample vector that's biased towards the preferred alignment direction (importance sampling). - vec2 Xi = Hammersley(i, SAMPLE_COUNT); - vec3 H = ImportanceSampleGGX(Xi, N, roughness); - vec3 L = normalize(2.0 * dot(V, H) * H - V); + // make the simplifying assumption that V equals R equals the normal + vec3 R = N; + vec3 V = R; - float NdotL = max(dot(N, L), 0.0); - if(NdotL > 0.0) - { - // sample from the environment's mip level based on roughness/pdf - float D = DistributionGGX(N, H, roughness); - float NdotH = max(dot(N, H), 0.0); - float HdotV = max(dot(H, V), 0.0); - float pdf = D * NdotH / (4.0 * HdotV) + 0.0001; + const uint SAMPLE_COUNT = 1024u; + vec3 prefilteredColor = vec3(0.0); + float totalWeight = 0.0; - float resolution = 512.0; // resolution of source cubemap (per face) - float saTexel = 4.0 * PI / (6.0 * resolution * resolution); - float saSample = 1.0 / (float(SAMPLE_COUNT) * pdf + 0.0001); + for(uint i = 0u; i < SAMPLE_COUNT; ++i) + { + // generates a sample vector that's biased towards the preferred alignment direction (importance sampling). + vec2 Xi = Hammersley(i, SAMPLE_COUNT); + vec3 H = ImportanceSampleGGX(Xi, N, roughness); + vec3 L = normalize(2.0 * dot(V, H) * H - V); - float mipLevel = roughness == 0.0 ? 0.0 : 0.5 * log2(saSample / saTexel); - - prefilteredColor += textureLod(environmentMap, L, mipLevel).rgb * NdotL; - totalWeight += NdotL; - } - } + float NdotL = max(dot(N, L), 0.0); + if(NdotL > 0.0) + { + // sample from the environment's mip level based on roughness/pdf + float D = DistributionGGX(N, H, roughness); + float NdotH = max(dot(N, H), 0.0); + float HdotV = max(dot(H, V), 0.0); + float pdf = D * NdotH / (4.0 * HdotV) + 0.0001; - prefilteredColor = prefilteredColor / totalWeight; + float resolution = 512.0; // resolution of source cubemap (per face) + float saTexel = 4.0 * PI / (6.0 * resolution * resolution); + float saSample = 1.0 / (float(SAMPLE_COUNT) * pdf + 0.0001); - FragColor = vec4(prefilteredColor, 1.0); + float mipLevel = roughness == 0.0 ? 0.0 : 0.5 * log2(saSample / saTexel); + + prefilteredColor += textureLod(environmentMap, L, mipLevel).rgb * NdotL; + totalWeight += NdotL; + } + } + + prefilteredColor = prefilteredColor / totalWeight; + + FragColor = vec4(prefilteredColor, 1.0); } \ No newline at end of file diff --git a/assets/shaders/rect_fragment.glsl b/assets/shaders/rect_fragment.glsl index ca9e5f6..dad78ef 100644 --- a/assets/shaders/rect_fragment.glsl +++ b/assets/shaders/rect_fragment.glsl @@ -1,11 +1,12 @@ #version 330 core + out vec4 FragColor; -in vec2 TexCoords; +in vec2 TexCoords; uniform sampler2D tex; void main() { vec3 color = texture(tex, TexCoords).rgb; - FragColor = vec4(color, 1.0); + FragColor = vec4(color, 1.0); } diff --git a/assets/shaders/shadow_fragment.glsl b/assets/shaders/shadow_fragment.glsl index 4565d20..230854e 100644 --- a/assets/shaders/shadow_fragment.glsl +++ b/assets/shaders/shadow_fragment.glsl @@ -2,6 +2,6 @@ void main() { - // This is implicit: - // gl_FragDepth = gl_FragCoord.z; + // This is implicit: + // gl_FragDepth = gl_FragCoord.z; } diff --git a/assets/shaders/shadow_vertex.glsl b/assets/shaders/shadow_vertex.glsl index eaca317..d9e4337 100644 --- a/assets/shaders/shadow_vertex.glsl +++ b/assets/shaders/shadow_vertex.glsl @@ -6,5 +6,5 @@ uniform mat4 model; void main() { - gl_Position = light_space_matrix * model * vec4(aPos, 1.0); + gl_Position = light_space_matrix * model * vec4(aPos, 1.0); } diff --git a/assets/shaders/vertex.glsl b/assets/shaders/vertex.glsl index 1c89491..aad89aa 100644 --- a/assets/shaders/vertex.glsl +++ b/assets/shaders/vertex.glsl @@ -1,4 +1,5 @@ #version 330 core + layout (location=0) in vec3 aPos; layout (location=1) in vec3 aNormal; layout (location=2) in vec2 aTexCoords; @@ -17,8 +18,8 @@ out vec4 frag_pos_light_space; void main() { - gl_Position = projection * view * model * vec4(aPos, 1.0); - fragPos = vec3(model * vec4(aPos, 1.0)); - frag_normal = normalize(mat3(norm) * aNormal); - frag_pos_light_space = light_space_matrix * model * vec4(aPos, 1); + gl_Position = projection * view * model * vec4(aPos, 1.0); + fragPos = vec3(model * vec4(aPos, 1.0)); + frag_normal = normalize(mat3(norm) * aNormal); + frag_pos_light_space = light_space_matrix * model * vec4(aPos, 1); } diff --git a/src/graphics.c b/src/graphics.c index a7ad6fd..2ef58ed 100644 --- a/src/graphics.c +++ b/src/graphics.c @@ -13,9 +13,9 @@ #include "graphics.h" typedef struct { - unsigned int vao; - unsigned int vbo; - int num_vertices; + unsigned int vao; + unsigned int vbo; + int num_vertices; } GPUMeshBuffer; #define MAX_MESH_BUFFERS 128 @@ -34,9 +34,7 @@ static unsigned int irradianceMap; static unsigned int prefilterMap; static unsigned int brdfLUTTexture; -/* - * Shader program handles - */ +// Shader program handles static unsigned int background_program; static unsigned int shader_program; static unsigned int shadow_program; @@ -45,70 +43,69 @@ static unsigned int skybox_program; static GLFWwindow *window_; static unsigned int -compile_shader(const char *vertex_file, - const char *fragment_file) +compile_shader(const char *vertex_file, const char *fragment_file) { - int success; - char infolog[512]; + int success; + char infolog[512]; - char *vertex_str = load_file(vertex_file, NULL); - if (vertex_str == NULL) { - fprintf(stderr, "Couldn't load file '%s'\n", vertex_file); - return 0; - } + char *vertex_str = load_file(vertex_file, NULL); + if (vertex_str == NULL) { + fprintf(stderr, "Couldn't load file '%s'\n", vertex_file); + return 0; + } - char *fragment_str = load_file(fragment_file, NULL); - if (fragment_str == NULL) { - fprintf(stderr, "Couldn't load file '%s'\n", fragment_file); - free(vertex_str); - return 0; - } + char *fragment_str = load_file(fragment_file, NULL); + if (fragment_str == NULL) { + fprintf(stderr, "Couldn't load file '%s'\n", fragment_file); + free(vertex_str); + return 0; + } - unsigned int vertex_shader = glCreateShader(GL_VERTEX_SHADER); - glShaderSource(vertex_shader, 1, &vertex_str, NULL); - glCompileShader(vertex_shader); + unsigned int vertex_shader = glCreateShader(GL_VERTEX_SHADER); + glShaderSource(vertex_shader, 1, &vertex_str, NULL); + glCompileShader(vertex_shader); - glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &success); - if(!success) { - glGetShaderInfoLog(vertex_shader, sizeof(infolog), NULL, infolog); - fprintf(stderr, "Couldn't compile vertex shader '%s' (%s)\n", vertex_file, infolog); - free(vertex_str); - free(fragment_str); - return 0; - } + glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &success); + if(!success) { + glGetShaderInfoLog(vertex_shader, sizeof(infolog), NULL, infolog); + fprintf(stderr, "Couldn't compile vertex shader '%s' (%s)\n", vertex_file, infolog); + free(vertex_str); + free(fragment_str); + return 0; + } - unsigned int fragment_shader = glCreateShader(GL_FRAGMENT_SHADER); - glShaderSource(fragment_shader, 1, &fragment_str, NULL); - glCompileShader(fragment_shader); + unsigned int fragment_shader = glCreateShader(GL_FRAGMENT_SHADER); + glShaderSource(fragment_shader, 1, &fragment_str, NULL); + glCompileShader(fragment_shader); - glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &success); - if(!success) { - glGetShaderInfoLog(fragment_shader, sizeof(infolog), NULL, infolog); - fprintf(stderr, "Couldn't compile fragment shader '%s' (%s)\n", fragment_file, infolog); - free(vertex_str); - free(fragment_str); - return 0; - } + glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &success); + if(!success) { + glGetShaderInfoLog(fragment_shader, sizeof(infolog), NULL, infolog); + fprintf(stderr, "Couldn't compile fragment shader '%s' (%s)\n", fragment_file, infolog); + free(vertex_str); + free(fragment_str); + return 0; + } - unsigned int shader_program = glCreateProgram(); - glAttachShader(shader_program, vertex_shader); - glAttachShader(shader_program, fragment_shader); - glLinkProgram(shader_program); + unsigned int shader_program = glCreateProgram(); + glAttachShader(shader_program, vertex_shader); + glAttachShader(shader_program, fragment_shader); + glLinkProgram(shader_program); - glGetProgramiv(shader_program, GL_LINK_STATUS, &success); - if(!success) { - glGetProgramInfoLog(shader_program, sizeof(infolog), NULL, infolog); - fprintf(stderr, "Couldn't link shader program (%s)\n", infolog); - free(vertex_str); - free(fragment_str); - return 0; - } + glGetProgramiv(shader_program, GL_LINK_STATUS, &success); + if(!success) { + glGetProgramInfoLog(shader_program, sizeof(infolog), NULL, infolog); + fprintf(stderr, "Couldn't link shader program (%s)\n", infolog); + free(vertex_str); + free(fragment_str); + return 0; + } - glDeleteShader(vertex_shader); - glDeleteShader(fragment_shader); - free(vertex_str); - free(fragment_str); - return shader_program; + glDeleteShader(vertex_shader); + glDeleteShader(fragment_shader); + free(vertex_str); + free(fragment_str); + return shader_program; } static void set_uniform_m4(unsigned int program, const char *name, Matrix4 value) @@ -153,31 +150,31 @@ static void set_uniform_f(unsigned int program, const char *name, float value) static GPUMeshBuffer create_gpu_mesh_buffer(VertexArray vertices) { - GPUMeshBuffer buffer; + GPUMeshBuffer buffer; - glGenVertexArrays(1, &buffer.vao); - glGenBuffers(1, &buffer.vbo); + glGenVertexArrays(1, &buffer.vao); + glGenBuffers(1, &buffer.vbo); - glBindVertexArray(buffer.vao); + glBindVertexArray(buffer.vao); - glBindBuffer(GL_ARRAY_BUFFER, buffer.vbo); - glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex) * vertices.size, vertices.data, GL_STATIC_DRAW); + glBindBuffer(GL_ARRAY_BUFFER, buffer.vbo); + glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex) * vertices.size, vertices.data, GL_STATIC_DRAW); - // positions - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)0); - glEnableVertexAttribArray(0); + // positions + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)0); + glEnableVertexAttribArray(0); - // normals - glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*) (offsetof(Vertex, nx))); - glEnableVertexAttribArray(1); + // normals + glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*) (offsetof(Vertex, nx))); + glEnableVertexAttribArray(1); - // texture coordinates - glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*) (offsetof(Vertex, tx))); - glEnableVertexAttribArray(2); + // texture coordinates + glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*) (offsetof(Vertex, tx))); + glEnableVertexAttribArray(2); - buffer.num_vertices = vertices.size; + buffer.num_vertices = vertices.size; - return buffer; + return buffer; } ModelID load_3d_model(const char *file) @@ -209,26 +206,26 @@ void free_3d_model(ModelID id) static void draw_mesh_for_shadow_map(GPUMeshBuffer buffer, Matrix4 model) { - glUseProgram(shadow_program); + glUseProgram(shadow_program); set_uniform_m4(shadow_program, "model", model); glBindVertexArray(buffer.vao); - glDrawArrays(GL_TRIANGLES, 0, buffer.num_vertices); + glDrawArrays(GL_TRIANGLES, 0, buffer.num_vertices); } static void draw_mesh(GPUMeshBuffer buffer, Matrix4 model, Material material) { Matrix4 temp; assert(invert(model, &temp)); - Matrix4 normal = transpose(temp); + Matrix4 normal = transpose(temp); - glUseProgram(shader_program); + glUseProgram(shader_program); - set_uniform_f(shader_program, "perceptualRoughness", material.perceptualRoughness); - set_uniform_f(shader_program, "metallic", material.metallic); - set_uniform_f(shader_program, "reflectance", material.reflectance); - set_uniform_v3(shader_program, "baseColor", material.baseColor); + set_uniform_f(shader_program, "perceptualRoughness", material.perceptualRoughness); + set_uniform_f(shader_program, "metallic", material.metallic); + set_uniform_f(shader_program, "reflectance", material.reflectance); + set_uniform_v3(shader_program, "baseColor", material.baseColor); set_uniform_m4(shader_program, "model", model); - set_uniform_m4(shader_program, "norm", normal); + set_uniform_m4(shader_program, "norm", normal); glBindVertexArray(buffer.vao); glDrawArrays(GL_TRIANGLES, 0, buffer.num_vertices); @@ -238,73 +235,82 @@ unsigned int cubeVAO = 0; unsigned int cubeVBO = 0; void renderCube() { - // initialize (if necessary) - if (cubeVAO == 0) - { - float vertices[] = { - // back face - -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, // bottom-left - 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f, // top-right - 1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f, // bottom-right - 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f, // top-right - -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, // bottom-left - -1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f, // top-left - // front face - -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // bottom-left - 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, // bottom-right - 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, // top-right - 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, // top-right - -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, // top-left - -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // bottom-left - // left face - -1.0f, 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, // top-right - -1.0f, 1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // top-left - -1.0f, -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, // bottom-left - -1.0f, -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, // bottom-left - -1.0f, -1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, // bottom-right - -1.0f, 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, // top-right - // right face - 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, // top-left - 1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, // bottom-right - 1.0f, 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // top-right - 1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, // bottom-right - 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, // top-left - 1.0f, -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, // bottom-left - // bottom face - -1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f, // top-right - 1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 1.0f, // top-left - 1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, // bottom-left - 1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, // bottom-left - -1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, // bottom-right - -1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f, // top-right - // top face - -1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, // top-left - 1.0f, 1.0f , 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // bottom-right - 1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, // top-right - 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // bottom-right - -1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, // top-left - -1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f // bottom-left - }; - glGenVertexArrays(1, &cubeVAO); - glGenBuffers(1, &cubeVBO); - // fill buffer - glBindBuffer(GL_ARRAY_BUFFER, cubeVBO); - glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); - // link vertex attributes - glBindVertexArray(cubeVAO); - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0); - glEnableVertexAttribArray(1); - glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float))); - glEnableVertexAttribArray(2); - glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float))); - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindVertexArray(0); - } - // render Cube - glBindVertexArray(cubeVAO); - glDrawArrays(GL_TRIANGLES, 0, 36); - glBindVertexArray(0); + // initialize (if necessary) + if (cubeVAO == 0) { + float vertices[] = { + + // back face + -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, // bottom-left + 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f, // top-right + 1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f, // bottom-right + 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f, // top-right + -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, // bottom-left + -1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f, // top-left + + // front face + -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // bottom-left + 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, // bottom-right + 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, // top-right + 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, // top-right + -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, // top-left + -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // bottom-left + + // left face + -1.0f, 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, // top-right + -1.0f, 1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // top-left + -1.0f, -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, // bottom-left + -1.0f, -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, // bottom-left + -1.0f, -1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, // bottom-right + -1.0f, 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, // top-right + + // right face + 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, // top-left + 1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, // bottom-right + 1.0f, 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // top-right + 1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, // bottom-right + 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, // top-left + 1.0f, -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, // bottom-left + + // bottom face + -1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f, // top-right + 1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 1.0f, // top-left + 1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, // bottom-left + 1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, // bottom-left + -1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, // bottom-right + -1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f, // top-right + + // top face + -1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, // top-left + 1.0f, 1.0f , 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // bottom-right + 1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, // top-right + 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // bottom-right + -1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, // top-left + -1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f // bottom-left + }; + + glGenVertexArrays(1, &cubeVAO); + glGenBuffers(1, &cubeVBO); + + // fill buffer + glBindBuffer(GL_ARRAY_BUFFER, cubeVBO); + glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); + + // link vertex attributes + glBindVertexArray(cubeVAO); + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0); + glEnableVertexAttribArray(1); + glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float))); + glEnableVertexAttribArray(2); + glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float))); + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindVertexArray(0); + } + + // render Cube + glBindVertexArray(cubeVAO); + glDrawArrays(GL_TRIANGLES, 0, 36); + glBindVertexArray(0); } // renderQuad() renders a 1x1 XY quad in NDC @@ -313,195 +319,220 @@ unsigned int quadVAO = 0; unsigned int quadVBO; void renderQuad() { - if (quadVAO == 0) - { - float quadVertices[] = { - // positions // texture Coords - -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, - -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, - 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, - 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, - }; - // setup plane VAO - glGenVertexArrays(1, &quadVAO); - glGenBuffers(1, &quadVBO); - glBindVertexArray(quadVAO); - glBindBuffer(GL_ARRAY_BUFFER, quadVBO); - glBufferData(GL_ARRAY_BUFFER, sizeof(quadVertices), &quadVertices, GL_STATIC_DRAW); - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0); - glEnableVertexAttribArray(1); - glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float))); - } - glBindVertexArray(quadVAO); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - glBindVertexArray(0); + if (quadVAO == 0) { + + float quadVertices[] = { + // positions // texture Coords + -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, + -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, + 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, + 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, + }; + + // setup plane VAO + + glGenVertexArrays(1, &quadVAO); + glGenBuffers(1, &quadVBO); + + glBindVertexArray(quadVAO); + glBindBuffer(GL_ARRAY_BUFFER, quadVBO); + + glBufferData(GL_ARRAY_BUFFER, sizeof(quadVertices), &quadVertices, GL_STATIC_DRAW); + + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0); + + glEnableVertexAttribArray(1); + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float))); + } + + glBindVertexArray(quadVAO); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + glBindVertexArray(0); } void init_graphics(void *window) { window_ = window; - - shader_program = compile_shader("assets/shaders/vertex.glsl", "assets/shaders/fragment.glsl"); - shadow_program = compile_shader("assets/shaders/shadow_vertex.glsl", "assets/shaders/shadow_fragment.glsl"); - unsigned int equirectangular_to_cubemap_program = compile_shader("assets/shaders/cubemap_vertex.glsl", "assets/shaders/equirectangular_to_cubemap_fragment.glsl"); - unsigned int irradiance_convolution_program = compile_shader("assets/shaders/cubemap_vertex.glsl", "assets/shaders/irradiance_convolution_fragment.glsl"); - background_program = compile_shader("assets/shaders/background_vertex.glsl", "assets/shaders/background_fragment.glsl"); + // Compile the main shaders + shader_program = compile_shader( + "assets/shaders/vertex.glsl", + "assets/shaders/fragment.glsl"); - { - VertexArray vertices = make_sphere_mesh(0.5); - mesh_buffers[MODEL_SPHERE-1] = create_gpu_mesh_buffer(vertices); + // The program which calculates the shadow map + shadow_program = compile_shader( + "assets/shaders/shadow_vertex.glsl", + "assets/shaders/shadow_fragment.glsl"); + + // Program to compute a cubemap from an image (only necessary at startup) + unsigned int equirectangular_to_cubemap_program = compile_shader( + "assets/shaders/cubemap_vertex.glsl", + "assets/shaders/equirectangular_to_cubemap_fragment.glsl"); + + // Apply a low pass filter on the cubemap based on the roughness + // parameter (only necessary at startup) + unsigned int irradiance_convolution_program = compile_shader( + "assets/shaders/cubemap_vertex.glsl", + "assets/shaders/irradiance_convolution_fragment.glsl"); + + // Render the high resolution cubemap + background_program = compile_shader( + "assets/shaders/background_vertex.glsl", + "assets/shaders/background_fragment.glsl"); + + // Load the sphere mesh from memory + { + VertexArray vertices = make_sphere_mesh(0.5); + mesh_buffers[MODEL_SPHERE-1] = create_gpu_mesh_buffer(vertices); free(vertices.data); - } + } + + // Load the cube mesh from memory + { + VertexArray vertices = make_cube_mesh(); + mesh_buffers[MODEL_CUBE-1] = create_gpu_mesh_buffer(vertices); + free(vertices.data); + } { - VertexArray vertices = make_cube_mesh(); - mesh_buffers[MODEL_CUBE-1] = create_gpu_mesh_buffer(vertices); - free(vertices.data); - } + glGenFramebuffers(1, &captureFBO); + glGenRenderbuffers(1, &captureRBO); - { - glGenFramebuffers(1, &captureFBO); - glGenRenderbuffers(1, &captureRBO); + glBindFramebuffer(GL_FRAMEBUFFER, captureFBO); + glBindRenderbuffer(GL_RENDERBUFFER, captureRBO); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, 512, 512); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, captureRBO); + } - glBindFramebuffer(GL_FRAMEBUFFER, captureFBO); - glBindRenderbuffer(GL_RENDERBUFFER, captureRBO); - glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, 512, 512); - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, captureRBO); - } + { + stbi_set_flip_vertically_on_load(true); + int width, height, nrComponents; + float *data = stbi_loadf("assets/spruit_sunrise_4k.hdr", &width, &height, &nrComponents, 0); + if (!data) { + fprintf(stderr, "Couldn't load map\n"); + abort(); + } - { - stbi_set_flip_vertically_on_load(true); - int width, height, nrComponents; - float *data = stbi_loadf("assets/spruit_sunrise_4k.hdr", &width, &height, &nrComponents, 0); - if (!data) { - fprintf(stderr, "Couldn't load map\n"); - abort(); - } + glGenTextures(1, &hdrTexture); + glBindTexture(GL_TEXTURE_2D, hdrTexture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, width, height, 0, GL_RGB, GL_FLOAT, data); // note how we specify the texture's data value to be float - glGenTextures(1, &hdrTexture); - glBindTexture(GL_TEXTURE_2D, hdrTexture); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, width, height, 0, GL_RGB, GL_FLOAT, data); // note how we specify the texture's data value to be float + 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_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + stbi_image_free(data); + } - stbi_image_free(data); - } + // Set up projection and view matrices for capturing data onto the 6 cubemap face directions + Matrix4 captureProjection = perspective_matrix(deg2rad(90.0f), 1.0f, 0.1f, 10.0f); + Matrix4 captureViews[] = { + lookat_matrix((Vector3) {0.0f, 0.0f, 0.0f}, (Vector3) {1.0f, 0.0f, 0.0f}, (Vector3) {0.0f, -1.0f, 0.0f}), + lookat_matrix((Vector3) {0.0f, 0.0f, 0.0f}, (Vector3) {-1.0f, 0.0f, 0.0f}, (Vector3) {0.0f, -1.0f, 0.0f}), + lookat_matrix((Vector3) {0.0f, 0.0f, 0.0f}, (Vector3) {0.0f, 1.0f, 0.0f}, (Vector3) {0.0f, 0.0f, 1.0f}), + lookat_matrix((Vector3) {0.0f, 0.0f, 0.0f}, (Vector3) {0.0f, -1.0f, 0.0f}, (Vector3) {0.0f, 0.0f, -1.0f}), + lookat_matrix((Vector3) {0.0f, 0.0f, 0.0f}, (Vector3) {0.0f, 0.0f, 1.0f}, (Vector3) {0.0f, -1.0f, 0.0f}), + lookat_matrix((Vector3) {0.0f, 0.0f, 0.0f}, (Vector3) {0.0f, 0.0f, -1.0f}, (Vector3) {0.0f, -1.0f, 0.0f}) + }; + { + glGenTextures(1, &envCubemap); + glBindTexture(GL_TEXTURE_CUBE_MAP, envCubemap); + for (unsigned int i = 0; i < 6; ++i) + glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB16F, 512, 512, 0, GL_RGB, GL_FLOAT, NULL); + 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); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - // pbr: set up projection and view matrices for capturing data onto the 6 cubemap face directions - // ---------------------------------------------------------------------------------------------- - Matrix4 captureProjection = perspective_matrix(deg2rad(90.0f), 1.0f, 0.1f, 10.0f); - Matrix4 captureViews[] = { - lookat_matrix((Vector3) {0.0f, 0.0f, 0.0f}, (Vector3) {1.0f, 0.0f, 0.0f}, (Vector3) {0.0f, -1.0f, 0.0f}), - lookat_matrix((Vector3) {0.0f, 0.0f, 0.0f}, (Vector3) {-1.0f, 0.0f, 0.0f}, (Vector3) {0.0f, -1.0f, 0.0f}), - lookat_matrix((Vector3) {0.0f, 0.0f, 0.0f}, (Vector3) {0.0f, 1.0f, 0.0f}, (Vector3) {0.0f, 0.0f, 1.0f}), - lookat_matrix((Vector3) {0.0f, 0.0f, 0.0f}, (Vector3) {0.0f, -1.0f, 0.0f}, (Vector3) {0.0f, 0.0f, -1.0f}), - lookat_matrix((Vector3) {0.0f, 0.0f, 0.0f}, (Vector3) {0.0f, 0.0f, 1.0f}, (Vector3) {0.0f, -1.0f, 0.0f}), - lookat_matrix((Vector3) {0.0f, 0.0f, 0.0f}, (Vector3) {0.0f, 0.0f, -1.0f}, (Vector3) {0.0f, -1.0f, 0.0f}) - }; - { - glGenTextures(1, &envCubemap); - glBindTexture(GL_TEXTURE_CUBE_MAP, envCubemap); - for (unsigned int i = 0; i < 6; ++i) - glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB16F, 512, 512, 0, GL_RGB, GL_FLOAT, NULL); - 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); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + // pbr: convert HDR equirectangular environment map to cubemap equivalent + // ---------------------------------------------------------------------- + glUseProgram(equirectangular_to_cubemap_program); + glUniform1i(glGetUniformLocation(equirectangular_to_cubemap_program, "equirectangularMap"), 0); + glUniformMatrix4fv(glGetUniformLocation(equirectangular_to_cubemap_program, "projection"), 1, false, (float*) &captureProjection); - // pbr: convert HDR equirectangular environment map to cubemap equivalent - // ---------------------------------------------------------------------- - glUseProgram(equirectangular_to_cubemap_program); - glUniform1i(glGetUniformLocation(equirectangular_to_cubemap_program, "equirectangularMap"), 0); - glUniformMatrix4fv(glGetUniformLocation(equirectangular_to_cubemap_program, "projection"), 1, false, (float*) &captureProjection); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, hdrTexture); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, hdrTexture); + glViewport(0, 0, 512, 512); // don't forget to configure the viewport to the capture dimensions. + glBindFramebuffer(GL_FRAMEBUFFER, captureFBO); + for (unsigned int i = 0; i < 6; i++) { + glUniformMatrix4fv(glGetUniformLocation(equirectangular_to_cubemap_program, "view"), 1, false, (float*) &captureViews[i]); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, envCubemap, 0); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glViewport(0, 0, 512, 512); // don't forget to configure the viewport to the capture dimensions. - glBindFramebuffer(GL_FRAMEBUFFER, captureFBO); - for (unsigned int i = 0; i < 6; ++i) { - glUniformMatrix4fv(glGetUniformLocation(equirectangular_to_cubemap_program, "view"), 1, false, (float*) &captureViews[i]); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, envCubemap, 0); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + renderCube(); + } + glBindFramebuffer(GL_FRAMEBUFFER, 0); + } - renderCube(); - } - glBindFramebuffer(GL_FRAMEBUFFER, 0); - } + { + // pbr: create an irradiance cubemap, and re-scale capture FBO to irradiance scale. + glGenTextures(1, &irradianceMap); + glBindTexture(GL_TEXTURE_CUBE_MAP, irradianceMap); + for (unsigned int i = 0; i < 6; ++i) + glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB16F, 32, 32, 0, GL_RGB, GL_FLOAT, NULL); - { - // pbr: create an irradiance cubemap, and re-scale capture FBO to irradiance scale. - // -------------------------------------------------------------------------------- - glGenTextures(1, &irradianceMap); - glBindTexture(GL_TEXTURE_CUBE_MAP, irradianceMap); - for (unsigned int i = 0; i < 6; ++i) - { - glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB16F, 32, 32, 0, GL_RGB, GL_FLOAT, NULL); - } - 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); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + 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); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glBindFramebuffer(GL_FRAMEBUFFER, captureFBO); - glBindRenderbuffer(GL_RENDERBUFFER, captureRBO); - glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, 32, 32); - } + glBindFramebuffer(GL_FRAMEBUFFER, captureFBO); + glBindRenderbuffer(GL_RENDERBUFFER, captureRBO); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, 32, 32); + } - { - glUseProgram(irradiance_convolution_program); - glUniform1i(glGetUniformLocation(irradiance_convolution_program, "environmentMap"), 0); - glUniformMatrix4fv(glGetUniformLocation(irradiance_convolution_program, "projection"), 1, GL_FALSE, (float*) &captureProjection); + { + glUseProgram(irradiance_convolution_program); + glUniform1i(glGetUniformLocation(irradiance_convolution_program, "environmentMap"), 0); + glUniformMatrix4fv(glGetUniformLocation(irradiance_convolution_program, "projection"), 1, GL_FALSE, (float*) &captureProjection); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_CUBE_MAP, envCubemap); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_CUBE_MAP, envCubemap); - glViewport(0, 0, 32, 32); // don't forget to configure the viewport to the capture dimensions. - glBindFramebuffer(GL_FRAMEBUFFER, captureFBO); - for (unsigned int i = 0; i < 6; ++i) - { - glUniformMatrix4fv(glGetUniformLocation(irradiance_convolution_program, "view"), 1, GL_FALSE, (float*) &captureViews[i]); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, irradianceMap, 0); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glViewport(0, 0, 32, 32); // don't forget to configure the viewport to the capture dimensions. + glBindFramebuffer(GL_FRAMEBUFFER, captureFBO); + for (unsigned int i = 0; i < 6; ++i) + { + glUniformMatrix4fv(glGetUniformLocation(irradiance_convolution_program, "view"), 1, GL_FALSE, (float*) &captureViews[i]); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, irradianceMap, 0); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - renderCube(); - } - glBindFramebuffer(GL_FRAMEBUFFER, 0); - } + renderCube(); + } + glBindFramebuffer(GL_FRAMEBUFFER, 0); + } - { - int w, h; - glfwGetWindowSize(window, &w, &h); + { + int w, h; + glfwGetWindowSize(window, &w, &h); - Matrix4 projection = perspective_matrix(deg2rad(30.0f), (float) w / (float) h, 0.1f, 100.0f); - glUseProgram(background_program); - glUniformMatrix4fv(glGetUniformLocation(background_program, "projection"), 1, false, (float*) &projection); - } + Matrix4 projection = perspective_matrix(deg2rad(30.0f), (float) w / (float) h, 0.1f, 100.0f); + glUseProgram(background_program); + glUniformMatrix4fv(glGetUniformLocation(background_program, "projection"), 1, false, (float*) &projection); + } - { - glGenFramebuffers(1, &depth_map_fbo); + { + glGenFramebuffers(1, &depth_map_fbo); - glGenTextures(1, &depth_map); - glBindTexture(GL_TEXTURE_2D, depth_map); - glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, SHADOW_WIDTH, SHADOW_HEIGHT, 0, GL_DEPTH_COMPONENT, 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_BORDER); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); + glGenTextures(1, &depth_map); + glBindTexture(GL_TEXTURE_2D, depth_map); + glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, SHADOW_WIDTH, SHADOW_HEIGHT, 0, GL_DEPTH_COMPONENT, 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_BORDER); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); - glBindFramebuffer(GL_FRAMEBUFFER, depth_map_fbo); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth_map, 0); - glDrawBuffer(GL_NONE); - glReadBuffer(GL_NONE); - glBindFramebuffer(GL_FRAMEBUFFER, 0); - } + glBindFramebuffer(GL_FRAMEBUFFER, depth_map_fbo); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth_map, 0); + glDrawBuffer(GL_NONE); + glReadBuffer(GL_NONE); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + } { glGenTextures(1, &prefilterMap); @@ -569,8 +600,8 @@ void init_graphics(void *window) 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_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glBindFramebuffer(GL_FRAMEBUFFER, captureFBO); glBindRenderbuffer(GL_RENDERBUFFER, captureRBO); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, 512, 512); @@ -586,14 +617,10 @@ void init_graphics(void *window) unsigned int rect_program = compile_shader("assets/shaders/brdf_vertex.glsl", "assets/shaders/rect_fragment.glsl"); - unsigned int depth_render_buffer; + unsigned int depth_render_buffer; glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_LEQUAL); - - //glEnable(GL_DEPTH_TEST); - //glEnable(GL_CULL_FACE); - //glCullFace(GL_BACK); + glDepthFunc(GL_LEQUAL); } typedef struct { diff --git a/src/main.c b/src/main.c index a7299b9..ddeb972 100644 --- a/src/main.c +++ b/src/main.c @@ -11,23 +11,23 @@ static void error_callback(int error, const char* description) { - fprintf(stderr, "Error: %s\n", description); + fprintf(stderr, "Error: %s\n", description); } static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) { - if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) - glfwSetWindowShouldClose(window, GLFW_TRUE); + if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) + glfwSetWindowShouldClose(window, GLFW_TRUE); } void framebuffer_size_callback(GLFWwindow* window, int width, int height) { - glViewport(0, 0, width, height); + glViewport(0, 0, width, height); } void cursor_pos_callback(GLFWwindow *window, double x, double y) { - rotate_camera(x, y); + rotate_camera(x, y); } typedef enum { @@ -41,85 +41,85 @@ typedef enum { } PieceType; typedef struct { - bool is_black; - PieceType type; + bool is_black; + PieceType type; } Piece; typedef struct { - Piece pieces[8][8]; + Piece pieces[8][8]; } Board; void init_board(Board *board) { - for (int i = 0; i < 8; i++) - for (int j = 0; j < 8; j++) { - board->pieces[i][j] = (Piece) {false, PIECE_VOID}; - } - for (int i = 0; i < 8; i++) { - board->pieces[i][1] = (Piece) {true, PIECE_PAWN}; - board->pieces[i][6] = (Piece) {false, PIECE_PAWN}; - } + for (int i = 0; i < 8; i++) + for (int j = 0; j < 8; j++) { + board->pieces[i][j] = (Piece) {false, PIECE_VOID}; + } + for (int i = 0; i < 8; i++) { + board->pieces[i][1] = (Piece) {true, PIECE_PAWN}; + board->pieces[i][6] = (Piece) {false, PIECE_PAWN}; + } - board->pieces[3][0] = (Piece) {true, PIECE_KING}; - board->pieces[3][7] = (Piece) {false, PIECE_KING}; - board->pieces[4][0] = (Piece) {true, PIECE_QUEEN}; - board->pieces[4][7] = (Piece) {false, PIECE_QUEEN}; + board->pieces[3][0] = (Piece) {true, PIECE_KING}; + board->pieces[3][7] = (Piece) {false, PIECE_KING}; + board->pieces[4][0] = (Piece) {true, PIECE_QUEEN}; + board->pieces[4][7] = (Piece) {false, PIECE_QUEEN}; - board->pieces[2][7] = (Piece) {false, PIECE_BISHOP}; - board->pieces[5][7] = (Piece) {false, PIECE_BISHOP}; + board->pieces[2][7] = (Piece) {false, PIECE_BISHOP}; + board->pieces[5][7] = (Piece) {false, PIECE_BISHOP}; - board->pieces[2][0] = (Piece) {true, PIECE_BISHOP}; - board->pieces[5][0] = (Piece) {true, PIECE_BISHOP}; + board->pieces[2][0] = (Piece) {true, PIECE_BISHOP}; + board->pieces[5][0] = (Piece) {true, PIECE_BISHOP}; - board->pieces[1][7] = (Piece) {false, PIECE_KNIGHT}; - board->pieces[6][7] = (Piece) {false, PIECE_KNIGHT}; + board->pieces[1][7] = (Piece) {false, PIECE_KNIGHT}; + board->pieces[6][7] = (Piece) {false, PIECE_KNIGHT}; - board->pieces[1][0] = (Piece) {true, PIECE_KNIGHT}; - board->pieces[6][0] = (Piece) {true, PIECE_KNIGHT}; + board->pieces[1][0] = (Piece) {true, PIECE_KNIGHT}; + board->pieces[6][0] = (Piece) {true, PIECE_KNIGHT}; - board->pieces[0][0] = (Piece) {true, PIECE_ROOK}; - board->pieces[7][0] = (Piece) {true, PIECE_ROOK}; + board->pieces[0][0] = (Piece) {true, PIECE_ROOK}; + board->pieces[7][0] = (Piece) {true, PIECE_ROOK}; - board->pieces[0][7] = (Piece) {false, PIECE_ROOK}; - board->pieces[7][7] = (Piece) {false, PIECE_ROOK}; + board->pieces[0][7] = (Piece) {false, PIECE_ROOK}; + board->pieces[7][7] = (Piece) {false, PIECE_ROOK}; - /* - board->pieces[3][4] = {false, PIECE_KING}; - board->pieces[4][5] = {false, PIECE_PAWN}; - board->pieces[4][6] = {false, PIECE_PAWN}; - */ + /* + board->pieces[3][4] = {false, PIECE_KING}; + board->pieces[4][5] = {false, PIECE_PAWN}; + board->pieces[4][6] = {false, PIECE_PAWN}; + */ } int main(void) { - glfwSetErrorCallback(error_callback); + glfwSetErrorCallback(error_callback); - if (!glfwInit()) - return -1; + if (!glfwInit()) + return -1; - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); - glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); - GLFWwindow *window = glfwCreateWindow(2*640, 2*480, "3D Chess", NULL, NULL); - if (!window) { - glfwTerminate(); - return -1; - } + GLFWwindow *window = glfwCreateWindow(2*640, 2*480, "3D Chess", NULL, NULL); + if (!window) { + glfwTerminate(); + return -1; + } - glfwSetKeyCallback(window, key_callback); - glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); - glfwSetCursorPosCallback(window, cursor_pos_callback); - glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); + glfwSetKeyCallback(window, key_callback); + glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); + glfwSetCursorPosCallback(window, cursor_pos_callback); + glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); - glfwMakeContextCurrent(window); + glfwMakeContextCurrent(window); - if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) { - printf("Failed to initialize GLAD\n"); - return -1; - } + if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) { + printf("Failed to initialize GLAD\n"); + return -1; + } - glfwSwapInterval(1); + glfwSwapInterval(1); init_graphics(window); @@ -139,7 +139,7 @@ int main(void) printf("Couldn't load model\n"); piece_models[i] = MODEL_SPHERE; } - + Board board; init_board(&board); @@ -174,12 +174,24 @@ int main(void) draw_model(piece_models[board.pieces[i][j].type], (Vector3) {cell_w * (i + 0.5), 0, cell_d * (j + 0.5)}, (Vector3) {1, 1, 1}, (Vector3) {0, rotation, 0}, piece_material); } - update_graphics(); - glfwSwapBuffers(window); - glfwPollEvents(); - } + { + Material material = {.baseColor={1, 1, 1}, .metallic=1.0, .perceptualRoughness=0, .reflectance=0}; + Vector3 pos = {cell_w * (4 + 0.5), 0, cell_d * (4 + 0.5)}; + draw_model(piece_models[PIECE_KING], pos, (Vector3) {1, 1, 1}, (Vector3) {0, 0, 0}, material); + } - glfwDestroyWindow(window); - glfwTerminate(); - return 0; + { + Material material = {.baseColor={0, 0, 0}, .metallic=1.0, .perceptualRoughness=0, .reflectance=0}; + Vector3 pos = {cell_w * (5 + 0.5), 0, cell_d * (4 + 0.5)}; + draw_model(piece_models[PIECE_KING], pos, (Vector3) {1, 1, 1}, (Vector3) {0, 0, 0}, material); + } + + update_graphics(); + glfwSwapBuffers(window); + glfwPollEvents(); + } + + glfwDestroyWindow(window); + glfwTerminate(); + return 0; }