From 603bd98516421a5a05ac60be67fc635f23666fd2 Mon Sep 17 00:00:00 2001 From: luboslenco Date: Tue, 25 Aug 2026 21:24:57 +0200 Subject: [PATCH] paint: light fixes --- paint/assets/World_irradiance.arm | Bin 134 -> 134 bytes paint/shaders/deferred_light.kong | 63 +++++++++-------- paint/sources/io/import_envmap.c | 82 ++++++++++------------- paint/sources/render/make_mesh.c | 27 ++++---- paint/sources/render/render_envsphere.c | 8 +-- paint/sources/render/render_pathsphere.c | 8 +-- 6 files changed, 94 insertions(+), 94 deletions(-) diff --git a/paint/assets/World_irradiance.arm b/paint/assets/World_irradiance.arm index 0455dd01bf7207178827af29a49d302a78b15a10..5b43ef6bb2fedf967fab5bab47b0ebaca0c5a7eb 100644 GIT binary patch delta 115 zcmV-(0F3{J0fqsP8f+~b)ISvD-ao`I=s)nDK0esoIX(-6D?Z)lk3TRnoIkDNtUoN( zuRi$Y$3Bvt;67IHd_9Axbv>3=P(4-J4L%It7d~+aBR;-^k3Q|Ki$3k^b2tB>!>O9r}CA>+XLA(cjX}oSyQ9QuvNId51M?7M@CcRrgD7}x4E4`IroV}_j Vp1t8kpS?C6VLnTEVm^9OW28 - f32 accum = 0.0; - f32 weight = 1.0; - f32 weight1 = weight * 4 / 17.0; - f32 weight2 = weight * 8 / 17.0; - f32 weight3 = weight * 15 / 17.0; - f32 weight4 = weight * 5 / 68.0; - f32 weight5 = weight * 15 / 68.0; - - for (i32 x = 0; x < source_width; ++x) { - for (i32 y = 0; y < source_height; ++y) { - import_envmap_n = import_envmap_reverse_equirect(x / (float)source_width, y / (float)source_height); - - for (i32 i = 0; i < 3; ++i) { - f32 value = buffer_get_f16(source, ((x + y * source_width) * 8 + i * 2)); - value = math_pow(value, 1.0 / 2.2); - - sh->buffer[0 + i] += value * weight1; - sh->buffer[3 + i] += value * weight2 * import_envmap_n.x; - sh->buffer[6 + i] += value * weight2 * import_envmap_n.y; - sh->buffer[9 + i] += value * weight2 * import_envmap_n.z; - - sh->buffer[12 + i] += value * weight3 * import_envmap_n.x * import_envmap_n.z; - sh->buffer[15 + i] += value * weight3 * import_envmap_n.z * import_envmap_n.y; - sh->buffer[18 + i] += value * weight3 * import_envmap_n.y * import_envmap_n.x; - - sh->buffer[21 + i] += value * weight4 * (3.0 * import_envmap_n.z * import_envmap_n.z - 1.0); - sh->buffer[24 + i] += value * weight5 * (import_envmap_n.x * import_envmap_n.x - import_envmap_n.y * import_envmap_n.y); - - accum += weight; - } - } + f32_array_t *sh = f32_array_create(9 * 3 + 1); // Align to mult of 4 - 27->28 + for (i32 i = 0; i < sh->length; ++i) { + sh->buffer[i] = 0.0f; } - for (i32 i = 0; i < sh->length; ++i) { - sh->buffer[i] /= accum / 16.0; + f32 dtheta = math_pi() * 2.0f / (f32)source_width; + f32 dphi = math_pi() / (f32)source_height; + + for (i32 y = 0; y < source_height; ++y) { + f32 phi = (y + 0.5f) * dphi; + f32 sin_phi = math_sin(phi); + f32 cos_phi = math_cos(phi); + f32 domega = sin_phi * dtheta * dphi; + + for (i32 x = 0; x < source_width; ++x) { + f32 theta = (x + 0.5f) * dtheta - math_pi(); + f32 nx = sin_phi * math_cos(theta); + f32 ny = -(sin_phi * math_sin(theta)); + f32 nz = cos_phi; + + // Y00, Y1-1, Y10, Y11, Y2-2, Y2-1, Y20, Y21, Y22 + f32 basis[9]; + basis[0] = 0.282095f; + basis[1] = 0.488603f * ny; + basis[2] = 0.488603f * nz; + basis[3] = 0.488603f * nx; + basis[4] = 1.092548f * nx * ny; + basis[5] = 1.092548f * ny * nz; + basis[6] = 0.315392f * (3.0f * nz * nz - 1.0f); + basis[7] = 1.092548f * nx * nz; + basis[8] = 0.546274f * (nx * nx - ny * ny); + + for (i32 i = 0; i < 3; ++i) { + f32 value = buffer_get_f16(source, ((x + y * source_width) * 8 + i * 2)) * domega; + for (i32 j = 0; j < 9; ++j) { + sh->buffer[j * 3 + i] += value * basis[j]; + } + } + } } return sh; diff --git a/paint/sources/render/make_mesh.c b/paint/sources/render/make_mesh.c index 7d1e2d86..6e8a763e 100644 --- a/paint/sources/render/make_mesh.c +++ b/paint/sources/render/make_mesh.c @@ -18,16 +18,16 @@ fun sh_irradiance(nor: float3): float3 { \ var cl21: float3 = float3(constants.shirr5.y, constants.shirr5.z, constants.shirr5.w); \ var cl22: float3 = float3(constants.shirr6.x, constants.shirr6.y, constants.shirr6.z); \ return ( \ - cl22 * c1 * (nor.y * nor.y - (-nor.z) * (-nor.z)) + \ - cl20 * c3 * nor.x * nor.x + \ + cl22 * c1 * (nor.x * nor.x - nor.y * nor.y) + \ + cl20 * c3 * nor.z * nor.z + \ cl00 * c4 - \ cl20 * c5 + \ - cl2m2 * 2.0 * c1 * nor.y * (-nor.z) + \ - cl21 * 2.0 * c1 * nor.y * nor.x + \ - cl2m1 * 2.0 * c1 * (-nor.z) * nor.x + \ - cl11 * 2.0 * c2 * nor.y + \ - cl1m1 * 2.0 * c2 * (-nor.z) + \ - cl10 * 2.0 * c2 * nor.x \ + cl2m2 * 2.0 * c1 * nor.x * nor.y + \ + cl21 * 2.0 * c1 * nor.x * nor.z + \ + cl2m1 * 2.0 * c1 * nor.y * nor.z + \ + cl11 * 2.0 * c2 * nor.x + \ + cl1m1 * 2.0 * c2 * nor.y + \ + cl10 * 2.0 * c2 * nor.z \ ); \ } \ "; @@ -494,7 +494,9 @@ node_shader_context_t *make_mesh_run(material_t *data, i32 layer_pass) { node_shader_write_frag(kong, "var albedo: float3 = lerp3(basecol, float3(0.0, 0.0, 0.0), metallic);"); node_shader_write_frag(kong, "var f0: float3 = lerp3(float3(0.04, 0.04, 0.04), basecol, metallic);"); kong->frag_vvec = true; - node_shader_write_frag(kong, "var dotnv: float = max(0.0, dot(n, vvec));"); + node_shader_write_frag(kong, "var dotnv: float = dot(n, vvec);"); + node_shader_write_frag(kong, "if (dotnv < 0.05) { n = normalize(n + vvec * (0.05 - dotnv)); dotnv = dot(n, vvec); }"); + node_shader_write_frag(kong, "dotnv = max(0.0001, dotnv);"); // node_shader_add_constant(kong, "envmap_num_mipmaps: int", "_envmap_num_mipmaps"); node_shader_add_constant(kong, "envmap_data: float4", "_envmap_data"); // angle, sin(angle), cos(angle), strength node_shader_write_frag(kong, "var wreflect: float3 = reflect(-vvec, n);"); @@ -522,11 +524,12 @@ node_shader_context_t *make_mesh_run(material_t *data, i32 layer_pass) { node_shader_add_constant(kong, "shirr5: float4", "_envmap_irradiance5"); node_shader_add_constant(kong, "shirr6: float4", "_envmap_irradiance6"); node_shader_add_function(kong, str_sh_irradiance); - node_shader_write_frag(kong, "var indirect: float3 = albedo * (sh_irradiance(float3(n.x * constants.envmap_data.z - n.y * " - "constants.envmap_data.y, n.x * constants.envmap_data.y + n.y * constants.envmap_data.z, n.z)) / 3.14159265);"); + node_shader_write_frag(kong, "var indirect: float3 = albedo * (sh_irradiance(float3(n.x * constants.envmap_data.z + n.y * " + "constants.envmap_data.y, n.y * constants.envmap_data.z - n.x * constants.envmap_data.y, n.z)) / 3.14159265);"); node_shader_add_function(kong, str_env_brdf_approx); + node_shader_write_frag(kong, "indirect = indirect * occlusion;"); node_shader_write_frag(kong, "indirect = indirect + prefiltered_color * env_brdf_approx(f0, roughness, dotnv) * 0.5;"); - node_shader_write_frag(kong, "indirect = indirect * constants.envmap_data.w * occlusion;"); + node_shader_write_frag(kong, "indirect = indirect * constants.envmap_data.w * 0.5;"); node_shader_write_frag(kong, "indirect = max3(indirect, float3(0.0, 0.0, 0.0));"); node_shader_write_frag(kong, "output[1] = float4(indirect, 1.0);"); } diff --git a/paint/sources/render/render_envsphere.c b/paint/sources/render/render_envsphere.c index 72e1f455..7ef56cec 100644 --- a/paint/sources/render/render_envsphere.c +++ b/paint/sources/render/render_envsphere.c @@ -76,10 +76,10 @@ static node_shader_context_t *make_envsphere_shader(char *name, f32 roughness, f node_shader_write_frag(kong, "var lodc1: float3 = envmap_sample(lod1, envmap_coord);"); node_shader_write_frag(kong, "var prefiltered_color: float3 = lerp3(lodc0, lodc1, lodf);"); // Rotate normal by envmap angle for irradiance - node_shader_write_frag(kong, "var indirect: float3 = albedo * (sh_irradiance(float3(n.x * constants.envmap_data.z - n.y * constants.envmap_data.y, n.x * " - "constants.envmap_data.y + n.y * constants.envmap_data.z, n.z)) / 3.14159265);"); - node_shader_write_frag(kong, "indirect = indirect + prefiltered_color * env_brdf_approx(f0, roughness, dotnv) * 0.5;"); - node_shader_write_frag(kong, "indirect = indirect * constants.envmap_data.w;"); + node_shader_write_frag(kong, "var indirect: float3 = albedo * (sh_irradiance(float3(n.x * constants.envmap_data.z + n.y * constants.envmap_data.y, n.y * " + "constants.envmap_data.z - n.x * constants.envmap_data.y, n.z)) / 3.14159265);"); + node_shader_write_frag(kong, "indirect = indirect + prefiltered_color * env_brdf_approx(f0, roughness, dotnv);"); + node_shader_write_frag(kong, "indirect = indirect * constants.envmap_data.w * 0.5;"); node_shader_write_frag(kong, "indirect = max3(indirect, float3(0.0, 0.0, 0.0));"); // Filmic tone-mapping (matches compositor_pass) diff --git a/paint/sources/render/render_pathsphere.c b/paint/sources/render/render_pathsphere.c index 1a2d99d3..5fb2f897 100644 --- a/paint/sources/render/render_pathsphere.c +++ b/paint/sources/render/render_pathsphere.c @@ -75,10 +75,10 @@ static node_shader_context_t *make_pathsphere_shader(char *name) { node_shader_write_frag(kong, "var lodc1: float3 = envmap_sample(lod1, envmap_coord);"); node_shader_write_frag(kong, "var prefiltered_color: float3 = lerp3(lodc0, lodc1, lodf);"); // Rotate normal by envmap angle for irradiance - node_shader_write_frag(kong, "var indirect: float3 = albedo * (sh_irradiance(float3(n.x * constants.envmap_data.z - n.y * constants.envmap_data.y, n.x * " - "constants.envmap_data.y + n.y * constants.envmap_data.z, n.z)) / 3.14159265);"); - node_shader_write_frag(kong, "indirect = indirect + prefiltered_color * env_brdf_approx(f0, roughness, dotnv) * 0.5;"); - node_shader_write_frag(kong, "indirect = indirect * constants.envmap_data.w;"); + node_shader_write_frag(kong, "var indirect: float3 = albedo * (sh_irradiance(float3(n.x * constants.envmap_data.z + n.y * constants.envmap_data.y, n.y * " + "constants.envmap_data.z - n.x * constants.envmap_data.y, n.z)) / 3.14159265);"); + node_shader_write_frag(kong, "indirect = indirect + prefiltered_color * env_brdf_approx(f0, roughness, dotnv);"); + node_shader_write_frag(kong, "indirect = indirect * constants.envmap_data.w * 0.5;"); node_shader_write_frag(kong, "indirect = max3(indirect, float3(0.0, 0.0, 0.0));"); // Filmic tone-mapping (matches compositor_pass)