polyadvent

A game engine from scratch in C
git clone git://jb55.com/polyadvent
Log | Files | Refs | README

commit 635d96fefc2ed50d991870ccdd8d17552ec5cc1d
parent 95ef741994e05f68b7ce23885be1d7e8fda5a090
Author: William Casarin <jb55@jb55.com>
Date:   Mon, 12 Nov 2018 18:53:09 -0800

refactor pbr a bit

Diffstat:
Metc/shaders/lighting.glsl | 88+------------------------------------------------------------------------------
Aetc/shaders/pbr.glsl | 89+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Metc/shaders/shadows.glsl | 2+-
Msrc/update.c | 18++++++++++--------
4 files changed, 101 insertions(+), 96 deletions(-)

diff --git a/etc/shaders/lighting.glsl b/etc/shaders/lighting.glsl @@ -85,91 +85,5 @@ vec3 standard_light(vec3 color, vec4 position, vec4 normal) { return final; } -float dist_ggx(vec3 N, vec3 H, float roughness) -{ - float a = roughness * roughness; - float NdotH = max(dot(N, H), 0.0); - float NdotH2 = NdotH*NdotH; - float num = a; - float denom = (NdotH2 * (a - 1.0) + 1.0); - denom = PI * denom * denom; - - return num / denom; -} - - -float geom_schlick_ggx(float NdotV, float roughness) -{ - float r = (roughness + 1.0); - float k = (r*r) / 8.0; - - float num = NdotV; - float denom = NdotV * (1.0 - k) + k; - - return num / denom; -} - -float geom_smith(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 ggx1 = geom_schlick_ggx(NdotV, roughness); - float ggx2 = geom_schlick_ggx(NdotL, roughness); - - return ggx1 * ggx2; -} - -vec3 fresnel_schlick(float cos_theta, vec3 F0) -{ - return F0 + (1.0 - F0) * pow(1.0 - cos_theta, 5.0); -} - -vec3 pbr(vec3 albedo, vec3 V, vec3 normal) { - const float ao = 5.0; - const float metallic = 0.6; - const float roughness = 0.4; - vec3 radiance = sun_color * light_intensity; - // radiance += texture(skybox, vec3(0.0, 0.0, 1.0)).rgb; - vec3 N = normalize(normal); - vec3 L = normalize(light_dir); - vec3 H = normalize(V + L); - // non-metallic is always 0.04 - vec3 F0 = vec3(0.04); - // while we do vary F0 based on the metalness of a surface by linearly - // interpolating between the original F0 and the albedo value given the - // metallic property - F0 = mix(F0, albedo, metallic); - float HdotV = max(0.0, dot(H, V)); - vec3 F = fresnel_schlick(HdotV, F0); - float NDF = dist_ggx(N, H, roughness); - float G = geom_smith(N, V, L, roughness); - - float NdotL = max(0.0, dot(N, L)); - - // Cook-Torrance BRDF - vec3 numerator = NDF * G * F; - float denominator = 4.0 * max(0.0, dot(N, V)) * NdotL; - vec3 specular = numerator / max(denominator, 0.001); - - // kS = energy of light that gets reflected - // kD = remaining energy that gets refracted - vec3 kS = F; - vec3 kD = vec3(1.0) - kS; - kD *= 1.0 - metallic; - - // because metallic surfaces don't refract light and thus have no diffuse - // reflections we enforce this property by nullifying kD if the surface is - // metallic - - // Lo = outgoing radiance - // the result of the reflectance equation's integral ∫ over Ω - vec3 Lo = (kD * albedo / PI + specular) * radiance * NdotL; - - vec3 ambient = vec3(0.03) * albedo * ao; - vec3 color = ambient + Lo; - // color = uncharted_tonemap(color); - //color = color / (vec3(1.0) + color); - - return color; -} +#include pbr.glsl diff --git a/etc/shaders/pbr.glsl b/etc/shaders/pbr.glsl @@ -0,0 +1,89 @@ + +float dist_ggx(vec3 N, vec3 H, float roughness) +{ + float a = roughness * roughness; + float NdotH = max(dot(N, H), 0.0); + float NdotH2 = NdotH*NdotH; + + float num = a; + float denom = (NdotH2 * (a - 1.0) + 1.0); + denom = PI * denom * denom; + + return num / denom; +} + + +float geom_schlick_ggx(float NdotV, float roughness) +{ + float r = (roughness + 1.0); + float k = (r*r) / 8.0; + + float num = NdotV; + float denom = NdotV * (1.0 - k) + k; + + return num / denom; +} + +float geom_smith(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 ggx1 = geom_schlick_ggx(NdotV, roughness); + float ggx2 = geom_schlick_ggx(NdotL, roughness); + + return ggx1 * ggx2; +} + +vec3 fresnel_schlick(float cos_theta, vec3 F0) +{ + return F0 + (1.0 - F0) * pow(1.0 - cos_theta, 5.0); +} + +vec3 pbr(vec3 albedo, vec3 V, vec3 normal) { + const float ao = 5.0; + const float metallic = 0.6; + const float roughness = 0.4; + vec3 radiance = sun_color * light_intensity; + // radiance += texture(skybox, vec3(0.0, 0.0, 1.0)).rgb; + vec3 N = normalize(normal); + vec3 L = normalize(light_dir); + vec3 H = normalize(V + L); + // non-metallic is always 0.04 + vec3 F0 = vec3(0.04); + // while we do vary F0 based on the metalness of a surface by linearly + // interpolating between the original F0 and the albedo value given the + // metallic property + F0 = mix(F0, albedo, metallic); + float HdotV = max(0.0, dot(H, V)); + vec3 F = fresnel_schlick(HdotV, F0); + float NDF = dist_ggx(N, H, roughness); + float G = geom_smith(N, V, L, roughness); + + float NdotL = max(0.0, dot(N, L)); + + // Cook-Torrance BRDF + vec3 numerator = NDF * G * F; + float denominator = 4.0 * max(0.0, dot(N, V)) * NdotL; + vec3 specular = numerator / max(denominator, 0.001); + + // kS = energy of light that gets reflected + // kD = remaining energy that gets refracted + vec3 kS = F; + vec3 kD = vec3(1.0) - kS; + kD *= 1.0 - metallic; + + // because metallic surfaces don't refract light and thus have no diffuse + // reflections we enforce this property by nullifying kD if the surface is + // metallic + + // Lo = outgoing radiance + // the result of the reflectance equation's integral ∫ over Ω + vec3 Lo = (kD * albedo / PI + specular) * radiance * NdotL; + + vec3 ambient = vec3(0.03) * albedo * ao; + vec3 color = ambient + Lo; + // color = uncharted_tonemap(color); + //color = color / (vec3(1.0) + color); + + return color; +} diff --git a/etc/shaders/shadows.glsl b/etc/shaders/shadows.glsl @@ -11,7 +11,7 @@ vec3 shadow_strength(vec4 position, vec4 normal, vec4 v_shadow_coord) { vec4 shadow_sample = texture(shadow_map, v_shadow_coord.xy); - float bias = 0.002; + float bias = 0.0002; bool in_shadow = shadow_sample.z < v_shadow_coord.z - bias && shadow_sample.y < 1.0; diff --git a/src/update.c b/src/update.c @@ -191,14 +191,14 @@ void resize_fbos(struct entity *player, struct fbo *shadow_buffer, } // TODO: compute better bounds based - const float factor = 80.0; + const float factor = 1.5; float left = player->model.geom.min[0] - factor; float right = player->model.geom.max[0] + factor; float bottom = player->model.geom.min[1] - factor; - float top = player->model.geom.max[1] + factor; + float top = player->model.geom.max[1] + factor/2.0; - const float near = -80.0; - const float far = 80.0; + const float near = -1.0; + const float far = 5.0; // default ortho screenspace projection mat4_ortho(left, right, bottom, top, near, far, m4_ortho); @@ -220,7 +220,7 @@ void resize_fbos(struct entity *player, struct fbo *shadow_buffer, // TODO: match based on some real concept of time static void day_night_cycle(float time, struct resources *res) { float val = time * 0.0001; - float intensity = max(0.0, vec3_dot(res->light_dir, V3(0.0, 0.0, 0.8))); + float intensity = 1.0;//max(0.0, vec3_dot(res->light_dir, V3(0.0, 0.0, 1.0))); */ struct entity *player = get_player(res); float light_pos[3]; @@ -246,8 +246,10 @@ static void day_night_cycle(float time, struct resources *res) { /* vec3_normalize(res->light_intensity, res->light_intensity); */ res->light_dir[0] = 0.0; - res->light_dir[1] = sin(val); - res->light_dir[2] = cos(val) + 1.0; + /* res->light_dir[1] = sin(val); */ + /* res->light_dir[2] = cos(val) + 1.0; */ + res->light_dir[1] = 0.8; + res->light_dir[2] = 0.8; vec3_normalize(res->light_dir, res->light_dir); @@ -320,7 +322,7 @@ static void orbit_keep_above_ground(struct game *game) { float cam_terrain_z = game->terrain.fn(&game->terrain, camera_world[0], camera_world[1]); - const float bias = 5.0; + const float bias = 2.0; if (camera_world[2] < cam_terrain_z + bias) camera_world[2] = cam_terrain_z + bias;