diff --git a/src/client/init.rs b/src/client/init.rs index 8d8b410..c1e4555 100644 --- a/src/client/init.rs +++ b/src/client/init.rs @@ -41,7 +41,7 @@ pub fn init_world(world: &mut World) { orientation: Rotation3::identity(), grid: VoxelGrid::new(Array3::from_shape_fn(dim, |(x, y, z)| { if y == 0 { - rand::random() + VoxelColor::random() } else if (y == dim.1 - 1) && (x == 0 || x == dim.0 - 1 || z == 0 || z == dim.2 - 1) { VoxelColor { r: 255, diff --git a/src/client/mod.rs b/src/client/mod.rs index 902f687..aecc805 100644 --- a/src/client/mod.rs +++ b/src/client/mod.rs @@ -44,7 +44,6 @@ impl Client { init_world(&mut world); let state = ClientState::new(); - // render_channel.send(RenderMessage::ViewUpdate(state.camera)).expect("GRRRR"); Self { window, @@ -70,6 +69,8 @@ impl Client { if self.exit { self.renderer.send(RenderMessage::Exit).expect("AAAA"); + // you know I'd like to do a timeout here... + // only because I have an NVIDIA GPU HELP self.render_handle .take() .expect("uh oh") diff --git a/src/client/render/util/buf.rs b/src/client/render/util/buf.rs index 9a4801b..cb253b5 100644 --- a/src/client/render/util/buf.rs +++ b/src/client/render/util/buf.rs @@ -1,5 +1,5 @@ use std::marker::PhantomData; -use wgpu::{BufferAddress, BufferUsages}; +use wgpu::{util::DeviceExt, BufferAddress, BufferUsages}; pub struct ArrBuf { len: usize, @@ -74,6 +74,18 @@ impl ArrBuf { } } + pub fn init_with(device: &wgpu::Device, label: &str, usage: BufferUsages, data: &[T]) -> Self { + let label = &(label.to_owned() + " Buffer"); + Self { + len: data.len(), + buffer: Self::init_buf_with(device, label, usage, data), + label: label.to_string(), + typ: PhantomData, + usage, + moves: Vec::new(), + } + } + fn init_buf( device: &wgpu::Device, label: &str, @@ -91,6 +103,19 @@ impl ArrBuf { }) } + fn init_buf_with( + device: &wgpu::Device, + label: &str, + usage: BufferUsages, + data: &[T], + ) -> wgpu::Buffer { + device.create_buffer_init(&wgpu::util::BufferInitDescriptor { + label: Some(label), + usage: usage | BufferUsages::COPY_DST | BufferUsages::COPY_SRC, + contents: bytemuck::cast_slice(data), + }) + } + pub fn buffer(&self) -> &wgpu::Buffer { &self.buffer } diff --git a/src/client/render/util/storage.rs b/src/client/render/util/storage.rs index 6bd6a94..afbf80f 100644 --- a/src/client/render/util/storage.rs +++ b/src/client/render/util/storage.rs @@ -17,6 +17,17 @@ impl Storage { binding, } } + pub fn init_with(device: &wgpu::Device, label: &str, binding: u32, data: &[T]) -> Self { + Self { + buf: ArrBuf::init_with( + device, + &(label.to_owned() + " Storage"), + BufferUsages::STORAGE, + data + ), + binding, + } + } } impl Storage { diff --git a/src/client/render/voxel/color.rs b/src/client/render/voxel/color.rs index 819cd72..4021376 100644 --- a/src/client/render/voxel/color.rs +++ b/src/client/render/voxel/color.rs @@ -1,7 +1,7 @@ use rand::distributions::{Distribution, Standard}; #[repr(C)] -#[derive(Debug, Clone, Copy, PartialEq, bytemuck::Zeroable, bytemuck::Pod)] +#[derive(Debug, Clone, Copy, PartialEq, bytemuck::Zeroable)] pub struct VoxelColor { pub r: u8, pub g: u8, @@ -9,6 +9,8 @@ pub struct VoxelColor { pub a: u8, } +unsafe impl bytemuck::Pod for VoxelColor {} + impl VoxelColor { pub fn none() -> Self { Self { @@ -34,6 +36,9 @@ impl VoxelColor { a: 255, } } + pub fn random() -> Self { + rand::random() + } } impl Distribution for Standard { diff --git a/src/client/render/voxel/light.rs b/src/client/render/voxel/light.rs new file mode 100644 index 0000000..643d06c --- /dev/null +++ b/src/client/render/voxel/light.rs @@ -0,0 +1,9 @@ +use nalgebra::Vector3; + +#[repr(C, align(16))] +#[derive(Clone, Copy, PartialEq, bytemuck::Zeroable)] +pub struct GlobalLight { + pub direction: Vector3, +} + +unsafe impl bytemuck::Pod for GlobalLight {} diff --git a/src/client/render/voxel/mod.rs b/src/client/render/voxel/mod.rs index d6a1d50..329954e 100644 --- a/src/client/render/voxel/mod.rs +++ b/src/client/render/voxel/mod.rs @@ -1,13 +1,14 @@ -mod grid; -mod view; mod color; +mod grid; mod group; +mod light; +mod view; pub use color::*; -use nalgebra::{Projective3, Transform3, Translation3, Vector2}; +use light::GlobalLight; +use nalgebra::{Projective3, Transform3, Translation3, Vector2, Vector3}; -use {group::VoxelGroup, view::View}; use crate::client::{ camera::Camera, render::{ @@ -15,6 +16,7 @@ use crate::client::{ CreateVoxelGrid, }, }; +use {group::VoxelGroup, view::View}; pub struct VoxelPipeline { pipeline: wgpu::RenderPipeline, @@ -23,6 +25,7 @@ pub struct VoxelPipeline { bind_group: wgpu::BindGroup, voxel_groups: Storage, voxels: Storage, + global_lights: Storage, } impl VoxelPipeline { @@ -33,9 +36,17 @@ impl VoxelPipeline { source: wgpu::ShaderSource::Wgsl(include_str!("shader.wgsl").into()), }); - let view = Uniform::::init(device, "view", 0); + let view = Uniform::init(device, "view", 0); let voxels = Storage::init(device, "voxels", 1); let voxel_groups = Storage::init(device, "voxel groups", 2); + let global_lights = Storage::init_with( + device, + "global lights", + 3, + &[GlobalLight { + direction: Vector3::new(-0.5, -4.0, 2.0).normalize(), + }], + ); // bind groups let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { @@ -43,6 +54,7 @@ impl VoxelPipeline { view.bind_group_layout_entry(), voxels.bind_group_layout_entry(), voxel_groups.bind_group_layout_entry(), + global_lights.bind_group_layout_entry(), ], label: Some("tile_bind_group_layout"), }); @@ -53,6 +65,7 @@ impl VoxelPipeline { view.bind_group_entry(), voxels.bind_group_entry(), voxel_groups.bind_group_entry(), + global_lights.bind_group_entry(), ], label: Some("tile_bind_group"), }); @@ -109,6 +122,7 @@ impl VoxelPipeline { bind_group_layout, voxels, voxel_groups, + global_lights, } } @@ -156,6 +170,7 @@ impl VoxelPipeline { self.view.bind_group_entry(), self.voxels.bind_group_entry(), self.voxel_groups.bind_group_entry(), + self.global_lights.bind_group_entry(), ], label: Some("tile_bind_group"), }); diff --git a/src/client/render/voxel/shader.wgsl b/src/client/render/voxel/shader.wgsl index fd22094..087a443 100644 --- a/src/client/render/voxel/shader.wgsl +++ b/src/client/render/voxel/shader.wgsl @@ -1,5 +1,9 @@ // Vertex shader +struct GlobalLight { + dir: vec3, +}; + struct VertexOutput { @builtin(position) clip_position: vec4, @location(0) tex_coords: vec2, @@ -26,6 +30,8 @@ var view: View; var voxels: array; @group(0) @binding(2) var voxel_groups: array; +@group(0) @binding(3) +var global_lights: array; @vertex fn vs_main( @@ -62,7 +68,7 @@ fn fs_main( let dir = view.transform * vec4(normalize(pixel_pos), 0.0); var color = trace_full(pos, dir); - let light_mult = clamp((-dot(dir.xyz, normalize(GLOBAL_LIGHT)) - 0.99) * 200.0, 0.0, 1.0); + let light_mult = clamp((-dot(dir.xyz, global_lights[0].dir) - 0.99) * 200.0, 0.0, 1.0); let sky_color = light_mult * vec3(1.0, 1.0, 1.0); color += vec4(sky_color * (1.0 - color.a), 1.0 - color.a); color.a = 1.0; @@ -73,7 +79,6 @@ const ZERO3F = vec3(0.0); const ZERO2F = vec2(0.0); const DEPTH = 16u; const FULL_ALPHA = 0.9999; -const GLOBAL_LIGHT = vec3(-0.5, -4.0, 2.0); fn trace_full(pos: vec4, dir: vec4) -> vec4 { // GPUs hate this @@ -124,7 +129,6 @@ fn apply_group( (group.transform * vec4(0.0, 0.0, dir_if.z, 0.0)).xyz, ); var next_normal = vec3(0.0, 0.0, 0.0); - let norm_light = normalize(GLOBAL_LIGHT); // find where ray intersects with group let plane_point = (vec3(1.0) - dir_if) / 2.0 * dim_f; @@ -204,10 +208,10 @@ fn apply_group( // lighting let light = trace_light(full_pos); - let diffuse = max(dot(norm_light, normal) * ((dot(dir_view.xyz, normal) + 1.0) / 2.0 * .7 + .3) * 1.3 + 0.1, 0.0); + let diffuse = max(dot(global_lights[0].dir, normal) * ((dot(dir_view.xyz, normal) + 1.0) / 2.0 * .7 + .3) * 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 + -(dot(reflect(dir_view.xyz, normal), global_lights[0].dir) + 0.90) * 4.0, 0.0 )) - 1.0) * light; let lighting = max(diffuse * light.a, ambient); let new_rgb = min(vcolor.xyz * lighting + specular.xyz + light.xyz * vcolor.xyz, vec3(1.0)); @@ -233,7 +237,7 @@ fn apply_group( fn trace_light( pos: vec4 ) -> vec4 { - let dir = vec4(-normalize(GLOBAL_LIGHT), 0.0); + let dir = vec4(-global_lights[0].dir, 0.0); var mask = vec4(0.0); let start = pos + dir * .001; for (var gi: u32 = 0; gi < arrayLength(&voxel_groups); gi = gi + 1) {