basic working polygon renderer

This commit is contained in:
2024-06-15 03:03:48 -04:00
parent 219213ee24
commit aa466a248c
23 changed files with 639 additions and 300 deletions

View File

@@ -22,7 +22,11 @@ use crate::{
};
use self::{input::Input, render::Renderer, ClientState};
use std::{collections::HashMap, sync::Arc, time::{Duration, Instant}};
use std::{
collections::HashMap,
sync::Arc,
time::{Duration, Instant},
};
use winit::{
event::WindowEvent,
window::{Window, WindowAttributes},
@@ -44,6 +48,7 @@ pub struct Client<'a> {
systems: ClientSystems,
target: Instant,
frame_time: Duration,
the_thing: bool,
}
pub struct ClientSystems {
@@ -86,6 +91,7 @@ impl Client<'_> {
server_id_map: HashMap::new(),
target: Instant::now(),
frame_time: FRAME_TIME,
the_thing: false,
}
}
@@ -106,6 +112,13 @@ impl Client<'_> {
.expect("WHAT");
self.world.clear_trackers();
if self.state.camera.pos.y < -10.0 {
self.the_thing = !self.the_thing;
if self.the_thing == true {
let thing = include_bytes!("../../../../videos/meme/rab_falls_and_dies.mp4");
}
}
if now >= self.target {
self.target += self.frame_time;
let mut commands = std::mem::take(&mut self.render_commands);

View File

@@ -3,6 +3,7 @@ use crate::client::camera::Camera;
use super::{voxel::VoxelColor, Renderer};
use bevy_ecs::entity::Entity;
use nalgebra::{Rotation3, Vector3};
use ndarray::Array3;
use std::sync::Arc;
use winit::window::Window;
@@ -19,7 +20,7 @@ pub struct CreateVoxelGrid {
pub pos: Vector3<f32>,
pub orientation: Rotation3<f32>,
pub dimensions: Vector3<usize>,
pub grid: Vec<VoxelColor>,
pub grid: Array3<VoxelColor>,
}
#[derive(Debug, Clone)]

View File

@@ -1,14 +1,16 @@
mod command;
mod util;
pub mod voxel;
pub mod voxel_poly;
pub use command::*;
use util::Texture;
use super::camera::Camera;
use crate::client::rsc::CLEAR_COLOR;
use nalgebra::Vector2;
use smaa::{SmaaMode, SmaaTarget};
use voxel::VoxelPipeline;
use voxel_poly::VoxelPipeline;
use winit::dpi::PhysicalSize;
pub struct Renderer<'a> {
@@ -22,6 +24,7 @@ pub struct Renderer<'a> {
voxel_pipeline: VoxelPipeline,
smaa_target: SmaaTarget,
camera: Camera,
depth_texture: Texture,
}
impl<'a> Renderer<'a> {
@@ -67,7 +70,7 @@ impl<'a> Renderer<'a> {
format: surface_format,
width: size.width,
height: size.height,
present_mode: surface_caps.present_modes[0],
present_mode: wgpu::PresentMode::AutoVsync,
alpha_mode: surface_caps.alpha_modes[0],
view_formats: vec![],
desired_maximum_frame_latency: 2,
@@ -87,10 +90,12 @@ impl<'a> Renderer<'a> {
SmaaMode::Smaa1X,
);
let depth_texture = Texture::create_depth_texture(&device, &config, "depth_texture");
Self {
camera: Camera::default(),
size: Vector2::new(size.width, size.height),
voxel_pipeline: VoxelPipeline::new(&device, &config.format),
voxel_pipeline: VoxelPipeline::new(&device, &config),
staging_belt,
surface,
encoder: Self::create_encoder(&device),
@@ -98,6 +103,7 @@ impl<'a> Renderer<'a> {
config,
queue,
smaa_target,
depth_texture,
}
}
@@ -127,7 +133,14 @@ impl<'a> Renderer<'a> {
store: wgpu::StoreOp::Store,
},
})],
depth_stencil_attachment: None,
depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {
view: &self.depth_texture.view,
depth_ops: Some(wgpu::Operations {
load: wgpu::LoadOp::Clear(1.0),
store: wgpu::StoreOp::Store,
}),
stencil_ops: None,
}),
timestamp_writes: None,
occlusion_query_set: None,
});
@@ -149,6 +162,8 @@ impl<'a> Renderer<'a> {
self.smaa_target
.resize(&self.device, size.width, size.height);
self.depth_texture =
Texture::create_depth_texture(&self.device, &self.config, "depth_texture");
self.voxel_pipeline.update_view(
&self.device,
&mut self.encoder,

View File

@@ -5,7 +5,7 @@ use super::buf::{ArrBuf, ArrBufUpdate, BufMove};
pub struct Instances<T: bytemuck::Pod> {
buf: ArrBuf<T>,
location: u32,
attrs: [VertexAttribute; 1],
attrs: Vec<VertexAttribute>,
}
impl<T: bytemuck::Pod> Instances<T> {
@@ -24,7 +24,7 @@ impl<T: bytemuck::Pod> Instances<T> {
device: &wgpu::Device,
label: &str,
location: u32,
format: wgpu::VertexFormat,
attrs: &[wgpu::VertexAttribute],
) -> Self {
Self {
buf: ArrBuf::init(
@@ -33,11 +33,26 @@ impl<T: bytemuck::Pod> Instances<T> {
BufferUsages::VERTEX,
),
location,
attrs: [wgpu::VertexAttribute {
format,
offset: 0,
shader_location: location,
}],
attrs: attrs.to_vec(),
}
}
pub fn init_with(
device: &wgpu::Device,
label: &str,
location: u32,
attrs: &[wgpu::VertexAttribute],
data: &[T],
) -> Self {
Self {
buf: ArrBuf::init_with(
device,
&(label.to_owned() + " Instance"),
BufferUsages::VERTEX,
data,
),
location,
attrs: attrs.to_vec(),
}
}
@@ -56,4 +71,8 @@ impl<T: bytemuck::Pod> Instances<T> {
pub fn mov(&mut self, mov: BufMove) {
self.buf.mov(mov);
}
pub fn len(&self) -> usize {
self.buf.len()
}
}

View File

@@ -2,8 +2,12 @@ mod buf;
mod instance;
mod storage;
mod uniform;
mod vertex;
mod texture;
pub use buf::*;
pub use instance::*;
pub use storage::*;
pub use uniform::*;
pub use vertex::*;
pub use texture::*;

View File

@@ -1,12 +1,12 @@
use super::buf::{ArrBuf, ArrBufUpdate, BufMove};
use wgpu::BufferUsages;
pub struct Storage<T: bytemuck::Pod + PartialEq> {
pub struct Storage<T: bytemuck::Pod> {
binding: u32,
buf: ArrBuf<T>,
}
impl<T: PartialEq + bytemuck::Pod> Storage<T> {
impl<T: bytemuck::Pod> Storage<T> {
pub fn init(device: &wgpu::Device, label: &str, binding: u32) -> Self {
Self {
buf: ArrBuf::init(
@@ -30,7 +30,7 @@ impl<T: PartialEq + bytemuck::Pod> Storage<T> {
}
}
impl<T: PartialEq + bytemuck::Pod> Storage<T> {
impl<T: bytemuck::Pod> Storage<T> {
pub fn bind_group_layout_entry(&self) -> wgpu::BindGroupLayoutEntry {
wgpu::BindGroupLayoutEntry {
binding: self.binding,

View File

@@ -0,0 +1,55 @@
pub struct Texture {
pub texture: wgpu::Texture,
pub view: wgpu::TextureView,
pub sampler: wgpu::Sampler,
}
impl Texture {
pub const DEPTH_FORMAT: wgpu::TextureFormat = wgpu::TextureFormat::Depth32Float; // 1.
pub fn create_depth_texture(
device: &wgpu::Device,
config: &wgpu::SurfaceConfiguration,
label: &str,
) -> Self {
let size = wgpu::Extent3d {
// 2.
width: config.width,
height: config.height,
depth_or_array_layers: 1,
};
let desc = wgpu::TextureDescriptor {
label: Some(label),
size,
mip_level_count: 1,
sample_count: 1,
dimension: wgpu::TextureDimension::D2,
format: Self::DEPTH_FORMAT,
usage: wgpu::TextureUsages::RENDER_ATTACHMENT // 3.
| wgpu::TextureUsages::TEXTURE_BINDING,
view_formats: &[],
};
let texture = device.create_texture(&desc);
let view = texture.create_view(&wgpu::TextureViewDescriptor::default());
let sampler = device.create_sampler(&wgpu::SamplerDescriptor {
// 4.
address_mode_u: wgpu::AddressMode::ClampToEdge,
address_mode_v: wgpu::AddressMode::ClampToEdge,
address_mode_w: wgpu::AddressMode::ClampToEdge,
mag_filter: wgpu::FilterMode::Linear,
min_filter: wgpu::FilterMode::Linear,
mipmap_filter: wgpu::FilterMode::Nearest,
compare: Some(wgpu::CompareFunction::LessEqual), // 5.
lod_min_clamp: 0.0,
lod_max_clamp: 100.0,
..Default::default()
});
Self {
texture,
view,
sampler,
}
}
}

View File

@@ -23,6 +23,17 @@ impl<T: Default + bytemuck::Pod> Uniform<T> {
}
impl<T: PartialEq + bytemuck::Pod> Uniform<T> {
pub fn init_with(device: &wgpu::Device, name: &str, binding: u32, data: &[T]) -> Self {
Self {
buffer: device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some(&(name.to_owned() + " Uniform Buf")),
contents: bytemuck::cast_slice(data),
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
}),
binding,
ty: PhantomData,
}
}
pub fn bind_group_layout_entry(&self) -> wgpu::BindGroupLayoutEntry {
wgpu::BindGroupLayoutEntry {
binding: self.binding,

View File

@@ -0,0 +1,86 @@
use wgpu::{BufferUsages, VertexAttribute};
use super::buf::{ArrBuf, ArrBufUpdate, BufMove};
pub struct Vertices<T: bytemuck::Pod> {
buf: ArrBuf<T>,
location: u32,
attrs: [VertexAttribute; 1],
}
impl<T: bytemuck::Pod> Vertices<T> {
pub fn update(
&mut self,
device: &wgpu::Device,
encoder: &mut wgpu::CommandEncoder,
belt: &mut wgpu::util::StagingBelt,
size: usize,
updates: &[ArrBufUpdate<T>],
) -> bool {
self.buf.update(device, encoder, belt, size, updates)
}
pub fn init(
device: &wgpu::Device,
label: &str,
location: u32,
format: wgpu::VertexFormat,
) -> Self {
Self {
buf: ArrBuf::init(
device,
&(label.to_owned() + " Instance"),
BufferUsages::VERTEX,
),
location,
attrs: [wgpu::VertexAttribute {
format,
offset: 0,
shader_location: location,
}],
}
}
pub fn init_with(
device: &wgpu::Device,
label: &str,
location: u32,
format: wgpu::VertexFormat,
data: &[T],
) -> Self {
Self {
buf: ArrBuf::init_with(
device,
&(label.to_owned() + " Instance"),
BufferUsages::VERTEX,
data,
),
location,
attrs: [wgpu::VertexAttribute {
format,
offset: 0,
shader_location: location,
}],
}
}
pub fn set_in<'a>(&'a self, render_pass: &mut wgpu::RenderPass<'a>) {
render_pass.set_vertex_buffer(self.location, self.buf.buffer().slice(..));
}
pub fn desc(&self) -> wgpu::VertexBufferLayout {
wgpu::VertexBufferLayout {
array_stride: std::mem::size_of::<T>() as wgpu::BufferAddress,
step_mode: wgpu::VertexStepMode::Vertex,
attributes: &self.attrs,
}
}
pub fn mov(&mut self, mov: BufMove) {
self.buf.mov(mov);
}
pub fn len(&self) -> usize {
self.buf.len()
}
}

View File

@@ -150,7 +150,7 @@ impl VoxelPipeline {
let updates = [ArrBufUpdate {
offset,
data: &grid,
data: &grid.as_slice().unwrap(),
}];
let size = offset + grid.len();
self.voxels.update(device, encoder, belt, size, &updates);
@@ -226,7 +226,6 @@ impl VoxelPipeline {
width: size.x,
height: size.y,
zoom: camera.scale,
padding: 0,
transform,
};
self.view.update(device, encoder, belt, data)

View File

@@ -6,15 +6,13 @@ struct GlobalLight {
struct VertexOutput {
@builtin(position) clip_position: vec4<f32>,
@location(0) tex_coords: vec2<f32>,
};
struct View {
transform: mat4x4<f32>,
width: u32,
height: u32,
zoom: f32,
padding: u32,
transform: mat4x4<f32>,
};
struct VoxelGroup {

View File

@@ -3,11 +3,10 @@ use nalgebra::Transform3;
#[repr(C, align(16))]
#[derive(Clone, Copy, PartialEq, bytemuck::Zeroable)]
pub struct View {
pub transform: Transform3<f32>,
pub width: u32,
pub height: u32,
pub zoom: f32,
pub padding: u32,
pub transform: Transform3<f32>,
}
unsafe impl bytemuck::Pod for View {}
@@ -18,7 +17,6 @@ impl Default for View {
width: 1,
height: 1,
zoom: 1.0,
padding: 0,
transform: Transform3::identity(),
}
}

View File

@@ -0,0 +1,11 @@
use nalgebra::{Transform3, Vector3};
#[repr(C, align(16))]
#[derive(Debug, Clone, Copy, PartialEq, bytemuck::Zeroable, Default)]
pub struct FaceGroup {
pub transform: Transform3<f32>,
pub dimensions: Vector3<u32>,
pub face: u32,
}
unsafe impl bytemuck::Pod for FaceGroup {}

View File

@@ -0,0 +1,12 @@
use bytemuck::Zeroable;
use crate::client::render::voxel::VoxelColor;
#[repr(C)]
#[derive(Copy, Clone, Debug, Zeroable)]
pub struct VoxelFace {
pub index: u32,
pub color: VoxelColor,
}
unsafe impl bytemuck::Pod for VoxelFace {}

View File

@@ -1,26 +1,47 @@
use super::uniform::Uniform;
use nalgebra::{Projective3, Translation3, Rotation3};
mod view;
mod color;
mod vertex;
mod group;
mod instance;
mod square;
mod view;
use core::panic;
use group::FaceGroup;
use instance::VoxelFace;
use nalgebra::{Perspective3, Transform3, Translation3, Vector2, Vector3};
use view::View;
use wgpu::{SurfaceConfiguration, VertexAttribute, VertexFormat};
use crate::client::camera::Camera;
use super::{
util::{Instances, Texture, Uniform},
CreateVoxelGrid, UpdateGridTransform,
};
pub struct VoxelPipeline {
pipeline: wgpu::RenderPipeline,
view: Uniform<View>,
bind_group_layout: wgpu::BindGroupLayout,
bind_group: wgpu::BindGroup,
voxel_groups: Storage<VoxelGroup>,
voxels: Storage<VoxelColor>,
arst: bool,
bind_groups: Vec<wgpu::BindGroup>,
vertices: Vec<Instances<VoxelFace>>,
}
const WIDTH: u32 = 300;
const HEIGHT: u32 = 300;
const INSTANCE_ATTRS: [wgpu::VertexAttribute; 2] = [
VertexAttribute {
format: VertexFormat::Uint32,
offset: 0,
shader_location: 0,
},
VertexAttribute {
format: VertexFormat::Uint32,
offset: 4,
shader_location: 1,
},
];
impl VoxelPipeline {
pub fn new(device: &wgpu::Device, format: &wgpu::TextureFormat) -> Self {
pub fn new(device: &wgpu::Device, config: &SurfaceConfiguration) -> Self {
// shaders
let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
label: Some("Tile Shader"),
@@ -28,29 +49,19 @@ impl VoxelPipeline {
});
let view = Uniform::<View>::init(device, "view", 0);
let voxels = Storage::init(device, "voxels", 1);
let voxel_groups = Storage::init(device, "voxel groups", 2);
let example_faces =
Instances::<VoxelFace>::init(device, "voxel groups", 0, &INSTANCE_ATTRS);
let example_group = Uniform::<FaceGroup>::init(device, "voxel group", 1);
// bind groups
let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
entries: &[
view.bind_group_layout_entry(),
voxels.bind_group_layout_entry(),
voxel_groups.bind_group_layout_entry(),
example_group.bind_group_layout_entry(),
],
label: Some("tile_bind_group_layout"),
});
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
layout: &bind_group_layout,
entries: &[
view.bind_group_entry(),
voxels.bind_group_entry(),
voxel_groups.bind_group_entry(),
],
label: Some("tile_bind_group"),
});
// pipeline
let render_pipeline_layout =
device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
@@ -65,14 +76,14 @@ impl VoxelPipeline {
vertex: wgpu::VertexState {
module: &shader,
entry_point: "vs_main",
buffers: &[],
buffers: &[example_faces.desc()],
compilation_options: wgpu::PipelineCompilationOptions::default(),
},
fragment: Some(wgpu::FragmentState {
module: &shader,
entry_point: "fs_main",
targets: &[Some(wgpu::ColorTargetState {
format: *format,
format: config.format,
blend: Some(wgpu::BlendState::REPLACE),
write_mask: wgpu::ColorWrites::ALL,
})],
@@ -82,12 +93,18 @@ impl VoxelPipeline {
topology: wgpu::PrimitiveTopology::TriangleStrip,
strip_index_format: None,
front_face: wgpu::FrontFace::Ccw,
cull_mode: None,
cull_mode: Some(wgpu::Face::Back),
polygon_mode: wgpu::PolygonMode::Fill,
unclipped_depth: false,
conservative: false,
},
depth_stencil: None,
depth_stencil: Some(wgpu::DepthStencilState {
format: Texture::DEPTH_FORMAT,
depth_write_enabled: true,
depth_compare: wgpu::CompareFunction::Less,
stencil: wgpu::StencilState::default(),
bias: wgpu::DepthBiasState::default(),
}),
multisample: wgpu::MultisampleState {
count: 1,
mask: !0,
@@ -99,165 +116,123 @@ impl VoxelPipeline {
Self {
pipeline: render_pipeline,
view,
bind_group,
bind_group_layout,
voxels,
voxel_groups,
arst: false,
bind_groups: Vec::new(),
vertices: Vec::new(),
}
}
pub fn update(
pub fn update_view(
&mut self,
device: &wgpu::Device,
encoder: &mut wgpu::CommandEncoder,
belt: &mut wgpu::util::StagingBelt,
update_data: &RenderUpdateData,
size: Vector2<u32>,
camera: &Camera,
) {
if !self.arst {
let lx = 15;
let ly = 10;
let lz = 10;
let mut data = vec![VoxelColor::none(); lx * ly * lz];
for x in 0..lx {
for y in 0..ly {
data[x + y * lx] = VoxelColor {
r: (x as f32 / lx as f32 * 255.0) as u8,
g: (y as f32 / ly as f32 * 255.0) as u8,
b: 0,
a: 100,
};
}
}
for x in 0..lx {
for y in 0..ly {
data[x + y * lx + 3 * lx * ly] = VoxelColor {
r: (x as f32 / lx as f32 * 255.0) as u8,
g: (y as f32 / ly as f32 * 255.0) as u8,
b: 100,
a: 255,
};
}
}
for i in 0..lx.min(ly.min(lz)) {
data[i + i * lx + i * lx * ly] = VoxelColor::white();
}
let lx2 = 1000;
let ly2 = 2;
let lz2 = 1000;
let offset2 = data.len();
let mut data2 = vec![VoxelColor::none(); lx2 * ly2 * lz2];
let paint = VoxelColor {
r: 255,
g: 0,
b: 255,
a: 255,
};
for x in 0..lx2 {
data2[x + (ly2 - 1) * lx2] = paint;
data2[x + (ly2 - 1) * lx2 + (lz2 - 1) * lx2 * ly2] = paint;
}
for z in 0..lz2 {
data2[(ly2 - 1) * lx2 + z * lx2 * ly2] = paint;
data2[lx2 - 1 + (ly2 - 1) * lx2 + z * lx2 * ly2] = paint;
}
for x in 0..lx2 {
for z in 0..lz2 {
data2[x + z * lx2 * ly2] = rand::random();
}
}
data.append(&mut data2);
let lx3 = 3;
let ly3 = 3;
let lz3 = 3;
let offset3 = data.len();
data.append(&mut vec![
VoxelColor {
r: 255,
g: 0,
b: 255,
a: 255,
};
lx3 * ly3 * lz3
]);
self.voxels.update(
device,
encoder,
belt,
data.len(),
&[ArrBufUpdate { offset: 0, data }],
);
let proj = Projective3::identity()
* Translation3::new(0.0, 0.0, 20.0)
* Rotation3::from_axis_angle(&Vector3::y_axis(), 0.5)
* Translation3::new(-(lx as f32 / 2.0), -(ly as f32 / 2.0), -(lz as f32 / 2.0));
let group = VoxelGroup {
transform: proj,
transform_inv: proj.inverse(),
dimensions: Vector3::new(lx as u32, ly as u32, lz as u32),
offset: 0,
};
let proj2 = Projective3::identity()
* Translation3::new(0.0, -2.1, 20.0)
* Translation3::new(
-(lx2 as f32 / 2.0),
-(ly2 as f32 / 2.0),
-(lz2 as f32 / 2.0),
);
let group2 = VoxelGroup {
transform: proj2,
transform_inv: proj2.inverse(),
dimensions: Vector3::new(lx2 as u32, ly2 as u32, lz2 as u32),
offset: offset2 as u32,
};
let proj3 = Projective3::identity()
* 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)),
std::f32::consts::PI / 4.0,
)
* Translation3::new(
-(lx3 as f32 / 2.0),
-(ly3 as f32 / 2.0),
-(lz3 as f32 / 2.0),
);
let group3 = VoxelGroup {
transform: proj3,
transform_inv: proj3.inverse(),
dimensions: Vector3::new(lx3 as u32, ly3 as u32, lz3 as u32),
offset: offset3 as u32,
};
let groups = vec![group, group2, group3];
self.voxel_groups.update(
device,
encoder,
belt,
groups.len(),
&[ArrBufUpdate {
offset: 0,
data: groups,
}],
);
self.bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
layout: &self.bind_group_layout,
entries: &[
self.view.bind_group_entry(),
self.voxels.bind_group_entry(),
self.voxel_groups.bind_group_entry(),
],
label: Some("tile_bind_group"),
});
self.arst = true;
}
self.view.update(device, encoder, belt, update_data);
let mut transform = (Translation3::from(camera.pos) * camera.orientation)
.inverse()
.to_matrix();
transform = transform.append_nonuniform_scaling(&Vector3::new(1.0, 1.0, -1.0));
let projection = Perspective3::new(
size.x as f32 / size.y as f32,
std::f32::consts::PI / 2.0,
0.1,
1000.0,
);
transform = projection.as_matrix() * transform;
let data = View {
width: size.x,
height: size.y,
zoom: camera.scale,
transform,
};
self.view.update(device, encoder, belt, data)
}
pub fn draw<'a>(&'a self, render_pass: &mut wgpu::RenderPass<'a>) {
render_pass.set_pipeline(&self.pipeline);
render_pass.set_bind_group(0, &self.bind_group, &[]);
render_pass.draw(0..4, 0..1);
for i in 0..self.bind_groups.len() {
render_pass.set_bind_group(0, &self.bind_groups[i], &[]);
let vertices = &self.vertices[i];
vertices.set_in(render_pass);
render_pass.draw(0..4, 0..vertices.len() as u32);
}
}
pub fn add_group(
&mut self,
device: &wgpu::Device,
encoder: &mut wgpu::CommandEncoder,
belt: &mut wgpu::util::StagingBelt,
CreateVoxelGrid {
id,
pos,
orientation,
dimensions,
grid,
}: CreateVoxelGrid,
) {
let proj = Transform3::identity()
* Translation3::from(pos)
* orientation
* Translation3::from(-dimensions.cast() / 2.0);
for face in 0..6 {
let group = FaceGroup {
dimensions: dimensions.cast(),
transform: proj,
face,
};
let uniform = Uniform::init_with(device, "voxel group", 1, &[group]);
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
layout: &self.bind_group_layout,
entries: &[self.view.bind_group_entry(), uniform.bind_group_entry()],
label: Some("voxel bind group"),
});
self.bind_groups.push(bind_group);
let mut data = Vec::new();
let n_offset = match face % 3 {
0 => 1,
1 => dimensions.z * dimensions.y,
2 => dimensions.z,
_ => 0,
} as i32
* ((face as i32 / 3) * 2 - 1);
let face_dir = (face as i32 / 3) * 2 - 1;
for (i, ((x, y, z), color)) in grid.indexed_iter().enumerate() {
let neighbor = match face {
0 => if z > 0 {Some((x, y, z - 1))} else {None},
2 => if y > 0 {Some((x, y - 1, z))} else {None},
1 => if x > 0 {Some((x - 1, y, z))} else {None},
3 => if z < dimensions.z - 1 {Some((x, y, z + 1))} else {None},
5 => if y < dimensions.y - 1 {Some((x, y + 1, z))} else {None},
4 => if x < dimensions.x - 1 {Some((x + 1, y, z))} else {None},
_ => panic!("what"),
}.map(|p| grid.get(p).unwrap());
if color.a > 0 && !neighbor.is_some_and(|c| c.a == color.a) {
data.push(VoxelFace {
index: i as u32,
color: *color,
});
}
}
self.vertices.push(Instances::init_with(
device,
"vvvvv",
0,
&INSTANCE_ATTRS,
&data,
));
}
}
pub fn update_transform(
&mut self,
device: &wgpu::Device,
encoder: &mut wgpu::CommandEncoder,
staging_belt: &mut wgpu::util::StagingBelt,
update: UpdateGridTransform,
) {
}
}

View File

@@ -1,10 +1,20 @@
// Vertex shader
struct InstanceInput {
@location(0) index: u32,
@location(1) color: u32,
};
struct VertexOutput {
@builtin(position) clip_position: vec4<f32>,
@location(0) tex_coords: vec2<f32>,
@location(0) color: vec4<f32>,
};
struct VoxelFace {
index: u32,
color: u32,
}
struct View {
transform: mat4x4<f32>,
width: u32,
@@ -14,31 +24,51 @@ struct View {
struct VoxelGroup {
transform: mat4x4<f32>,
transform_inv: mat4x4<f32>,
dimensions: vec3<u32>,
offset: u32,
face: u32,
};
@group(0) @binding(0)
var<uniform> view: View;
@group(0) @binding(1)
var<storage, read> voxels: array<u32>;
@group(0) @binding(2)
var<storage, read> voxel_groups: array<VoxelGroup>;
var<uniform> group: VoxelGroup;
const DIRECTIONS = array(
vec3<f32>(1.0, 1.0, 0.0),
vec3<f32>(0.0, 1.0, 1.0),
vec3<f32>(1.0, 0.0, 1.0),
);
@vertex
fn vs_main(
@builtin(vertex_index) vi: u32,
@builtin(instance_index) ii: u32,
in: InstanceInput
) -> VertexOutput {
var out: VertexOutput;
var pos = vec2<f32>(
f32(vi % 2u) * 2.0 - 1.0,
f32(vi / 2u) * 2.0 - 1.0,
) ;
out.clip_position = vec4<f32>(pos.x, pos.y, 0.0, 1.0);
out.tex_coords = pos;
let invert = select(0.0, 1.0, group.face / 3 == 1);
let invert_mult = 1.0 - invert * 2.0;
var square_pos = vec2<f32>(
f32(vi % 2u),
invert + invert_mult * f32(vi / 2u),
);
var cube_pos = vec3<f32>(invert);
square_pos *= invert_mult;
cube_pos[(group.face) % 3] += square_pos.x;
cube_pos[(group.face + 1) % 3] += square_pos.y;
var pos = vec4<f32>(
cube_pos,
1.0,
);
pos += vec4<f32>(
f32(in.index / (group.dimensions.z * group.dimensions.y)),
f32((in.index / group.dimensions.z) % group.dimensions.y),
f32(in.index % group.dimensions.z),
0.0,
);
pos = view.transform * group.transform * pos;
out.clip_position = pos;
out.color = unpack4x8unorm(in.color);
return out;
}
@@ -48,22 +78,5 @@ fn vs_main(
fn fs_main(
in: VertexOutput,
) -> @location(0) vec4<f32> {
// get position of the pixel; eye at origin, pixel on plane z = 1
let win_dim = vec2<f32>(f32(view.width), f32(view.height));
let aspect = win_dim.y / win_dim.x;
let pixel_pos = vec3<f32>(
(in.clip_position.xy / win_dim - vec2<f32>(0.5)) * vec2<f32>(2.0, -2.0 * aspect),
1.0
);
// move to position in world
let pos = view.transform * vec4<f32>(pixel_pos, 1.0);
let dir = view.transform * vec4<f32>(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 sky_color = light_mult * vec3<f32>(1.0, 1.0, 1.0);
color += vec4<f32>(sky_color * (1.0 - color.a), 1.0 - color.a);
color.a = 1.0;
return color;
return in.color;
}

View File

@@ -1,6 +0,0 @@
#[repr(C)]
#[derive(Copy, Clone, Debug)]
struct Vertex {
position: [f32; 3],
color: [f32; 3],
}

View File

@@ -1,11 +1,9 @@
use nalgebra::{Transform3, Translation3};
use crate::client::render::uniform::UniformData;
use nalgebra::Matrix4;
#[repr(C, align(16))]
#[derive(Clone, Copy, PartialEq, bytemuck::Zeroable)]
pub struct View {
pub transform: Transform3<f32>,
pub transform: Matrix4<f32>,
pub width: u32,
pub height: u32,
pub zoom: f32,
@@ -19,29 +17,7 @@ impl Default for View {
width: 1,
height: 1,
zoom: 1.0,
transform: Transform3::identity(),
}
}
}
impl UniformData for View {
fn update(&mut self, data: &crate::client::render::RenderUpdateData) -> bool {
let camera = data.state.camera;
let new = Transform3::identity() * Translation3::from(camera.pos) * camera.orientation;
if new == self.transform
&& data.size.width == self.width
&& data.size.height == self.height
&& camera.scale == self.zoom
{
false
} else {
*self = Self {
width: data.size.width,
height: data.size.height,
zoom: camera.scale,
transform: new,
};
true
transform: Matrix4::identity(),
}
}
}

View File

@@ -1,3 +1,5 @@
use std::ops::Deref;
use bevy_ecs::{
entity::Entity,
query::{Added, Changed, Or},
@@ -31,7 +33,7 @@ pub fn add_grid(
grid.len_of(Axis(1)),
grid.len_of(Axis(2)),
),
grid: grid.iter().cloned().collect(),
grid: grid.deref().clone(),
}));
}
}