General clean up
This commit is contained in:
@@ -7,10 +7,10 @@ uniform samplerCube environmentMap;
|
|||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
vec3 envColor = texture(environmentMap, WorldPos).rgb;
|
vec3 envColor = texture(environmentMap, WorldPos).rgb;
|
||||||
|
|
||||||
// HDR tonemap and gamma correct
|
// HDR tonemap and gamma correct
|
||||||
envColor = envColor / (envColor + vec3(1.0));
|
envColor = envColor / (envColor + vec3(1.0));
|
||||||
envColor = pow(envColor, vec3(1.0/2.2));
|
envColor = pow(envColor, vec3(1.0/2.2));
|
||||||
|
|
||||||
FragColor = vec4(envColor, 1.0);
|
FragColor = vec4(envColor, 1.0);
|
||||||
}
|
}
|
||||||
@@ -8,7 +8,7 @@ out vec3 WorldPos;
|
|||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
WorldPos = aPos;
|
WorldPos = aPos;
|
||||||
|
|
||||||
mat4 rotView = mat4(mat3(view));
|
mat4 rotView = mat4(mat3(view));
|
||||||
vec4 clipPos = projection * rotView * vec4(WorldPos, 1.0);
|
vec4 clipPos = projection * rotView * vec4(WorldPos, 1.0);
|
||||||
|
|||||||
@@ -3,24 +3,24 @@ out vec2 FragColor;
|
|||||||
in vec2 TexCoords;
|
in vec2 TexCoords;
|
||||||
|
|
||||||
const float PI = 3.14159265359;
|
const float PI = 3.14159265359;
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html
|
// http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html
|
||||||
// efficient VanDerCorpus calculation.
|
// efficient VanDerCorpus calculation.
|
||||||
float RadicalInverse_VdC(uint bits)
|
float RadicalInverse_VdC(uint bits)
|
||||||
{
|
{
|
||||||
bits = (bits << 16u) | (bits >> 16u);
|
bits = (bits << 16u) | (bits >> 16u);
|
||||||
bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u);
|
bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u);
|
||||||
bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u);
|
bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u);
|
||||||
bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u);
|
bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u);
|
||||||
bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u);
|
bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u);
|
||||||
return float(bits) * 2.3283064365386963e-10; // / 0x100000000
|
return float(bits) * 2.3283064365386963e-10; // / 0x100000000
|
||||||
}
|
}
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
vec2 Hammersley(uint i, uint N)
|
vec2 Hammersley(uint i, uint N)
|
||||||
{
|
{
|
||||||
return vec2(float(i)/float(N), RadicalInverse_VdC(i));
|
return vec2(float(i)/float(N), RadicalInverse_VdC(i));
|
||||||
}
|
}
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
vec3 ImportanceSampleGGX(vec2 Xi, vec3 N, float roughness)
|
vec3 ImportanceSampleGGX(vec2 Xi, vec3 N, float roughness)
|
||||||
{
|
{
|
||||||
float a = roughness*roughness;
|
float a = roughness*roughness;
|
||||||
@@ -36,78 +36,78 @@ vec3 ImportanceSampleGGX(vec2 Xi, vec3 N, float roughness)
|
|||||||
H.z = cosTheta;
|
H.z = cosTheta;
|
||||||
|
|
||||||
// from tangent-space H vector to world-space sample vector
|
// 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 tangent = normalize(cross(up, N));
|
||||||
vec3 bitangent = cross(N, tangent);
|
vec3 bitangent = cross(N, tangent);
|
||||||
|
|
||||||
vec3 sampleVec = tangent * H.x + bitangent * H.y + N * H.z;
|
vec3 sampleVec = tangent * H.x + bitangent * H.y + N * H.z;
|
||||||
return normalize(sampleVec);
|
return normalize(sampleVec);
|
||||||
}
|
}
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
float GeometrySchlickGGX(float NdotV, float roughness)
|
float GeometrySchlickGGX(float NdotV, float roughness)
|
||||||
{
|
{
|
||||||
// note that we use a different k for IBL
|
// note that we use a different k for IBL
|
||||||
float a = roughness;
|
float a = roughness;
|
||||||
float k = (a * a) / 2.0;
|
float k = (a * a) / 2.0;
|
||||||
|
|
||||||
float nom = NdotV;
|
float nom = NdotV;
|
||||||
float denom = NdotV * (1.0 - k) + k;
|
float denom = NdotV * (1.0 - k) + k;
|
||||||
|
|
||||||
return nom / denom;
|
return nom / denom;
|
||||||
}
|
}
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
float GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness)
|
float GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness)
|
||||||
{
|
{
|
||||||
float NdotV = max(dot(N, V), 0.0);
|
float NdotV = max(dot(N, V), 0.0);
|
||||||
float NdotL = max(dot(N, L), 0.0);
|
float NdotL = max(dot(N, L), 0.0);
|
||||||
float ggx2 = GeometrySchlickGGX(NdotV, roughness);
|
float ggx2 = GeometrySchlickGGX(NdotV, roughness);
|
||||||
float ggx1 = GeometrySchlickGGX(NdotL, roughness);
|
float ggx1 = GeometrySchlickGGX(NdotL, roughness);
|
||||||
|
|
||||||
return ggx1 * ggx2;
|
return ggx1 * ggx2;
|
||||||
}
|
}
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
vec2 IntegrateBRDF(float NdotV, float roughness)
|
vec2 IntegrateBRDF(float NdotV, float roughness)
|
||||||
{
|
{
|
||||||
vec3 V;
|
vec3 V;
|
||||||
V.x = sqrt(1.0 - NdotV*NdotV);
|
V.x = sqrt(1.0 - NdotV*NdotV);
|
||||||
V.y = 0.0;
|
V.y = 0.0;
|
||||||
V.z = NdotV;
|
V.z = NdotV;
|
||||||
|
|
||||||
float A = 0.0;
|
float A = 0.0;
|
||||||
float B = 0.0;
|
float B = 0.0;
|
||||||
|
|
||||||
vec3 N = vec3(0.0, 0.0, 1.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);
|
|
||||||
|
|
||||||
float NdotL = max(L.z, 0.0);
|
const uint SAMPLE_COUNT = 1024u;
|
||||||
float NdotH = max(H.z, 0.0);
|
for(uint i = 0u; i < SAMPLE_COUNT; ++i) {
|
||||||
float VdotH = max(dot(V, H), 0.0);
|
|
||||||
|
|
||||||
if(NdotL > 0.0)
|
// generates a sample vector that's biased towards the
|
||||||
{
|
// preferred alignment direction (importance sampling).
|
||||||
float G = GeometrySmith(N, V, L, roughness);
|
vec2 Xi = Hammersley(i, SAMPLE_COUNT);
|
||||||
float G_Vis = (G * VdotH) / (NdotH * NdotV);
|
vec3 H = ImportanceSampleGGX(Xi, N, roughness);
|
||||||
float Fc = pow(1.0 - VdotH, 5.0);
|
vec3 L = normalize(2.0 * dot(V, H) * H - V);
|
||||||
|
|
||||||
A += (1.0 - Fc) * G_Vis;
|
float NdotL = max(L.z, 0.0);
|
||||||
B += Fc * G_Vis;
|
float NdotH = max(H.z, 0.0);
|
||||||
}
|
float VdotH = max(dot(V, H), 0.0);
|
||||||
}
|
|
||||||
A /= float(SAMPLE_COUNT);
|
if(NdotL > 0.0) {
|
||||||
B /= float(SAMPLE_COUNT);
|
|
||||||
return vec2(A, B);
|
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()
|
void main()
|
||||||
{
|
{
|
||||||
vec2 integratedBRDF = IntegrateBRDF(TexCoords.x, TexCoords.y);
|
vec2 integratedBRDF = IntegrateBRDF(TexCoords.x, TexCoords.y);
|
||||||
FragColor = integratedBRDF;
|
FragColor = integratedBRDF;
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
#version 330 core
|
#version 330 core
|
||||||
|
|
||||||
layout (location = 0) in vec3 aPos;
|
layout (location = 0) in vec3 aPos;
|
||||||
layout (location = 1) in vec2 aTexCoords;
|
layout (location = 1) in vec2 aTexCoords;
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#version 330 core
|
#version 330 core
|
||||||
|
|
||||||
layout (location = 0) in vec3 aPos;
|
layout (location = 0) in vec3 aPos;
|
||||||
|
|
||||||
out vec3 WorldPos;
|
out vec3 WorldPos;
|
||||||
|
|||||||
@@ -1,31 +1,33 @@
|
|||||||
#version 330 core
|
#version 330 core
|
||||||
|
|
||||||
out vec4 FragColor;
|
out vec4 FragColor;
|
||||||
in vec3 WorldPos;
|
in vec3 WorldPos;
|
||||||
|
|
||||||
uniform sampler2D equirectangularMap;
|
uniform sampler2D equirectangularMap;
|
||||||
|
|
||||||
const vec2 invAtan = vec2(0.1591, 0.3183);
|
const vec2 invAtan = vec2(0.1591, 0.3183);
|
||||||
|
|
||||||
vec2 SampleSphericalMap(vec3 v)
|
vec2 SampleSphericalMap(vec3 v)
|
||||||
{
|
{
|
||||||
vec2 uv = vec2(atan(v.z, v.x), asin(v.y));
|
vec2 uv = vec2(atan(v.z, v.x), asin(v.y));
|
||||||
uv *= invAtan;
|
uv *= invAtan;
|
||||||
uv += 0.5;
|
uv += 0.5;
|
||||||
return uv;
|
return uv;
|
||||||
}
|
}
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
vec2 uv = SampleSphericalMap(normalize(WorldPos));
|
vec2 uv = SampleSphericalMap(normalize(WorldPos));
|
||||||
vec3 color = texture(equirectangularMap, uv).rgb;
|
vec3 color = texture(equirectangularMap, uv).rgb;
|
||||||
|
|
||||||
// reinhard tone mapping
|
// 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;
|
//float gamma = 2.2;
|
||||||
//mapped = pow(mapped, vec3(1.0 / gamma));
|
//mapped = pow(mapped, vec3(1.0 / gamma));
|
||||||
|
|
||||||
color = mapped;
|
color = mapped;
|
||||||
|
|
||||||
FragColor = vec4(color, 1.0);
|
FragColor = vec4(color, 1.0);
|
||||||
}
|
}
|
||||||
@@ -29,66 +29,66 @@ uniform sampler2D brdfLUT;
|
|||||||
float shadow_factor(vec4 frag_pos_light_space);
|
float shadow_factor(vec4 frag_pos_light_space);
|
||||||
|
|
||||||
float distribGGX(float NoH, float a) {
|
float distribGGX(float NoH, float a) {
|
||||||
float a2 = a * a;
|
float a2 = a * a;
|
||||||
float f = (NoH * a2 - NoH) * NoH + 1.0;
|
float f = (NoH * a2 - NoH) * NoH + 1.0;
|
||||||
return a2 / (PI * f * f);
|
return a2 / (PI * f * f);
|
||||||
}
|
}
|
||||||
|
|
||||||
vec3 fresnelSchlick(float u, vec3 f0) {
|
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)
|
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 geometrySmith(float NoV, float NoL, float a) {
|
||||||
float a2 = a * a;
|
float a2 = a * a;
|
||||||
float GGXL = NoV * sqrt((-NoL * a2 + NoL) * NoL + a2);
|
float GGXL = NoV * sqrt((-NoL * a2 + NoL) * NoL + a2);
|
||||||
float GGXV = NoL * sqrt((-NoV * a2 + NoV) * NoV + a2);
|
float GGXV = NoL * sqrt((-NoV * a2 + NoV) * NoV + a2);
|
||||||
return 0.5 / (GGXV + GGXL);
|
return 0.5 / (GGXV + GGXL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
vec3 l = normalize(lightDir);
|
vec3 l = normalize(lightDir);
|
||||||
vec3 v = normalize(viewPos - fragPos);
|
vec3 v = normalize(viewPos - fragPos);
|
||||||
vec3 n = frag_normal;
|
vec3 n = frag_normal;
|
||||||
vec3 h = normalize(v + l);
|
vec3 h = normalize(v + l);
|
||||||
|
|
||||||
float light_intensity = 1;
|
float light_intensity = 1;
|
||||||
|
|
||||||
float perceptualRoughness2 = max(perceptualRoughness, 0.089);
|
float perceptualRoughness2 = max(perceptualRoughness, 0.089);
|
||||||
float roughness = perceptualRoughness2 * perceptualRoughness2;
|
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 NoV = abs(dot(n, v)) + 1e-5;
|
||||||
float NoL = clamp(dot(n, l), 0.0, 1.0);
|
float NoL = clamp(dot(n, l), 0.0, 1.0);
|
||||||
float NoH = clamp(dot(n, h), 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 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);
|
float shadow = shadow_factor(frag_pos_light_space);
|
||||||
|
|
||||||
// Direct lighting
|
// Direct lighting
|
||||||
{
|
{
|
||||||
float D = distribGGX(NoH, roughness);
|
float D = distribGGX(NoH, roughness);
|
||||||
vec3 F = fresnelSchlick(LoH, f0);
|
vec3 F = fresnelSchlick(LoH, f0);
|
||||||
float V = geometrySmith(NoV, NoL, roughness);
|
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 ambient;
|
||||||
{
|
{
|
||||||
vec3 F = fresnelSchlickRoughness(NoV, f0, roughness);
|
vec3 F = fresnelSchlickRoughness(NoV, f0, roughness);
|
||||||
|
|
||||||
vec3 irradiance = texture(irradianceMap, n).rgb;
|
vec3 irradiance = texture(irradianceMap, n).rgb;
|
||||||
@@ -105,32 +105,33 @@ void main()
|
|||||||
|
|
||||||
float ao = 1;
|
float ao = 1;
|
||||||
ambient = ((1 - F) * (1 - metallic) * diffuse + specular) * ao;
|
ambient = ((1 - F) * (1 - metallic) * diffuse + specular) * ao;
|
||||||
}
|
}
|
||||||
|
|
||||||
color = color + ambient;
|
color = color + ambient;
|
||||||
|
|
||||||
color = color / (color + vec3(1.0)); // HDR tonemapping
|
color = color / (color + vec3(1.0)); // HDR tonemapping
|
||||||
color = pow(color, vec3(1.0/2.2)); // gamma correct
|
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)
|
float shadow_factor(vec4 frag_pos_light_space)
|
||||||
{
|
{
|
||||||
vec3 proj_coords = frag_pos_light_space.xyz / frag_pos_light_space.w;
|
vec3 proj_coords = frag_pos_light_space.xyz / frag_pos_light_space.w;
|
||||||
proj_coords = proj_coords * 0.5 + 0.5;
|
proj_coords = proj_coords * 0.5 + 0.5;
|
||||||
|
|
||||||
float closest_depth = texture(shadow_map, proj_coords.xy).r;
|
float closest_depth = texture(shadow_map, proj_coords.xy).r;
|
||||||
float current_depth = proj_coords.z;
|
float current_depth = proj_coords.z;
|
||||||
|
|
||||||
float bias = 0.005;
|
float bias = 0.005;
|
||||||
float shadow = 0;
|
float shadow = 0;
|
||||||
vec2 delta = 1.0 / textureSize(shadow_map, 0);
|
vec2 delta = 1.0 / textureSize(shadow_map, 0);
|
||||||
for (int i = -1; i < 2; i++)
|
for (int i = -1; i < 2; i++)
|
||||||
for (int j = -1; j < 2; j++) {
|
for (int j = -1; j < 2; j++) {
|
||||||
float closest_depth = texture(shadow_map, proj_coords.xy + vec2(i, j) * delta).r;
|
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 += (current_depth - bias > closest_depth) ? 1.0 : 0.0;
|
||||||
}
|
}
|
||||||
shadow /= 9;
|
|
||||||
return shadow;
|
shadow /= 9;
|
||||||
|
return shadow;
|
||||||
}
|
}
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -7,37 +7,37 @@ uniform samplerCube environmentMap;
|
|||||||
const float PI = 3.14159265359;
|
const float PI = 3.14159265359;
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
// The world vector acts as the normal of a tangent surface
|
// The world vector acts as the normal of a tangent surface
|
||||||
// from the origin, aligned to WorldPos. Given this normal, calculate all
|
// from the origin, aligned to WorldPos. Given this normal, calculate all
|
||||||
// incoming radiance of the environment. The result of this radiance
|
// incoming radiance of the environment. The result of this radiance
|
||||||
// is the radiance of light coming from -Normal direction, which is what
|
// is the radiance of light coming from -Normal direction, which is what
|
||||||
// we use in the PBR shader to sample irradiance.
|
// we use in the PBR shader to sample irradiance.
|
||||||
vec3 N = normalize(WorldPos);
|
vec3 N = normalize(WorldPos);
|
||||||
|
|
||||||
vec3 irradiance = vec3(0.0);
|
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;
|
|
||||||
|
|
||||||
irradiance += texture(environmentMap, sampleVec).rgb * cos(theta) * sin(theta);
|
// tangent space calculation from origin point
|
||||||
nrSamples++;
|
vec3 up = vec3(0.0, 1.0, 0.0);
|
||||||
}
|
vec3 right = normalize(cross(up, N));
|
||||||
}
|
up = normalize(cross(N, right));
|
||||||
irradiance = PI * irradiance * (1.0 / float(nrSamples));
|
|
||||||
|
float sampleDelta = 0.025;
|
||||||
FragColor = vec4(irradiance, 1.0);
|
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);
|
||||||
}
|
}
|
||||||
@@ -6,101 +6,101 @@ uniform samplerCube environmentMap;
|
|||||||
uniform float roughness;
|
uniform float roughness;
|
||||||
|
|
||||||
const float PI = 3.14159265359;
|
const float PI = 3.14159265359;
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
float DistributionGGX(vec3 N, vec3 H, float roughness)
|
float DistributionGGX(vec3 N, vec3 H, float roughness)
|
||||||
{
|
{
|
||||||
float a = roughness*roughness;
|
float a = roughness*roughness;
|
||||||
float a2 = a*a;
|
float a2 = a*a;
|
||||||
float NdotH = max(dot(N, H), 0.0);
|
float NdotH = max(dot(N, H), 0.0);
|
||||||
float NdotH2 = NdotH*NdotH;
|
float NdotH2 = NdotH*NdotH;
|
||||||
|
|
||||||
float nom = a2;
|
float nom = a2;
|
||||||
float denom = (NdotH2 * (a2 - 1.0) + 1.0);
|
float denom = (NdotH2 * (a2 - 1.0) + 1.0);
|
||||||
denom = PI * denom * denom;
|
denom = PI * denom * denom;
|
||||||
|
|
||||||
return nom / denom;
|
return nom / denom;
|
||||||
}
|
}
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html
|
// http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html
|
||||||
// efficient VanDerCorpus calculation.
|
// efficient VanDerCorpus calculation.
|
||||||
float RadicalInverse_VdC(uint bits)
|
float RadicalInverse_VdC(uint bits)
|
||||||
{
|
{
|
||||||
bits = (bits << 16u) | (bits >> 16u);
|
bits = (bits << 16u) | (bits >> 16u);
|
||||||
bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u);
|
bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u);
|
||||||
bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u);
|
bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u);
|
||||||
bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u);
|
bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u);
|
||||||
bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u);
|
bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u);
|
||||||
return float(bits) * 2.3283064365386963e-10; // / 0x100000000
|
return float(bits) * 2.3283064365386963e-10; // / 0x100000000
|
||||||
}
|
}
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
vec2 Hammersley(uint i, uint N)
|
vec2 Hammersley(uint i, uint N)
|
||||||
{
|
{
|
||||||
return vec2(float(i)/float(N), RadicalInverse_VdC(i));
|
return vec2(float(i)/float(N), RadicalInverse_VdC(i));
|
||||||
}
|
}
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
vec3 ImportanceSampleGGX(vec2 Xi, vec3 N, float roughness)
|
vec3 ImportanceSampleGGX(vec2 Xi, vec3 N, float roughness)
|
||||||
{
|
{
|
||||||
float a = roughness*roughness;
|
float a = roughness*roughness;
|
||||||
|
|
||||||
float phi = 2.0 * PI * Xi.x;
|
float phi = 2.0 * PI * Xi.x;
|
||||||
float cosTheta = sqrt((1.0 - Xi.y) / (1.0 + (a*a - 1.0) * Xi.y));
|
float cosTheta = sqrt((1.0 - Xi.y) / (1.0 + (a*a - 1.0) * Xi.y));
|
||||||
float sinTheta = sqrt(1.0 - cosTheta*cosTheta);
|
float sinTheta = sqrt(1.0 - cosTheta*cosTheta);
|
||||||
|
|
||||||
// from spherical coordinates to cartesian coordinates - halfway vector
|
// from spherical coordinates to cartesian coordinates - halfway vector
|
||||||
vec3 H;
|
vec3 H;
|
||||||
H.x = cos(phi) * sinTheta;
|
H.x = cos(phi) * sinTheta;
|
||||||
H.y = sin(phi) * sinTheta;
|
H.y = sin(phi) * sinTheta;
|
||||||
H.z = cosTheta;
|
H.z = cosTheta;
|
||||||
|
|
||||||
// from tangent-space H vector to world-space sample vector
|
// 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 tangent = normalize(cross(up, N));
|
||||||
vec3 bitangent = cross(N, tangent);
|
vec3 bitangent = cross(N, tangent);
|
||||||
|
|
||||||
vec3 sampleVec = tangent * H.x + bitangent * H.y + N * H.z;
|
vec3 sampleVec = tangent * H.x + bitangent * H.y + N * H.z;
|
||||||
return normalize(sampleVec);
|
return normalize(sampleVec);
|
||||||
}
|
}
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
vec3 N = normalize(WorldPos);
|
vec3 N = normalize(WorldPos);
|
||||||
|
|
||||||
// make the simplifying assumption that V equals R equals the normal
|
|
||||||
vec3 R = N;
|
|
||||||
vec3 V = R;
|
|
||||||
|
|
||||||
const uint SAMPLE_COUNT = 1024u;
|
// make the simplifying assumption that V equals R equals the normal
|
||||||
vec3 prefilteredColor = vec3(0.0);
|
vec3 R = N;
|
||||||
float totalWeight = 0.0;
|
vec3 V = R;
|
||||||
|
|
||||||
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 NdotL = max(dot(N, L), 0.0);
|
const uint SAMPLE_COUNT = 1024u;
|
||||||
if(NdotL > 0.0)
|
vec3 prefilteredColor = vec3(0.0);
|
||||||
{
|
float totalWeight = 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;
|
|
||||||
|
|
||||||
float resolution = 512.0; // resolution of source cubemap (per face)
|
for(uint i = 0u; i < SAMPLE_COUNT; ++i)
|
||||||
float saTexel = 4.0 * PI / (6.0 * resolution * resolution);
|
{
|
||||||
float saSample = 1.0 / (float(SAMPLE_COUNT) * pdf + 0.0001);
|
// 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);
|
float NdotL = max(dot(N, L), 0.0);
|
||||||
|
if(NdotL > 0.0)
|
||||||
prefilteredColor += textureLod(environmentMap, L, mipLevel).rgb * NdotL;
|
{
|
||||||
totalWeight += NdotL;
|
// 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);
|
||||||
}
|
}
|
||||||
@@ -1,11 +1,12 @@
|
|||||||
#version 330 core
|
#version 330 core
|
||||||
|
|
||||||
out vec4 FragColor;
|
out vec4 FragColor;
|
||||||
in vec2 TexCoords;
|
in vec2 TexCoords;
|
||||||
|
|
||||||
uniform sampler2D tex;
|
uniform sampler2D tex;
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
vec3 color = texture(tex, TexCoords).rgb;
|
vec3 color = texture(tex, TexCoords).rgb;
|
||||||
FragColor = vec4(color, 1.0);
|
FragColor = vec4(color, 1.0);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,6 @@
|
|||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
// This is implicit:
|
// This is implicit:
|
||||||
// gl_FragDepth = gl_FragCoord.z;
|
// gl_FragDepth = gl_FragCoord.z;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,5 +6,5 @@ uniform mat4 model;
|
|||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
gl_Position = light_space_matrix * model * vec4(aPos, 1.0);
|
gl_Position = light_space_matrix * model * vec4(aPos, 1.0);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#version 330 core
|
#version 330 core
|
||||||
|
|
||||||
layout (location=0) in vec3 aPos;
|
layout (location=0) in vec3 aPos;
|
||||||
layout (location=1) in vec3 aNormal;
|
layout (location=1) in vec3 aNormal;
|
||||||
layout (location=2) in vec2 aTexCoords;
|
layout (location=2) in vec2 aTexCoords;
|
||||||
@@ -17,8 +18,8 @@ out vec4 frag_pos_light_space;
|
|||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
gl_Position = projection * view * model * vec4(aPos, 1.0);
|
gl_Position = projection * view * model * vec4(aPos, 1.0);
|
||||||
fragPos = vec3(model * vec4(aPos, 1.0));
|
fragPos = vec3(model * vec4(aPos, 1.0));
|
||||||
frag_normal = normalize(mat3(norm) * aNormal);
|
frag_normal = normalize(mat3(norm) * aNormal);
|
||||||
frag_pos_light_space = light_space_matrix * model * vec4(aPos, 1);
|
frag_pos_light_space = light_space_matrix * model * vec4(aPos, 1);
|
||||||
}
|
}
|
||||||
|
|||||||
+345
-318
@@ -13,9 +13,9 @@
|
|||||||
#include "graphics.h"
|
#include "graphics.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
unsigned int vao;
|
unsigned int vao;
|
||||||
unsigned int vbo;
|
unsigned int vbo;
|
||||||
int num_vertices;
|
int num_vertices;
|
||||||
} GPUMeshBuffer;
|
} GPUMeshBuffer;
|
||||||
|
|
||||||
#define MAX_MESH_BUFFERS 128
|
#define MAX_MESH_BUFFERS 128
|
||||||
@@ -34,9 +34,7 @@ static unsigned int irradianceMap;
|
|||||||
static unsigned int prefilterMap;
|
static unsigned int prefilterMap;
|
||||||
static unsigned int brdfLUTTexture;
|
static unsigned int brdfLUTTexture;
|
||||||
|
|
||||||
/*
|
// Shader program handles
|
||||||
* Shader program handles
|
|
||||||
*/
|
|
||||||
static unsigned int background_program;
|
static unsigned int background_program;
|
||||||
static unsigned int shader_program;
|
static unsigned int shader_program;
|
||||||
static unsigned int shadow_program;
|
static unsigned int shadow_program;
|
||||||
@@ -45,70 +43,69 @@ static unsigned int skybox_program;
|
|||||||
static GLFWwindow *window_;
|
static GLFWwindow *window_;
|
||||||
|
|
||||||
static unsigned int
|
static unsigned int
|
||||||
compile_shader(const char *vertex_file,
|
compile_shader(const char *vertex_file, const char *fragment_file)
|
||||||
const char *fragment_file)
|
|
||||||
{
|
{
|
||||||
int success;
|
int success;
|
||||||
char infolog[512];
|
char infolog[512];
|
||||||
|
|
||||||
char *vertex_str = load_file(vertex_file, NULL);
|
char *vertex_str = load_file(vertex_file, NULL);
|
||||||
if (vertex_str == NULL) {
|
if (vertex_str == NULL) {
|
||||||
fprintf(stderr, "Couldn't load file '%s'\n", vertex_file);
|
fprintf(stderr, "Couldn't load file '%s'\n", vertex_file);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *fragment_str = load_file(fragment_file, NULL);
|
char *fragment_str = load_file(fragment_file, NULL);
|
||||||
if (fragment_str == NULL) {
|
if (fragment_str == NULL) {
|
||||||
fprintf(stderr, "Couldn't load file '%s'\n", fragment_file);
|
fprintf(stderr, "Couldn't load file '%s'\n", fragment_file);
|
||||||
free(vertex_str);
|
free(vertex_str);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int vertex_shader = glCreateShader(GL_VERTEX_SHADER);
|
unsigned int vertex_shader = glCreateShader(GL_VERTEX_SHADER);
|
||||||
glShaderSource(vertex_shader, 1, &vertex_str, NULL);
|
glShaderSource(vertex_shader, 1, &vertex_str, NULL);
|
||||||
glCompileShader(vertex_shader);
|
glCompileShader(vertex_shader);
|
||||||
|
|
||||||
glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &success);
|
glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &success);
|
||||||
if(!success) {
|
if(!success) {
|
||||||
glGetShaderInfoLog(vertex_shader, sizeof(infolog), NULL, infolog);
|
glGetShaderInfoLog(vertex_shader, sizeof(infolog), NULL, infolog);
|
||||||
fprintf(stderr, "Couldn't compile vertex shader '%s' (%s)\n", vertex_file, infolog);
|
fprintf(stderr, "Couldn't compile vertex shader '%s' (%s)\n", vertex_file, infolog);
|
||||||
free(vertex_str);
|
free(vertex_str);
|
||||||
free(fragment_str);
|
free(fragment_str);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
|
unsigned int fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
|
||||||
glShaderSource(fragment_shader, 1, &fragment_str, NULL);
|
glShaderSource(fragment_shader, 1, &fragment_str, NULL);
|
||||||
glCompileShader(fragment_shader);
|
glCompileShader(fragment_shader);
|
||||||
|
|
||||||
glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &success);
|
glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &success);
|
||||||
if(!success) {
|
if(!success) {
|
||||||
glGetShaderInfoLog(fragment_shader, sizeof(infolog), NULL, infolog);
|
glGetShaderInfoLog(fragment_shader, sizeof(infolog), NULL, infolog);
|
||||||
fprintf(stderr, "Couldn't compile fragment shader '%s' (%s)\n", fragment_file, infolog);
|
fprintf(stderr, "Couldn't compile fragment shader '%s' (%s)\n", fragment_file, infolog);
|
||||||
free(vertex_str);
|
free(vertex_str);
|
||||||
free(fragment_str);
|
free(fragment_str);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int shader_program = glCreateProgram();
|
unsigned int shader_program = glCreateProgram();
|
||||||
glAttachShader(shader_program, vertex_shader);
|
glAttachShader(shader_program, vertex_shader);
|
||||||
glAttachShader(shader_program, fragment_shader);
|
glAttachShader(shader_program, fragment_shader);
|
||||||
glLinkProgram(shader_program);
|
glLinkProgram(shader_program);
|
||||||
|
|
||||||
glGetProgramiv(shader_program, GL_LINK_STATUS, &success);
|
glGetProgramiv(shader_program, GL_LINK_STATUS, &success);
|
||||||
if(!success) {
|
if(!success) {
|
||||||
glGetProgramInfoLog(shader_program, sizeof(infolog), NULL, infolog);
|
glGetProgramInfoLog(shader_program, sizeof(infolog), NULL, infolog);
|
||||||
fprintf(stderr, "Couldn't link shader program (%s)\n", infolog);
|
fprintf(stderr, "Couldn't link shader program (%s)\n", infolog);
|
||||||
free(vertex_str);
|
free(vertex_str);
|
||||||
free(fragment_str);
|
free(fragment_str);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
glDeleteShader(vertex_shader);
|
glDeleteShader(vertex_shader);
|
||||||
glDeleteShader(fragment_shader);
|
glDeleteShader(fragment_shader);
|
||||||
free(vertex_str);
|
free(vertex_str);
|
||||||
free(fragment_str);
|
free(fragment_str);
|
||||||
return shader_program;
|
return shader_program;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void set_uniform_m4(unsigned int program, const char *name, Matrix4 value)
|
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)
|
static GPUMeshBuffer create_gpu_mesh_buffer(VertexArray vertices)
|
||||||
{
|
{
|
||||||
GPUMeshBuffer buffer;
|
GPUMeshBuffer buffer;
|
||||||
|
|
||||||
glGenVertexArrays(1, &buffer.vao);
|
glGenVertexArrays(1, &buffer.vao);
|
||||||
glGenBuffers(1, &buffer.vbo);
|
glGenBuffers(1, &buffer.vbo);
|
||||||
|
|
||||||
glBindVertexArray(buffer.vao);
|
glBindVertexArray(buffer.vao);
|
||||||
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, buffer.vbo);
|
glBindBuffer(GL_ARRAY_BUFFER, buffer.vbo);
|
||||||
glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex) * vertices.size, vertices.data, GL_STATIC_DRAW);
|
glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex) * vertices.size, vertices.data, GL_STATIC_DRAW);
|
||||||
|
|
||||||
// positions
|
// positions
|
||||||
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)0);
|
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)0);
|
||||||
glEnableVertexAttribArray(0);
|
glEnableVertexAttribArray(0);
|
||||||
|
|
||||||
// normals
|
// normals
|
||||||
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*) (offsetof(Vertex, nx)));
|
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*) (offsetof(Vertex, nx)));
|
||||||
glEnableVertexAttribArray(1);
|
glEnableVertexAttribArray(1);
|
||||||
|
|
||||||
// texture coordinates
|
// texture coordinates
|
||||||
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*) (offsetof(Vertex, tx)));
|
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*) (offsetof(Vertex, tx)));
|
||||||
glEnableVertexAttribArray(2);
|
glEnableVertexAttribArray(2);
|
||||||
|
|
||||||
buffer.num_vertices = vertices.size;
|
buffer.num_vertices = vertices.size;
|
||||||
|
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
ModelID load_3d_model(const char *file)
|
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)
|
static void draw_mesh_for_shadow_map(GPUMeshBuffer buffer, Matrix4 model)
|
||||||
{
|
{
|
||||||
glUseProgram(shadow_program);
|
glUseProgram(shadow_program);
|
||||||
set_uniform_m4(shadow_program, "model", model);
|
set_uniform_m4(shadow_program, "model", model);
|
||||||
glBindVertexArray(buffer.vao);
|
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)
|
static void draw_mesh(GPUMeshBuffer buffer, Matrix4 model, Material material)
|
||||||
{
|
{
|
||||||
Matrix4 temp;
|
Matrix4 temp;
|
||||||
assert(invert(model, &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, "perceptualRoughness", material.perceptualRoughness);
|
||||||
set_uniform_f(shader_program, "metallic", material.metallic);
|
set_uniform_f(shader_program, "metallic", material.metallic);
|
||||||
set_uniform_f(shader_program, "reflectance", material.reflectance);
|
set_uniform_f(shader_program, "reflectance", material.reflectance);
|
||||||
set_uniform_v3(shader_program, "baseColor", material.baseColor);
|
set_uniform_v3(shader_program, "baseColor", material.baseColor);
|
||||||
set_uniform_m4(shader_program, "model", model);
|
set_uniform_m4(shader_program, "model", model);
|
||||||
set_uniform_m4(shader_program, "norm", normal);
|
set_uniform_m4(shader_program, "norm", normal);
|
||||||
|
|
||||||
glBindVertexArray(buffer.vao);
|
glBindVertexArray(buffer.vao);
|
||||||
glDrawArrays(GL_TRIANGLES, 0, buffer.num_vertices);
|
glDrawArrays(GL_TRIANGLES, 0, buffer.num_vertices);
|
||||||
@@ -238,73 +235,82 @@ unsigned int cubeVAO = 0;
|
|||||||
unsigned int cubeVBO = 0;
|
unsigned int cubeVBO = 0;
|
||||||
void renderCube()
|
void renderCube()
|
||||||
{
|
{
|
||||||
// initialize (if necessary)
|
// initialize (if necessary)
|
||||||
if (cubeVAO == 0)
|
if (cubeVAO == 0) {
|
||||||
{
|
float vertices[] = {
|
||||||
float vertices[] = {
|
|
||||||
// back face
|
// 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, 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, 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, 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, 0.0f, // bottom-left
|
-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
|
-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
|
// front face
|
||||||
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, 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, 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, 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
|
||||||
// left 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, -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
|
// left face
|
||||||
-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, 1.0f, 0.0f, // top-right
|
||||||
-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, 1.0f, 1.0f, // top-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, 0.0f, 1.0f, // bottom-left
|
||||||
-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, 0.0f, 1.0f, // bottom-left
|
||||||
// right face
|
-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-left
|
-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, 0.0f, 1.0f, // bottom-right
|
|
||||||
1.0f, 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // top-right
|
// right face
|
||||||
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, 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, 0.0f, 0.0f, // bottom-left
|
1.0f, 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // top-right
|
||||||
// bottom face
|
1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, // bottom-right
|
||||||
-1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f, // top-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, 0.0f, -1.0f, 0.0f, 1.0f, 1.0f, // top-left
|
1.0f, -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.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, 1.0f, 0.0f, // bottom-left
|
// bottom face
|
||||||
-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
|
||||||
-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
|
||||||
// top face
|
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, 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-right
|
-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, 1.0f, 1.0f, // top-right
|
-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, 0.0f, // bottom-right
|
|
||||||
-1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, // top-left
|
// top face
|
||||||
-1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f // bottom-left
|
-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
|
||||||
glGenVertexArrays(1, &cubeVAO);
|
1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, // top-right
|
||||||
glGenBuffers(1, &cubeVBO);
|
1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // bottom-right
|
||||||
// fill buffer
|
-1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, // top-left
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, cubeVBO);
|
-1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f // bottom-left
|
||||||
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
|
};
|
||||||
// link vertex attributes
|
|
||||||
glBindVertexArray(cubeVAO);
|
glGenVertexArrays(1, &cubeVAO);
|
||||||
glEnableVertexAttribArray(0);
|
glGenBuffers(1, &cubeVBO);
|
||||||
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
|
|
||||||
glEnableVertexAttribArray(1);
|
// fill buffer
|
||||||
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
|
glBindBuffer(GL_ARRAY_BUFFER, cubeVBO);
|
||||||
glEnableVertexAttribArray(2);
|
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
|
||||||
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
// link vertex attributes
|
||||||
glBindVertexArray(0);
|
glBindVertexArray(cubeVAO);
|
||||||
}
|
glEnableVertexAttribArray(0);
|
||||||
// render Cube
|
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
|
||||||
glBindVertexArray(cubeVAO);
|
glEnableVertexAttribArray(1);
|
||||||
glDrawArrays(GL_TRIANGLES, 0, 36);
|
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
|
||||||
glBindVertexArray(0);
|
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
|
// renderQuad() renders a 1x1 XY quad in NDC
|
||||||
@@ -313,195 +319,220 @@ unsigned int quadVAO = 0;
|
|||||||
unsigned int quadVBO;
|
unsigned int quadVBO;
|
||||||
void renderQuad()
|
void renderQuad()
|
||||||
{
|
{
|
||||||
if (quadVAO == 0)
|
if (quadVAO == 0) {
|
||||||
{
|
|
||||||
float quadVertices[] = {
|
float quadVertices[] = {
|
||||||
// positions // texture Coords
|
// positions // texture Coords
|
||||||
-1.0f, 1.0f, 0.0f, 0.0f, 1.0f,
|
-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, 0.0f, 0.0f,
|
||||||
1.0f, 1.0f, 0.0f, 1.0f, 1.0f,
|
1.0f, 1.0f, 0.0f, 1.0f, 1.0f,
|
||||||
1.0f, -1.0f, 0.0f, 1.0f, 0.0f,
|
1.0f, -1.0f, 0.0f, 1.0f, 0.0f,
|
||||||
};
|
};
|
||||||
// setup plane VAO
|
|
||||||
glGenVertexArrays(1, &quadVAO);
|
// setup plane VAO
|
||||||
glGenBuffers(1, &quadVBO);
|
|
||||||
glBindVertexArray(quadVAO);
|
glGenVertexArrays(1, &quadVAO);
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, quadVBO);
|
glGenBuffers(1, &quadVBO);
|
||||||
glBufferData(GL_ARRAY_BUFFER, sizeof(quadVertices), &quadVertices, GL_STATIC_DRAW);
|
|
||||||
glEnableVertexAttribArray(0);
|
glBindVertexArray(quadVAO);
|
||||||
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
|
glBindBuffer(GL_ARRAY_BUFFER, quadVBO);
|
||||||
glEnableVertexAttribArray(1);
|
|
||||||
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));
|
glBufferData(GL_ARRAY_BUFFER, sizeof(quadVertices), &quadVertices, GL_STATIC_DRAW);
|
||||||
}
|
|
||||||
glBindVertexArray(quadVAO);
|
glEnableVertexAttribArray(0);
|
||||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
|
||||||
glBindVertexArray(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)
|
void init_graphics(void *window)
|
||||||
{
|
{
|
||||||
window_ = 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");
|
// Compile the main shaders
|
||||||
unsigned int irradiance_convolution_program = compile_shader("assets/shaders/cubemap_vertex.glsl", "assets/shaders/irradiance_convolution_fragment.glsl");
|
shader_program = compile_shader(
|
||||||
background_program = compile_shader("assets/shaders/background_vertex.glsl", "assets/shaders/background_fragment.glsl");
|
"assets/shaders/vertex.glsl",
|
||||||
|
"assets/shaders/fragment.glsl");
|
||||||
|
|
||||||
{
|
// The program which calculates the shadow map
|
||||||
VertexArray vertices = make_sphere_mesh(0.5);
|
shadow_program = compile_shader(
|
||||||
mesh_buffers[MODEL_SPHERE-1] = create_gpu_mesh_buffer(vertices);
|
"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);
|
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();
|
glGenFramebuffers(1, &captureFBO);
|
||||||
mesh_buffers[MODEL_CUBE-1] = create_gpu_mesh_buffer(vertices);
|
glGenRenderbuffers(1, &captureRBO);
|
||||||
free(vertices.data);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
glBindFramebuffer(GL_FRAMEBUFFER, captureFBO);
|
||||||
glGenFramebuffers(1, &captureFBO);
|
glBindRenderbuffer(GL_RENDERBUFFER, captureRBO);
|
||||||
glGenRenderbuffers(1, &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);
|
stbi_set_flip_vertically_on_load(true);
|
||||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, 512, 512);
|
int width, height, nrComponents;
|
||||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, captureRBO);
|
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);
|
||||||
stbi_set_flip_vertically_on_load(true);
|
glBindTexture(GL_TEXTURE_2D, hdrTexture);
|
||||||
int width, height, nrComponents;
|
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
|
||||||
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);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
glBindTexture(GL_TEXTURE_2D, hdrTexture);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
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_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);
|
stbi_image_free(data);
|
||||||
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);
|
// 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
|
// pbr: convert HDR equirectangular environment map to cubemap equivalent
|
||||||
// ----------------------------------------------------------------------------------------------
|
// ----------------------------------------------------------------------
|
||||||
Matrix4 captureProjection = perspective_matrix(deg2rad(90.0f), 1.0f, 0.1f, 10.0f);
|
glUseProgram(equirectangular_to_cubemap_program);
|
||||||
Matrix4 captureViews[] = {
|
glUniform1i(glGetUniformLocation(equirectangular_to_cubemap_program, "equirectangularMap"), 0);
|
||||||
lookat_matrix((Vector3) {0.0f, 0.0f, 0.0f}, (Vector3) {1.0f, 0.0f, 0.0f}, (Vector3) {0.0f, -1.0f, 0.0f}),
|
glUniformMatrix4fv(glGetUniformLocation(equirectangular_to_cubemap_program, "projection"), 1, false, (float*) &captureProjection);
|
||||||
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
|
glActiveTexture(GL_TEXTURE0);
|
||||||
// ----------------------------------------------------------------------
|
glBindTexture(GL_TEXTURE_2D, hdrTexture);
|
||||||
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);
|
glViewport(0, 0, 512, 512); // don't forget to configure the viewport to the capture dimensions.
|
||||||
glBindTexture(GL_TEXTURE_2D, hdrTexture);
|
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.
|
renderCube();
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, captureFBO);
|
}
|
||||||
for (unsigned int i = 0; i < 6; ++i) {
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||||
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();
|
{
|
||||||
}
|
// pbr: create an irradiance cubemap, and re-scale capture FBO to irradiance scale.
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
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);
|
||||||
// pbr: create an irradiance cubemap, and re-scale capture FBO to irradiance scale.
|
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);
|
||||||
glGenTextures(1, &irradianceMap);
|
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
glBindTexture(GL_TEXTURE_CUBE_MAP, irradianceMap);
|
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
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);
|
|
||||||
|
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, captureFBO);
|
glBindFramebuffer(GL_FRAMEBUFFER, captureFBO);
|
||||||
glBindRenderbuffer(GL_RENDERBUFFER, captureRBO);
|
glBindRenderbuffer(GL_RENDERBUFFER, captureRBO);
|
||||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, 32, 32);
|
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, 32, 32);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
glUseProgram(irradiance_convolution_program);
|
glUseProgram(irradiance_convolution_program);
|
||||||
glUniform1i(glGetUniformLocation(irradiance_convolution_program, "environmentMap"), 0);
|
glUniform1i(glGetUniformLocation(irradiance_convolution_program, "environmentMap"), 0);
|
||||||
glUniformMatrix4fv(glGetUniformLocation(irradiance_convolution_program, "projection"), 1, GL_FALSE, (float*) &captureProjection);
|
glUniformMatrix4fv(glGetUniformLocation(irradiance_convolution_program, "projection"), 1, GL_FALSE, (float*) &captureProjection);
|
||||||
|
|
||||||
glActiveTexture(GL_TEXTURE0);
|
glActiveTexture(GL_TEXTURE0);
|
||||||
glBindTexture(GL_TEXTURE_CUBE_MAP, envCubemap);
|
glBindTexture(GL_TEXTURE_CUBE_MAP, envCubemap);
|
||||||
|
|
||||||
glViewport(0, 0, 32, 32); // don't forget to configure the viewport to the capture dimensions.
|
glViewport(0, 0, 32, 32); // don't forget to configure the viewport to the capture dimensions.
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, captureFBO);
|
glBindFramebuffer(GL_FRAMEBUFFER, captureFBO);
|
||||||
for (unsigned int i = 0; i < 6; ++i)
|
for (unsigned int i = 0; i < 6; ++i)
|
||||||
{
|
{
|
||||||
glUniformMatrix4fv(glGetUniformLocation(irradiance_convolution_program, "view"), 1, GL_FALSE, (float*) &captureViews[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);
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, irradianceMap, 0);
|
||||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
|
|
||||||
renderCube();
|
renderCube();
|
||||||
}
|
}
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
int w, h;
|
int w, h;
|
||||||
glfwGetWindowSize(window, &w, &h);
|
glfwGetWindowSize(window, &w, &h);
|
||||||
|
|
||||||
Matrix4 projection = perspective_matrix(deg2rad(30.0f), (float) w / (float) h, 0.1f, 100.0f);
|
Matrix4 projection = perspective_matrix(deg2rad(30.0f), (float) w / (float) h, 0.1f, 100.0f);
|
||||||
glUseProgram(background_program);
|
glUseProgram(background_program);
|
||||||
glUniformMatrix4fv(glGetUniformLocation(background_program, "projection"), 1, false, (float*) &projection);
|
glUniformMatrix4fv(glGetUniformLocation(background_program, "projection"), 1, false, (float*) &projection);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
glGenFramebuffers(1, &depth_map_fbo);
|
glGenFramebuffers(1, &depth_map_fbo);
|
||||||
|
|
||||||
glGenTextures(1, &depth_map);
|
glGenTextures(1, &depth_map);
|
||||||
glBindTexture(GL_TEXTURE_2D, 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);
|
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_MIN_FILTER, GL_NEAREST);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_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_S, GL_CLAMP_TO_BORDER);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
|
||||||
|
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, depth_map_fbo);
|
glBindFramebuffer(GL_FRAMEBUFFER, depth_map_fbo);
|
||||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth_map, 0);
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth_map, 0);
|
||||||
glDrawBuffer(GL_NONE);
|
glDrawBuffer(GL_NONE);
|
||||||
glReadBuffer(GL_NONE);
|
glReadBuffer(GL_NONE);
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
glGenTextures(1, &prefilterMap);
|
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_S, GL_CLAMP_TO_EDGE);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, 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_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);
|
glBindFramebuffer(GL_FRAMEBUFFER, captureFBO);
|
||||||
glBindRenderbuffer(GL_RENDERBUFFER, captureRBO);
|
glBindRenderbuffer(GL_RENDERBUFFER, captureRBO);
|
||||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, 512, 512);
|
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 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);
|
glEnable(GL_DEPTH_TEST);
|
||||||
glDepthFunc(GL_LEQUAL);
|
glDepthFunc(GL_LEQUAL);
|
||||||
|
|
||||||
//glEnable(GL_DEPTH_TEST);
|
|
||||||
//glEnable(GL_CULL_FACE);
|
|
||||||
//glCullFace(GL_BACK);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|||||||
+78
-66
@@ -11,23 +11,23 @@
|
|||||||
|
|
||||||
static void error_callback(int error, const char* description)
|
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)
|
static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
|
||||||
{
|
{
|
||||||
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
|
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
|
||||||
glfwSetWindowShouldClose(window, GLFW_TRUE);
|
glfwSetWindowShouldClose(window, GLFW_TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
|
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)
|
void cursor_pos_callback(GLFWwindow *window, double x, double y)
|
||||||
{
|
{
|
||||||
rotate_camera(x, y);
|
rotate_camera(x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@@ -41,85 +41,85 @@ typedef enum {
|
|||||||
} PieceType;
|
} PieceType;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
bool is_black;
|
bool is_black;
|
||||||
PieceType type;
|
PieceType type;
|
||||||
} Piece;
|
} Piece;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
Piece pieces[8][8];
|
Piece pieces[8][8];
|
||||||
} Board;
|
} Board;
|
||||||
|
|
||||||
void init_board(Board *board)
|
void init_board(Board *board)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < 8; i++)
|
for (int i = 0; i < 8; i++)
|
||||||
for (int j = 0; j < 8; j++) {
|
for (int j = 0; j < 8; j++) {
|
||||||
board->pieces[i][j] = (Piece) {false, PIECE_VOID};
|
board->pieces[i][j] = (Piece) {false, PIECE_VOID};
|
||||||
}
|
}
|
||||||
for (int i = 0; i < 8; i++) {
|
for (int i = 0; i < 8; i++) {
|
||||||
board->pieces[i][1] = (Piece) {true, PIECE_PAWN};
|
board->pieces[i][1] = (Piece) {true, PIECE_PAWN};
|
||||||
board->pieces[i][6] = (Piece) {false, PIECE_PAWN};
|
board->pieces[i][6] = (Piece) {false, PIECE_PAWN};
|
||||||
}
|
}
|
||||||
|
|
||||||
board->pieces[3][0] = (Piece) {true, PIECE_KING};
|
board->pieces[3][0] = (Piece) {true, PIECE_KING};
|
||||||
board->pieces[3][7] = (Piece) {false, PIECE_KING};
|
board->pieces[3][7] = (Piece) {false, PIECE_KING};
|
||||||
board->pieces[4][0] = (Piece) {true, PIECE_QUEEN};
|
board->pieces[4][0] = (Piece) {true, PIECE_QUEEN};
|
||||||
board->pieces[4][7] = (Piece) {false, PIECE_QUEEN};
|
board->pieces[4][7] = (Piece) {false, PIECE_QUEEN};
|
||||||
|
|
||||||
board->pieces[2][7] = (Piece) {false, PIECE_BISHOP};
|
board->pieces[2][7] = (Piece) {false, PIECE_BISHOP};
|
||||||
board->pieces[5][7] = (Piece) {false, PIECE_BISHOP};
|
board->pieces[5][7] = (Piece) {false, PIECE_BISHOP};
|
||||||
|
|
||||||
board->pieces[2][0] = (Piece) {true, PIECE_BISHOP};
|
board->pieces[2][0] = (Piece) {true, PIECE_BISHOP};
|
||||||
board->pieces[5][0] = (Piece) {true, PIECE_BISHOP};
|
board->pieces[5][0] = (Piece) {true, PIECE_BISHOP};
|
||||||
|
|
||||||
board->pieces[1][7] = (Piece) {false, PIECE_KNIGHT};
|
board->pieces[1][7] = (Piece) {false, PIECE_KNIGHT};
|
||||||
board->pieces[6][7] = (Piece) {false, PIECE_KNIGHT};
|
board->pieces[6][7] = (Piece) {false, PIECE_KNIGHT};
|
||||||
|
|
||||||
board->pieces[1][0] = (Piece) {true, PIECE_KNIGHT};
|
board->pieces[1][0] = (Piece) {true, PIECE_KNIGHT};
|
||||||
board->pieces[6][0] = (Piece) {true, PIECE_KNIGHT};
|
board->pieces[6][0] = (Piece) {true, PIECE_KNIGHT};
|
||||||
|
|
||||||
board->pieces[0][0] = (Piece) {true, PIECE_ROOK};
|
board->pieces[0][0] = (Piece) {true, PIECE_ROOK};
|
||||||
board->pieces[7][0] = (Piece) {true, PIECE_ROOK};
|
board->pieces[7][0] = (Piece) {true, PIECE_ROOK};
|
||||||
|
|
||||||
board->pieces[0][7] = (Piece) {false, PIECE_ROOK};
|
board->pieces[0][7] = (Piece) {false, PIECE_ROOK};
|
||||||
board->pieces[7][7] = (Piece) {false, PIECE_ROOK};
|
board->pieces[7][7] = (Piece) {false, PIECE_ROOK};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
board->pieces[3][4] = {false, PIECE_KING};
|
board->pieces[3][4] = {false, PIECE_KING};
|
||||||
board->pieces[4][5] = {false, PIECE_PAWN};
|
board->pieces[4][5] = {false, PIECE_PAWN};
|
||||||
board->pieces[4][6] = {false, PIECE_PAWN};
|
board->pieces[4][6] = {false, PIECE_PAWN};
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
glfwSetErrorCallback(error_callback);
|
glfwSetErrorCallback(error_callback);
|
||||||
|
|
||||||
if (!glfwInit())
|
if (!glfwInit())
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
||||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
|
||||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
||||||
|
|
||||||
GLFWwindow *window = glfwCreateWindow(2*640, 2*480, "3D Chess", NULL, NULL);
|
GLFWwindow *window = glfwCreateWindow(2*640, 2*480, "3D Chess", NULL, NULL);
|
||||||
if (!window) {
|
if (!window) {
|
||||||
glfwTerminate();
|
glfwTerminate();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
glfwSetKeyCallback(window, key_callback);
|
glfwSetKeyCallback(window, key_callback);
|
||||||
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
|
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
|
||||||
glfwSetCursorPosCallback(window, cursor_pos_callback);
|
glfwSetCursorPosCallback(window, cursor_pos_callback);
|
||||||
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
|
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
|
||||||
|
|
||||||
glfwMakeContextCurrent(window);
|
glfwMakeContextCurrent(window);
|
||||||
|
|
||||||
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
|
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
|
||||||
printf("Failed to initialize GLAD\n");
|
printf("Failed to initialize GLAD\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
glfwSwapInterval(1);
|
glfwSwapInterval(1);
|
||||||
|
|
||||||
init_graphics(window);
|
init_graphics(window);
|
||||||
|
|
||||||
@@ -139,7 +139,7 @@ int main(void)
|
|||||||
printf("Couldn't load model\n");
|
printf("Couldn't load model\n");
|
||||||
piece_models[i] = MODEL_SPHERE;
|
piece_models[i] = MODEL_SPHERE;
|
||||||
}
|
}
|
||||||
|
|
||||||
Board board;
|
Board board;
|
||||||
init_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);
|
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);
|
Material material = {.baseColor={1, 1, 1}, .metallic=1.0, .perceptualRoughness=0, .reflectance=0};
|
||||||
glfwPollEvents();
|
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();
|
Material material = {.baseColor={0, 0, 0}, .metallic=1.0, .perceptualRoughness=0, .reflectance=0};
|
||||||
return 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;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user