diff --git a/src/client/render/voxel/pipeline.rs b/src/client/render/voxel/pipeline.rs index 8479ded..fcfceb4 100644 --- a/src/client/render/voxel/pipeline.rs +++ b/src/client/render/voxel/pipeline.rs @@ -182,7 +182,7 @@ impl VoxelPipeline { dimensions: Vector3::new(lx as u32, ly as u32, lz as u32), offset: 0, }; - let thing2 = Translation3::new(0.0, -10.0, 20.0) + let thing2 = Translation3::new(0.0, 2.5, 20.0) * Translation3::new( -(lx2 as f32 / 2.0), -(ly2 as f32 / 2.0), diff --git a/src/client/render/voxel/shader.wgsl b/src/client/render/voxel/shader.wgsl index 3f0326b..09db6a7 100644 --- a/src/client/render/voxel/shader.wgsl +++ b/src/client/render/voxel/shader.wgsl @@ -47,6 +47,7 @@ fn vs_main( const ZERO3F = vec3(0.0); const ZERO2F = vec2(0.0); const DEPTH = 20; +const FULL_ALPHA = 0.9999; @fragment fn fs_main( @@ -57,35 +58,186 @@ fn fs_main( let aspect = win_dim.y / win_dim.x; let pixel_pos = vec3( (in.clip_position.xy / win_dim - vec2(0.5)) * vec2(2.0, -2.0 * aspect), - 1.0 + 0.0 ); // move to position in world - let dir_view = view.transform * vec4(normalize(pixel_pos), 0.0); + let dir_view = view.transform * vec4(normalize(pixel_pos + vec3(0.0, 0.0, 1.0)), 0.0); let pos_view = view.transform * vec4(pixel_pos, 1.0); + return trace_full(pos_view, dir_view); +} + +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 * pos_view).xyz; + let dir = (group.transform * 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 trace_first(pos_view: vec4, dir_view: vec4) -> vec4 { + var depth = 9999999999999.0; + var result = vec4(0.0); + for (var gi: u32 = 0; gi < arrayLength(&voxel_groups); gi = gi + 1) { + 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 * pos_view).xyz; + let dir = (group.transform * 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) { + continue; + } + 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 t = 0.0; + var prev_t = t; + var color = vec4(0.0); + var gdepth = 9999999999999.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); + prev_t = t; + t = next_t[axis]; + vox_pos[axis] += dir_i[axis]; + next_t[axis] += inc_t[axis]; + + // hit a voxel + if vcolor.a > 0.0 { + let full_t = t_offset + prev_t; + gdepth = min(gdepth, full_t); + 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; + } + } + result = select(result, color, gdepth < depth); + depth = min(gdepth, depth); + } + return result; +} + +fn trace_full(pos_view: vec4, dir_view: vec4) -> vec4 { + // GPUs hate this var depths = array(); - var colors = array,DEPTH>(); + var colors = array(); for (var gi: u32 = 0; gi < arrayLength(&voxel_groups); gi = gi + 1) { - draw_group(gi, pos_view, dir_view, &depths, &colors); + apply_group(gi, pos_view, dir_view, &depths, &colors); } var color = vec4(0.0); - for(var di = 0; di < DEPTH; di += 1) { - // p sure if it can't unroll colors the performance dies; switch to buffer - let vcolor = colors[di]; + for (var di = 0; di < DEPTH; di += 1) { + let vcolor = unpack4x8unorm(colors[di]); color += vec4(vcolor.xyz * vcolor.a * (1.0 - color.a), (1.0 - color.a) * vcolor.a); - if vcolor.a == 0.0 || color.a >= 0.99999 { + if vcolor.a == 0.0 || color.a >= FULL_ALPHA { return color; } } return color; } -fn draw_group( +fn apply_group( gi: u32, pos_view: vec4, dir_view: vec4, depths: ptr>, - colors: ptr,DEPTH>>, + colors: ptr>, ) { let group = voxel_groups[gi]; let dim_f = vec3(group.dimensions); @@ -134,14 +286,11 @@ fn draw_group( // time of next plane hit for each direction var next_t = inc_t * abs(pos - corner); var alpha = 0.0; - var safety = 0; var t = 0.0; var prev_t = t; var depth = 0; + var prev_a = 0.0; loop { - // should prolly remove when gaming - safety += 1; - 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]); @@ -156,29 +305,31 @@ fn draw_group( if vcolor.a > 0.0 { let full_t = t_offset + prev_t; // skip closer depth hits, or completely if behind opaque - while (*depths)[depth] < full_t && (*colors)[depth].a != 0.0 { - depth += 1; - if depth >= DEPTH || (*colors)[depth].a == 1.0 { + var a = unpack4x8unorm((*colors)[depth]).a; + while (*depths)[depth] < full_t && a != 0.0 { + alpha += (1.0 - alpha) * a; + if depth + 1 >= DEPTH || alpha >= FULL_ALPHA { return; } + depth += 1; + a = unpack4x8unorm((*colors)[depth]).a; } var move_d = depth; // move further depth hits back - while move_d < DEPTH - 1 && (*colors)[move_d].a != 0.0 { + while move_d < DEPTH - 1 && unpack4x8unorm((*colors)[move_d]).a != 0.0 { (*colors)[move_d + 1] = (*colors)[move_d]; (*depths)[move_d + 1] = (*depths)[move_d]; move_d += 1; } // add hit (*depths)[depth] = full_t; - (*colors)[depth] = vcolor; + (*colors)[depth] = voxels[i]; + prev_a = vcolor.a; depth += 1; alpha += (1.0 - alpha) * vcolor.a; } - if alpha >= 0.9999 || depth >= DEPTH - || vox_pos[axis] < 0 || vox_pos[axis] >= dim_i[axis] - || safety > 1000 { + if alpha >= FULL_ALPHA || depth >= DEPTH || vox_pos[axis] < 0 || vox_pos[axis] >= dim_i[axis] { return; } } diff --git a/src/client/render/voxel/shader_stuff.wgsl b/src/client/render/voxel/shader_stuff.wgsl new file mode 100644 index 0000000..4717f8c --- /dev/null +++ b/src/client/render/voxel/shader_stuff.wgsl @@ -0,0 +1,115 @@ +fn trace_first(pos_view: vec4, dir_view: vec4) -> vec4 { + var depth = 9999999999999.0; + var result = vec4(0.0); + + var group: VoxelGroup; + var dim_f: vec3; + var dim_i: vec3; + var pos: vec3; + var dir: vec3; + var dir_if: vec3; + + var plane_point: vec3; + var t_offset: f32; + var t_i: vec3; + var px: vec3; + var py: vec3; + var pz: vec3; + var hit: vec3; + var vox_pos: vec3; + + var dir_i: vec3; + var inc_t: vec3; + var corner: vec3; + var next_t: vec3; + var t: f32; + var prev_t: f32; + var color: vec4; + var gdepth: f32; + var i: u32; + var vcolor: vec4; + var axis: i32; + var full_t: f32; + + for (var gi: u32 = 0; gi < arrayLength(&voxel_groups); gi = gi + 1) { + group = voxel_groups[gi]; + dim_f = vec3(group.dimensions); + dim_i = vec3(group.dimensions); + + // transform so that group is at 0,0 + pos = (group.transform * pos_view).xyz; + dir = (group.transform * dir_view).xyz; + + dir_if = sign(dir); + + + + // find where ray intersects with group + plane_point = (vec3(1.0) - dir_if) / 2.0 * dim_f; + t_offset = 0.0; + if outside3f(pos, ZERO3F, dim_f) { + // time of intersection; x = td + p, solve for t + t_i = (plane_point - pos) / dir; + // points of intersection + px = pos + t_i.x * dir; + py = pos + t_i.y * dir; + pz = pos + t_i.z * dir; + + // check if point is in bounds + 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) { + continue; + } + 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); + } + vox_pos = clamp(vec3(pos), vec3(0), dim_i - vec3(1)); + + + + dir_i = vec3(dir_if); + // time to move 1 unit using dir + inc_t = abs(1.0 / dir); + corner = vec3(vox_pos) + vec3(0.5) + dir_if / 2.0; + + // time of next plane hit for each direction + next_t = inc_t * abs(pos - corner); + t = 0.0; + prev_t = t; + color = vec4(0.0); + gdepth = 9999999999999.0; + loop { + i = u32(vox_pos.x + vox_pos.y * dim_i.x + vox_pos.z * dim_i.x * dim_i.y) + group.offset; + vcolor = unpack4x8unorm(voxels[i]); + + // select next voxel to move to next based on least time + axis = select(select(2, 1, next_t.y < next_t.z), 0, next_t.x < next_t.y && next_t.x < next_t.z); + prev_t = t; + t = next_t[axis]; + vox_pos[axis] += dir_i[axis]; + next_t[axis] += inc_t[axis]; + + // hit a voxel + if vcolor.a > 0.0 { + full_t = t_offset + prev_t; + gdepth = min(gdepth, full_t); + color += vec4(vcolor.xyz * vcolor.a * (1.0 - color.a), (1.0 - color.a) * vcolor.a); + if color.a >= FULL_ALPHA { + break; + } + } + + if color.a >= FULL_ALPHA || vox_pos[axis] < 0 || vox_pos[axis] >= dim_i[axis] { + break; + } + } + result = select(result, color, gdepth < depth); + depth = min(gdepth, depth); + } + return result; +} +