From f6ff671b416de2572416e2f7b1c5961428b294f1 Mon Sep 17 00:00:00 2001 From: shadow cat Date: Fri, 7 Jun 2024 17:31:44 -0400 Subject: [PATCH] global shadow --- src/client/render/voxel/pipeline.rs | 2 +- src/client/render/voxel/shader.wgsl | 103 ++++++++++++++++++++++++++-- 2 files changed, 99 insertions(+), 6 deletions(-) diff --git a/src/client/render/voxel/pipeline.rs b/src/client/render/voxel/pipeline.rs index bf9f6e9..0e4c891 100644 --- a/src/client/render/voxel/pipeline.rs +++ b/src/client/render/voxel/pipeline.rs @@ -211,7 +211,7 @@ impl VoxelPipeline { offset: offset2 as u32, }; let proj3 = Projective3::identity() - * Translation3::new(0.0, 0.0, 10.0) + * Translation3::new(0.0, 0.0, 16.5) * Rotation3::from_axis_angle(&Vector3::y_axis(), std::f32::consts::PI / 4.0) * Rotation3::from_axis_angle( &UnitVector3::new_normalize(Vector3::new(1.0, 0.0, 1.0)), diff --git a/src/client/render/voxel/shader.wgsl b/src/client/render/voxel/shader.wgsl index 5565848..0d387be 100644 --- a/src/client/render/voxel/shader.wgsl +++ b/src/client/render/voxel/shader.wgsl @@ -75,13 +75,13 @@ const DEPTH = 20; const FULL_ALPHA = 0.9999; const GLOBAL_LIGHT = vec3(-0.5, -4.0, 2.0); -fn trace_full(pos_view: vec4, dir_view: vec4) -> vec4 { +fn trace_full(pos: vec4, dir: vec4) -> vec4 { // GPUs hate this var depths = array(); var colors = array(); for (var gi: u32 = 0; gi < arrayLength(&voxel_groups); gi = gi + 1) { - apply_group(gi, pos_view, dir_view, &depths, &colors); + apply_group(gi, pos, dir, &depths, &colors); } var color = vec4(0.0); for (var di = 0; di < DEPTH; di += 1) { @@ -181,7 +181,7 @@ fn apply_group( // hit a voxel if vcolor.a > 0.0 { let full_t = t_offset + prev_t; - // skip closer depth hits, or completely if behind opaque + // skip closer depth hits, or finish if behind opaque var a = unpack4x8unorm((*colors)[depth]).a; while (*depths)[depth] < full_t && a != 0.0 { alpha += (1.0 - alpha) * a; @@ -198,9 +198,21 @@ fn apply_group( (*depths)[move_d + 1] = (*depths)[move_d]; move_d += 1; } + let full_pos = pos_view + dir_view * full_t; + + // lighting + let shadow = trace_light(full_pos); + let diffuse = max(dot(norm_light, normal) * 1.3 + 0.1, 0.0); + let ambient = 0.2; + let specular = (exp(max( + -(dot(reflect(dir_view.xyz, normal), norm_light) + 0.90) * 4.0, 0.0 + )) - 1.0) * shadow; + let lighting = max(diffuse, ambient) * shadow; + let new_rgb = min(vcolor.xyz * lighting + vec3(specular), vec3(1.0)); + let new_a = min(vcolor.a + specular, 1.0); + let color = vec4(new_rgb, new_a); + // add hit - let light = max(dot(norm_light, normal) * 1.3 + 0.1, 0.1); - var color = vec4(vcolor.xyz * light, vcolor.a); (*depths)[depth] = full_t; (*colors)[depth] = pack4x8unorm(color); prev_a = vcolor.a; @@ -214,6 +226,87 @@ fn apply_group( } } +fn trace_light( + pos: vec4 +) -> f32 { + let dir = vec4(-normalize(GLOBAL_LIGHT), 0.0); + var mask = 1.0; + let start = pos + dir * .001; + for (var gi: u32 = 0; gi < arrayLength(&voxel_groups); gi = gi + 1) { + let color = trace_one(gi, start, dir); + mask -= mask * color.a; + if mask <= .0001 { + return mask; + } + } + return mask; +} + +fn trace_one(gi: u32, pos_view: vec4, dir_view: vec4) -> vec4 { + let group = voxel_groups[gi]; + let dim_f = vec3(group.dimensions); + let dim_i = vec3(group.dimensions); + + // transform so that group is at 0,0 + var pos = (group.transform_inv * pos_view).xyz; + let dir = (group.transform_inv * dir_view).xyz; + + let dir_if = sign(dir); + + + + // find where ray intersects with group + let plane_point = (vec3(1.0) - dir_if) / 2.0 * dim_f; + var t_offset = 0.0; + if outside3f(pos, ZERO3F, dim_f) { + // time of intersection; x = td + p, solve for t + let t_i = (plane_point - pos) / dir; + // points of intersection + let px = pos + t_i.x * dir; + let py = pos + t_i.y * dir; + let pz = pos + t_i.z * dir; + + // check if point is in bounds + let hit = vec3( + inside2f(px.yz, ZERO2F, dim_f.yz), + inside2f(py.xz, ZERO2F, dim_f.xz), + inside2f(pz.xy, ZERO2F, dim_f.xy), + ) && (t_i > ZERO3F); + if !any(hit) { + return vec4(0.0); + } + pos = select(select(pz, py, hit.y), px, hit.x); + t_offset = select(select(t_i.z, t_i.y, hit.y), t_i.x, hit.x); + } + var vox_pos = clamp(vec3(pos), vec3(0), dim_i - vec3(1)); + + + + let dir_i = vec3(dir_if); + // time to move 1 unit using dir + let inc_t = abs(1.0 / dir); + let corner = vec3(vox_pos) + vec3(0.5) + dir_if / 2.0; + + // time of next plane hit for each direction + var next_t = inc_t * abs(pos - corner); + var color = vec4(0.0); + loop { + let i = u32(vox_pos.x + vox_pos.y * dim_i.x + vox_pos.z * dim_i.x * dim_i.y) + group.offset; + var vcolor = unpack4x8unorm(voxels[i]); + + // select next voxel to move to next based on least time + let axis = select(select(2, 1, next_t.y < next_t.z), 0, next_t.x < next_t.y && next_t.x < next_t.z); + vox_pos[axis] += dir_i[axis]; + next_t[axis] += inc_t[axis]; + color += vec4(vcolor.xyz * vcolor.a * (1.0 - color.a), (1.0 - color.a) * vcolor.a); + + if color.a >= FULL_ALPHA || vox_pos[axis] < 0 || vox_pos[axis] >= dim_i[axis] { + break; + } + } + return color; +} + fn outside3f(v: vec3, low: vec3, high: vec3) -> bool { return any(v < low) || any(v > high); }