Meshify chunks

This commit is contained in:
Sijmen 2021-05-31 04:01:03 +02:00
parent da7f7759ad
commit 033c257d3b
Signed by: vijfhoek
GPG key ID: 82D05C89B28B0DAE
11 changed files with 264 additions and 393 deletions

View file

@ -1,49 +0,0 @@
use cgmath::Vector3;
use std::ops::{Div, Sub};
pub struct Aabb<T> {
pub min: Vector3<T>,
pub max: Vector3<T>,
}
impl<T: Ord + Copy + Sub<Output = T> + Div<Output = T>> Aabb<T> {
pub fn intersects_ray(
&self,
ray_origin: Vector3<T>,
ray_direction: Vector3<T>,
) -> Option<(T, T)> {
let mut t_min = (self.min.x - ray_origin.x) / ray_direction.x;
let mut t_max = (self.max.x - ray_origin.x) / ray_direction.x;
if t_min > t_max {
std::mem::swap(&mut t_min, &mut t_max);
}
let mut ty_min = (self.min.y - ray_origin.y) / ray_direction.y;
let mut ty_max = (self.max.y - ray_origin.y) / ray_direction.y;
if ty_min > ty_max {
std::mem::swap(&mut ty_min, &mut ty_max);
}
if t_min > ty_max || ty_min > t_max {
return None;
}
t_min = T::max(t_min, ty_min);
t_max = T::min(t_min, ty_max);
let mut tz_min = (self.min.z - ray_origin.z) / ray_direction.z;
let mut tz_max = (self.max.z - ray_origin.z) / ray_direction.z;
if tz_min > tz_max {
std::mem::swap(&mut tz_min, &mut tz_max);
}
if t_min > tz_max || tz_min > t_max {
return None;
}
t_min = T::max(t_min, tz_min);
t_max = T::max(t_max, tz_max);
Some((t_min, t_max))
}
}

View file

@ -1,5 +1,7 @@
use crate::instance::Instance;
use ahash::AHashMap;
use std::collections::VecDeque;
use crate::{cube, quad::Quad, vertex::Vertex};
use ahash::{AHashMap, AHashSet};
use cgmath::{InnerSpace, Vector3};
use noise::utils::{NoiseMapBuilder, PlaneMapBuilder};
@ -7,8 +9,11 @@ use noise::utils::{NoiseMapBuilder, PlaneMapBuilder};
pub enum BlockType {
Cobblestone,
Dirt,
Grass,
Stone,
Grass,
Bedrock,
Sand,
Gravel,
}
#[derive(Debug, Clone, Copy)]
@ -16,7 +21,7 @@ pub struct Block {
pub block_type: BlockType,
}
const CHUNK_SIZE: usize = 16;
pub(crate) const CHUNK_SIZE: usize = 16;
type ChunkBlocks = [[[Option<Block>; CHUNK_SIZE]; CHUNK_SIZE]; CHUNK_SIZE];
@ -85,6 +90,12 @@ impl Chunk {
block_type: BlockType::Grass,
});
}
if chunk_y == 0 {
blocks[0][z][x] = Some(Block {
block_type: BlockType::Bedrock,
});
}
}
}
@ -95,53 +106,91 @@ impl Chunk {
}
fn check_visible(&self, x: usize, y: usize, z: usize) -> bool {
(x > 0 && y > 0 && z > 0 && self.get_block(x - 1, y - 1, z - 1).is_some())
&& (y > 0 && z > 0 && self.get_block(x + 1, y - 1, z - 1).is_some())
&& (x > 0 && z > 0 && self.get_block(x - 1, y + 1, z - 1).is_some())
&& (z > 0 && self.get_block(x + 1, y + 1, z - 1).is_some())
&& (x > 0 && y > 0 && self.get_block(x - 1, y - 1, z + 1).is_some())
&& (y > 0 && self.get_block(x + 1, y - 1, z + 1).is_some())
&& (x > 0 && self.get_block(x - 1, y + 1, z + 1).is_some())
&& (x > 0 && y > 0 && z > 0 && self.get_block(x + 1, y + 1, z + 1).is_some())
self.get_block(x - 1, y - 1, z - 1).is_some()
&& self.get_block(x + 1, y - 1, z - 1).is_some()
&& self.get_block(x - 1, y + 1, z - 1).is_some()
&& self.get_block(x + 1, y + 1, z - 1).is_some()
&& self.get_block(x - 1, y - 1, z + 1).is_some()
&& self.get_block(x + 1, y - 1, z + 1).is_some()
&& self.get_block(x - 1, y + 1, z + 1).is_some()
&& self.get_block(x + 1, y + 1, z + 1).is_some()
}
pub fn to_instances(&self, offset: Vector3<i32>) -> Vec<(BlockType, Vec<Instance>)> {
let mut map: AHashMap<BlockType, Vec<Instance>> = AHashMap::new();
pub fn to_instances(&self, offset: Vector3<i32>) -> (Vec<Vertex>, Vec<u16>) {
let mut quads: Vec<(BlockType, i32, Vector3<i32>, Quad)> = Vec::new();
for (y, y_blocks) in self.blocks.iter().enumerate() {
let mut culled = AHashMap::new();
let mut todo = VecDeque::new();
for (z, z_blocks) in y_blocks.iter().enumerate() {
for (x, block) in z_blocks.iter().enumerate() {
if let Some(block) = block {
let position = Vector3::new(
(x as i32 + offset.x * 16) as f32,
(y as i32 + offset.y * 16) as f32,
(z as i32 + offset.z * 16) as f32,
);
// Don't add the block if it's not visible
if self.check_visible(x, y, z) {
continue;
}
let instances = map.entry(block.block_type).or_default();
instances.push(Instance {
position: position.into(),
highlighted: (self.highlighted == Some(Vector3::new(x, y, z))) as i32,
});
culled.insert((x, z), block.block_type);
todo.push_back((x, z));
}
}
}
let mut visited = AHashSet::new();
while let Some((x, z)) = todo.pop_front() {
if visited.contains(&(x, z)) {
continue;
}
visited.insert((x, z));
if let Some(&block_type) = &culled.get(&(x, z)) {
// Extend horizontally
let mut xmax = x + 1;
for x_ in x..CHUNK_SIZE {
xmax = x_ + 1;
if culled.get(&(x_ + 1, z)) != Some(&block_type)
|| visited.contains(&(x_ + 1, z))
{
break;
}
visited.insert((x_ + 1, z));
}
// Extend vertically
let mut zmax = z + 1;
'z: for z_ in z..CHUNK_SIZE {
zmax = z_ + 1;
for x_ in x..xmax {
if culled.get(&(x_, z_ + 1)) != Some(&block_type)
|| visited.contains(&(x_, z_ + 1))
{
break 'z;
}
}
for x_ in x..xmax {
visited.insert((x_, z_ + 1));
}
}
let quad = Quad::new(x as i32, z as i32, (xmax - x) as i32, (zmax - z) as i32);
quads.push((block_type, y as i32, offset, quad));
}
}
}
map.drain().collect()
}
let mut vertices = Vec::new();
let mut indices = Vec::new();
for (quad_index, (_, y, offset, quad)) in quads.iter().enumerate() {
#[rustfmt::skip]
let v = cube::vertices(quad, *y, *offset, (0, 1), (0, 1), (0, 1), (0, 1), (0, 1), (0, 1));
vertices.extend(&v);
pub fn get_mut_block(&mut self, x: usize, y: usize, z: usize) -> Option<&mut Block> {
self.blocks
.get_mut(y)
.and_then(|blocks| blocks.get_mut(z))
.and_then(|blocks| blocks.get_mut(x))
.and_then(|block| block.as_mut())
for index in cube::INDICES {
indices.push(index + quad_index as u16 * 24);
}
}
(vertices, indices)
}
pub fn get_block(&self, x: usize, y: usize, z: usize) -> Option<&Block> {

View file

@ -1,82 +1,67 @@
use crate::vertex::Vertex;
use cgmath::Vector3;
#[rustfmt::skip]
pub const VERTICES: &[Vertex] = &[
// Left
Vertex { position: [0.0, 0.0, 0.0], texture_coordinates: [1.0, 1.0], normal: [-1.0, 0.0, 0.0] },
Vertex { position: [0.0, 0.0, 1.0], texture_coordinates: [0.0, 1.0], normal: [-1.0, 0.0, 0.0] },
Vertex { position: [0.0, 1.0, 1.0], texture_coordinates: [0.0, 0.0], normal: [-1.0, 0.0, 0.0] },
Vertex { position: [0.0, 1.0, 0.0], texture_coordinates: [1.0, 0.0], normal: [-1.0, 0.0, 0.0] },
use crate::{quad::Quad, vertex::Vertex};
// Right
Vertex { position: [1.0, 0.0, 0.0], texture_coordinates: [0.0, 1.0], normal: [ 1.0, 0.0, 0.0] },
Vertex { position: [1.0, 0.0, 1.0], texture_coordinates: [1.0, 1.0], normal: [ 1.0, 0.0, 0.0] },
Vertex { position: [1.0, 1.0, 1.0], texture_coordinates: [1.0, 0.0], normal: [ 1.0, 0.0, 0.0] },
Vertex { position: [1.0, 1.0, 0.0], texture_coordinates: [0.0, 0.0], normal: [ 1.0, 0.0, 0.0] },
const S: f32 = 512.0 / 4096.0;
// Back
Vertex { position: [0.0, 0.0, 0.0], texture_coordinates: [1.0, 1.0], normal: [ 0.0, 0.0, -1.0] },
Vertex { position: [0.0, 1.0, 0.0], texture_coordinates: [1.0, 0.0], normal: [ 0.0, 0.0, -1.0] },
Vertex { position: [1.0, 1.0, 0.0], texture_coordinates: [0.0, 0.0], normal: [ 0.0, 0.0, -1.0] },
Vertex { position: [1.0, 0.0, 0.0], texture_coordinates: [0.0, 1.0], normal: [ 0.0, 0.0, -1.0] },
pub fn vertices(
quad: &Quad,
y: i32,
offset: Vector3<i32>,
left: (i32, i32),
right: (i32, i32),
back: (i32, i32),
front: (i32, i32),
bottom: (i32, i32),
top: (i32, i32),
) -> [Vertex; 24] {
let w = quad.w as f32;
let h = quad.h as f32;
// Front
Vertex { position: [0.0, 0.0, 1.0], texture_coordinates: [0.0, 1.0], normal: [ 0.0, 0.0, 1.0] },
Vertex { position: [0.0, 1.0, 1.0], texture_coordinates: [0.0, 0.0], normal: [ 0.0, 0.0, 1.0] },
Vertex { position: [1.0, 1.0, 1.0], texture_coordinates: [1.0, 0.0], normal: [ 0.0, 0.0, 1.0] },
Vertex { position: [1.0, 0.0, 1.0], texture_coordinates: [1.0, 1.0], normal: [ 0.0, 0.0, 1.0] },
let x = (quad.x + offset.x) as f32;
let y = (y + offset.y) as f32;
let z = (quad.y + offset.z) as f32;
// Bottom
Vertex { position: [0.0, 0.0, 0.0], texture_coordinates: [1.0, 0.0], normal: [ 0.0, -1.0, 0.0] },
Vertex { position: [0.0, 0.0, 1.0], texture_coordinates: [1.0, 1.0], normal: [ 0.0, -1.0, 0.0] },
Vertex { position: [1.0, 0.0, 1.0], texture_coordinates: [0.0, 1.0], normal: [ 0.0, -1.0, 0.0] },
Vertex { position: [1.0, 0.0, 0.0], texture_coordinates: [0.0, 0.0], normal: [ 0.0, -1.0, 0.0] },
#[rustfmt::skip]
let vertices = [
// Left
Vertex { position: [x, y, z ], texture_coordinates: [left.0 as f32 * S + S, left.1 as f32 * S + S], normal: [-1.0, 0.0, 0.0] },
Vertex { position: [x, y, z + h ], texture_coordinates: [left.0 as f32 * S, left.1 as f32 * S + S], normal: [-1.0, 0.0, 0.0] },
Vertex { position: [x, y + 1.0, z + h ], texture_coordinates: [left.0 as f32 * S, left.1 as f32 * S ], normal: [-1.0, 0.0, 0.0] },
Vertex { position: [x, y + 1.0, z ], texture_coordinates: [left.0 as f32 * S + S, left.1 as f32 * S ], normal: [-1.0, 0.0, 0.0] },
// Top
Vertex { position: [0.0, 1.0, 0.0], texture_coordinates: [0.0, 0.0], normal: [ 0.0, 1.0, 0.0] },
Vertex { position: [0.0, 1.0, 1.0], texture_coordinates: [0.0, 1.0], normal: [ 0.0, 1.0, 0.0] },
Vertex { position: [1.0, 1.0, 1.0], texture_coordinates: [1.0, 1.0], normal: [ 0.0, 1.0, 0.0] },
Vertex { position: [1.0, 1.0, 0.0], texture_coordinates: [1.0, 0.0], normal: [ 0.0, 1.0, 0.0] },
];
// Right
Vertex { position: [x + w, y, z ], texture_coordinates: [right.0 as f32 * S, right.1 as f32 * S + S], normal: [1.0, 0.0, 0.0] },
Vertex { position: [x + w, y, z + h ], texture_coordinates: [right.0 as f32 * S + S, right.1 as f32 * S + S], normal: [1.0, 0.0, 0.0] },
Vertex { position: [x + w, y + 1.0, z + h ], texture_coordinates: [right.0 as f32 * S + S, right.1 as f32 * S ], normal: [1.0, 0.0, 0.0] },
Vertex { position: [x + w, y + 1.0, z ], texture_coordinates: [right.0 as f32 * S, right.1 as f32 * S ], normal: [1.0, 0.0, 0.0] },
#[rustfmt::skip]
pub const VERTICES_GRASS: &[Vertex] = &[
// Left
Vertex { position: [0.0, 0.0, 0.0], texture_coordinates: [0.5, 0.5], normal: [-1.0, 0.0, 0.0] },
Vertex { position: [0.0, 0.0, 1.0], texture_coordinates: [0.0, 0.5], normal: [-1.0, 0.0, 0.0] },
Vertex { position: [0.0, 1.0, 1.0], texture_coordinates: [0.0, 0.0], normal: [-1.0, 0.0, 0.0] },
Vertex { position: [0.0, 1.0, 0.0], texture_coordinates: [0.5, 0.0], normal: [-1.0, 0.0, 0.0] },
// Back
Vertex { position: [x, y, z ], texture_coordinates: [back.0 as f32 * S + S, back.1 as f32 * S + S], normal: [0.0, 0.0, -1.0] },
Vertex { position: [x, y + 1.0, z ], texture_coordinates: [back.0 as f32 * S + S, back.1 as f32 * S ], normal: [0.0, 0.0, -1.0] },
Vertex { position: [x + w, y + 1.0, z ], texture_coordinates: [back.0 as f32 * S, back.1 as f32 * S ], normal: [0.0, 0.0, -1.0] },
Vertex { position: [x + w, y, z ], texture_coordinates: [back.0 as f32 * S, back.1 as f32 * S + S], normal: [0.0, 0.0, -1.0] },
// Right
Vertex { position: [1.0, 0.0, 0.0], texture_coordinates: [0.0, 0.5], normal: [ 1.0, 0.0, 0.0] },
Vertex { position: [1.0, 0.0, 1.0], texture_coordinates: [0.5, 0.5], normal: [ 1.0, 0.0, 0.0] },
Vertex { position: [1.0, 1.0, 1.0], texture_coordinates: [0.5, 0.0], normal: [ 1.0, 0.0, 0.0] },
Vertex { position: [1.0, 1.0, 0.0], texture_coordinates: [0.0, 0.0], normal: [ 1.0, 0.0, 0.0] },
// Front
Vertex { position: [x, y, z + h], texture_coordinates: [front.0 as f32 * S, front.1 as f32 * S + S], normal: [0.0, 0.0, 1.0] },
Vertex { position: [x, y + 1.0, z + h], texture_coordinates: [front.0 as f32 * S, front.1 as f32 * S ], normal: [0.0, 0.0, 1.0] },
Vertex { position: [x + w, y + 1.0, z + h], texture_coordinates: [front.0 as f32 * S + S, front.1 as f32 * S ], normal: [0.0, 0.0, 1.0] },
Vertex { position: [x + w, y, z + h], texture_coordinates: [front.0 as f32 * S + S, front.1 as f32 * S + S], normal: [0.0, 0.0, 1.0] },
// Back
Vertex { position: [0.0, 0.0, 0.0], texture_coordinates: [0.5, 0.5], normal: [ 0.0, 0.0, -1.0] },
Vertex { position: [0.0, 1.0, 0.0], texture_coordinates: [0.5, 0.0], normal: [ 0.0, 0.0, -1.0] },
Vertex { position: [1.0, 1.0, 0.0], texture_coordinates: [0.0, 0.0], normal: [ 0.0, 0.0, -1.0] },
Vertex { position: [1.0, 0.0, 0.0], texture_coordinates: [0.0, 0.5], normal: [ 0.0, 0.0, -1.0] },
// Bottom
Vertex { position: [x, y, z + 0.0], texture_coordinates: [bottom.0 as f32 * S + S, bottom.1 as f32 * S ], normal: [0.0, -1.0, 0.0] },
Vertex { position: [x, y, z + h ], texture_coordinates: [bottom.0 as f32 * S + S, bottom.1 as f32 * S + S], normal: [0.0, -1.0, 0.0] },
Vertex { position: [x + w, y, z + h ], texture_coordinates: [bottom.0 as f32 * S, bottom.1 as f32 * S + S], normal: [0.0, -1.0, 0.0] },
Vertex { position: [x + w, y, z ], texture_coordinates: [bottom.0 as f32 * S, bottom.1 as f32 * S ], normal: [0.0, -1.0, 0.0] },
// Front
Vertex { position: [0.0, 0.0, 1.0], texture_coordinates: [0.0, 0.5], normal: [ 0.0, 0.0, 1.0] },
Vertex { position: [0.0, 1.0, 1.0], texture_coordinates: [0.0, 0.0], normal: [ 0.0, 0.0, 1.0] },
Vertex { position: [1.0, 1.0, 1.0], texture_coordinates: [0.5, 0.0], normal: [ 0.0, 0.0, 1.0] },
Vertex { position: [1.0, 0.0, 1.0], texture_coordinates: [0.5, 0.5], normal: [ 0.0, 0.0, 1.0] },
// Bottom
Vertex { position: [0.0, 0.0, 0.0], texture_coordinates: [0.5, 0.5], normal: [ 0.0, -1.0, 0.0] },
Vertex { position: [0.0, 0.0, 1.0], texture_coordinates: [0.5, 1.0], normal: [ 0.0, -1.0, 0.0] },
Vertex { position: [1.0, 0.0, 1.0], texture_coordinates: [0.0, 1.0], normal: [ 0.0, -1.0, 0.0] },
Vertex { position: [1.0, 0.0, 0.0], texture_coordinates: [0.0, 0.5], normal: [ 0.0, -1.0, 0.0] },
// Top
Vertex { position: [0.0, 1.0, 0.0], texture_coordinates: [0.5, 0.0], normal: [ 0.0, 1.0, 0.0] },
Vertex { position: [0.0, 1.0, 1.0], texture_coordinates: [0.5, 0.5], normal: [ 0.0, 1.0, 0.0] },
Vertex { position: [1.0, 1.0, 1.0], texture_coordinates: [1.0, 0.5], normal: [ 0.0, 1.0, 0.0] },
Vertex { position: [1.0, 1.0, 0.0], texture_coordinates: [1.0, 0.0], normal: [ 0.0, 1.0, 0.0] },
];
// Top
Vertex { position: [x, y + 1.0, z ], texture_coordinates: [top.0 as f32 * S, top.1 as f32 * S ], normal: [0.0, 1.0, 0.0] },
Vertex { position: [x, y + 1.0, z + h], texture_coordinates: [top.0 as f32 * S, top.1 as f32 * S + S], normal: [0.0, 1.0, 0.0] },
Vertex { position: [x + w, y + 1.0, z + h], texture_coordinates: [top.0 as f32 * S + S, top.1 as f32 * S + S], normal: [0.0, 1.0, 0.0] },
Vertex { position: [x + w, y + 1.0, z ], texture_coordinates: [top.0 as f32 * S + S, top.1 as f32 * S ], normal: [0.0, 1.0, 0.0] },
];
vertices
}
#[rustfmt::skip]
pub const INDICES: &[u16] = &[

View file

@ -1,30 +0,0 @@
#[repr(C)]
#[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
pub struct Instance {
pub position: [f32; 3],
pub highlighted: i32,
}
impl Instance {
pub fn desc<'a>() -> wgpu::VertexBufferLayout<'a> {
use std::mem;
wgpu::VertexBufferLayout {
array_stride: mem::size_of::<Self>() as wgpu::BufferAddress,
step_mode: wgpu::InputStepMode::Instance,
attributes: &[
// position: [f32; 3]
wgpu::VertexAttribute {
offset: 0,
shader_location: 5,
format: wgpu::VertexFormat::Float32x3,
},
// highlighted: i32
wgpu::VertexAttribute {
offset: 12,
shader_location: 6,
format: wgpu::VertexFormat::Sint32,
},
],
}
}
}

View file

@ -2,8 +2,8 @@ mod aabb;
mod camera;
mod chunk;
mod cube;
mod instance;
mod light;
mod quad;
mod state;
mod texture;
mod uniforms;

13
src/quad.rs Normal file
View file

@ -0,0 +1,13 @@
#[derive(Debug)]
pub struct Quad {
pub x: i32,
pub y: i32,
pub w: i32,
pub h: i32,
}
impl Quad {
pub fn new(x: i32, y: i32, w: i32, h: i32) -> Self {
Quad { x, y, w, h }
}
}

View file

@ -27,23 +27,15 @@ struct VertexOutput {
[[location(0)]] texture_coordinates: vec2<f32>;
[[location(1)]] world_normal: vec3<f32>;
[[location(2)]] world_position: vec3<f32>;
[[location(3)]] highlighted: i32;
};
struct InstanceInput {
[[location(5)]] position: vec3<f32>;
[[location(6)]] highlighted: i32;
};
[[stage(vertex)]]
fn main(model: VertexInput, instance: InstanceInput) -> VertexOutput {
fn main(model: VertexInput) -> VertexOutput {
var out: VertexOutput;
out.texture_coordinates = model.texture_coordinates;
out.world_normal = model.normal;
out.world_position = model.position + instance.position;
out.world_position = model.position;
out.clip_position = uniforms.view_projection * vec4<f32>(out.world_position, 1.0);
out.highlighted = instance.highlighted;
return out;
}
@ -69,9 +61,6 @@ fn main(in: VertexOutput) -> [[location(0)]] vec4<f32> {
let specular_color = specular_strength * light.color;
var result: vec3<f32> = (ambient_color + diffuse_color + specular_color) * object_color.xyz;
if (in.highlighted != 0) {
result = result + 0.3;
}
return vec4<f32>(result, object_color.a);
}

View file

@ -1,19 +1,13 @@
use std::time::Duration;
use cgmath::{EuclideanSpace, InnerSpace, Rad};
use cgmath::{InnerSpace, Rad};
use wgpu::util::{BufferInitDescriptor, DeviceExt};
use winit::{
event::{DeviceEvent, ElementState, KeyboardInput, VirtualKeyCode},
window::Window,
};
use crate::{
chunk::{Block, BlockType},
cube,
texture::Texture,
vertex::Vertex,
world_state::WorldState,
};
use crate::{texture::Texture, vertex::Vertex, world_state::WorldState};
const UI_SCALE_X: f32 = 0.0045;
const UI_SCALE_Y: f32 = 0.008;
@ -387,33 +381,32 @@ impl State {
..
}) => self.input_keyboard(key, state),
DeviceEvent::Button {
button,
state: ElementState::Pressed,
} if self.mouse_grabbed => {
let camera = &self.world_state.camera;
// if let Some((pos, axis)) = self
// .world_state
// .chunk
// .raycast(camera.position.to_vec(), camera.direction())
// {
// if *button == 1 {
// self.world_state.chunk.blocks[pos.y][pos.z][pos.x].take();
// dbg!(&pos);
// self.world_state.update_chunk(&self.render_queue);
// } else if *button == 3 {
// let new_pos = pos.map(|x| x as i32) - axis;
// dbg!(&axis, &new_pos);
// self.world_state.chunk.blocks[new_pos.y as usize][new_pos.z as usize]
// [new_pos.x as usize] = Some(Block {
// block_type: BlockType::Cobblestone,
// });
// self.world_state.update_chunk(&self.render_queue);
// }
// }
}
// DeviceEvent::Button {
// button,
// state: ElementState::Pressed,
// } if self.mouse_grabbed => {
// let camera = &self.world_state.camera;
// // if let Some((pos, axis)) = self
// // .world_state
// // .chunk
// // .raycast(camera.position.to_vec(), camera.direction())
// // {
// // if *button == 1 {
// // self.world_state.chunk.blocks[pos.y][pos.z][pos.x].take();
// // dbg!(&pos);
// // self.world_state.update_chunk(&self.render_queue);
// // } else if *button == 3 {
// // let new_pos = pos.map(|x| x as i32) - axis;
// // dbg!(&axis, &new_pos);
// // self.world_state.chunk.blocks[new_pos.y as usize][new_pos.z as usize]
// // [new_pos.x as usize] = Some(Block {
// // block_type: BlockType::Cobblestone,
// // });
// // self.world_state.update_chunk(&self.render_queue);
// // }
// // }
// }
DeviceEvent::MouseMotion { delta: (dx, dy) } => self.input_mouse(*dx, *dy),
_ => (),
}
@ -486,33 +479,16 @@ impl State {
render_pass.set_bind_group(1, &self.world_state.uniform_bind_group, &[]);
render_pass.set_bind_group(2, &self.world_state.light_bind_group, &[]);
render_pass.set_index_buffer(
self.world_state.index_buffer.slice(..),
wgpu::IndexFormat::Uint16,
);
// Set the texture
let texture_bind_group = &self.world_state.texture_bind_group;
render_pass.set_bind_group(0, texture_bind_group, &[]);
for (block_type, offset, instance_list) in &self.world_state.instance_lists {
// Set the texture
let texture_bind_group = &self.world_state.texture_bind_groups[block_type];
render_pass.set_bind_group(0, texture_bind_group, &[]);
for (chunk_vertices, chunk_indices, index_count) in &self.world_state.chunk_buffers {
render_pass.set_vertex_buffer(0, chunk_vertices.slice(..));
render_pass.set_index_buffer(chunk_indices.slice(..), wgpu::IndexFormat::Uint16);
// Set the vertex buffer
let vertex_buffer = match block_type {
BlockType::Grass => self.world_state.vertex_buffer_grass.slice(..),
_ => self.world_state.vertex_buffer.slice(..),
};
render_pass.set_vertex_buffer(0, vertex_buffer);
// Set the instance buffer
let instance_buffer = &self.world_state.instance_buffers[&(*block_type, *offset)];
render_pass.set_vertex_buffer(1, instance_buffer.slice(..));
render_pass.draw_indexed(
0..cube::INDICES.len() as u32,
0,
0..instance_list.len() as u32,
);
triangle_count += cube::INDICES.len() / 3 * instance_list.len();
render_pass.draw_indexed(0..*index_count as u32, 0, 0..1);
triangle_count += index_count / 3;
}
}
@ -539,6 +515,7 @@ impl State {
render_pass.set_bind_group(0, &self.ui_texture_bind_group, &[]);
render_pass.draw_indexed(0..CROSSHAIR_INDICES.len() as u32, 0, 0..1);
triangle_count += CROSSHAIR_INDICES.len() / 3;
}

View file

@ -59,6 +59,7 @@ impl Texture {
bytes: &[u8],
label: &str,
) -> anyhow::Result<Self> {
println!("decoding image");
let image = image::load_from_memory(bytes)?;
let rgba = image.into_rgba8();
let (width, height) = rgba.dimensions();
@ -69,6 +70,7 @@ impl Texture {
depth_or_array_layers: 1,
};
println!("creating texture");
let texture = device.create_texture(&wgpu::TextureDescriptor {
label: Some(label),
size: texture_size,
@ -79,6 +81,7 @@ impl Texture {
usage: wgpu::TextureUsage::SAMPLED | wgpu::TextureUsage::COPY_DST,
});
println!("writing texture");
queue.write_texture(
wgpu::ImageCopyTexture {
texture: &texture,
@ -94,13 +97,15 @@ impl Texture {
texture_size,
);
println!("creating texture view");
let view = texture.create_view(&wgpu::TextureViewDescriptor {
label: Some(&format!("texture_view_{}", label)),
dimension: Some(wgpu::TextureViewDimension::D2),
array_layer_count: NonZeroU32::new(1),
..wgpu::TextureViewDescriptor::default()
});
println!("done");
Ok(Self {
texture,
sampler: None,

View file

@ -1,23 +1,21 @@
use crate::{chunk::Chunk, vertex::Vertex};
use cgmath::Vector3;
use crate::{
chunk::{BlockType, Chunk},
instance::Instance,
};
pub struct World {
chunks: Vec<Vec<Vec<Chunk>>>,
}
const WORLD_SIZE: usize = 16;
impl World {
pub fn generate() -> Self {
let mut chunks = Vec::with_capacity(16);
for y in 0..16 {
let mut chunks_z = Vec::with_capacity(16);
for z in 0..16 {
let mut chunks_x = Vec::with_capacity(16);
for x in 0..16 {
let chunk = Chunk::generate(x, y, z);
let mut chunks = Vec::with_capacity(WORLD_SIZE);
for y in 0..WORLD_SIZE {
let mut chunks_z = Vec::with_capacity(WORLD_SIZE);
for z in 0..WORLD_SIZE {
let mut chunks_x = Vec::with_capacity(WORLD_SIZE);
for x in 0..WORLD_SIZE {
let chunk = Chunk::generate(x as i32, y as i32, z as i32);
chunks_x.push(chunk);
}
chunks_z.push(chunks_x);
@ -28,18 +26,15 @@ impl World {
Self { chunks }
}
pub fn to_instances(&self) -> Vec<(BlockType, Vector3<i32>, Vec<Instance>)> {
pub fn to_instances(&self) -> Vec<(Vec<Vertex>, Vec<u16>)> {
let instant = std::time::Instant::now();
let mut instance_lists = Vec::new();
let mut instances = Vec::new();
for (y, chunks_y) in self.chunks.iter().enumerate() {
for (z, chunks_z) in chunks_y.iter().enumerate() {
for (x, chunk) in chunks_z.iter().enumerate() {
let offset = Vector3::new(x as i32, y as i32, z as i32);
for (block_type, instances) in chunk.to_instances(offset) {
instance_lists.push((block_type, offset, instances));
}
let offset = Vector3::new(x as i32 * 16, y as i32 * 16, z as i32 * 16);
instances.push(chunk.to_instances(offset));
}
}
}
@ -47,6 +42,6 @@ impl World {
let elapsed = instant.elapsed();
println!("generating world instances took {:?}", elapsed);
instance_lists
instances
}
}

View file

@ -1,18 +1,11 @@
use std::{mem::size_of, time::Instant};
use std::time::Instant;
use ahash::AHashMap;
use cgmath::{Vector3, Zero};
use wgpu::{
util::{BufferInitDescriptor, DeviceExt},
BufferAddress, BufferDescriptor,
};
use cgmath::Vector3;
use wgpu::util::{BufferInitDescriptor, DeviceExt};
use winit::dpi::PhysicalSize;
use crate::{
camera::{Camera, Projection},
chunk::{Block, BlockType, Chunk},
cube,
instance::Instance,
light::Light,
texture::Texture,
uniforms::Uniforms,
@ -25,24 +18,21 @@ pub struct WorldState {
pub uniforms: Uniforms,
pub uniform_buffer: wgpu::Buffer,
pub uniform_bind_group: wgpu::BindGroup,
pub texture_bind_groups: AHashMap<BlockType, wgpu::BindGroup>,
pub texture_bind_group: wgpu::BindGroup,
pub camera: Camera,
pub projection: Projection,
pub instance_lists: Vec<(BlockType, Vector3<i32>, Vec<Instance>)>,
pub vertex_buffer: wgpu::Buffer,
pub vertex_buffer_grass: wgpu::Buffer,
pub index_buffer: wgpu::Buffer,
pub instance_buffers: AHashMap<(BlockType, Vector3<i32>), wgpu::Buffer>,
pub depth_texture: Texture,
pub light_bind_group: wgpu::BindGroup,
pub world: World,
pub chunk_buffers: Vec<(wgpu::Buffer, wgpu::Buffer, usize)>,
}
impl WorldState {
fn create_textures(
render_device: &wgpu::Device,
render_queue: &wgpu::Queue,
) -> (wgpu::BindGroupLayout, AHashMap<BlockType, wgpu::BindGroup>) {
) -> (wgpu::BindGroupLayout, wgpu::BindGroup) {
let sampler = render_device.create_sampler(&wgpu::SamplerDescriptor::default());
let bind_group_layout =
@ -71,39 +61,32 @@ impl WorldState {
],
});
let bind_groups: AHashMap<BlockType, wgpu::BindGroup> = [
(BlockType::Cobblestone, "assets/block/cobblestone.png"),
(BlockType::Dirt, "assets/block/dirt.png"),
(BlockType::Grass, "assets/block_temp/grass.png"),
(BlockType::Stone, "assets/block/stone.png"),
]
.iter()
.map(|(block_type, texture_path)| {
let bytes = std::fs::read(texture_path).unwrap();
let texture =
Texture::from_bytes(render_device, render_queue, &bytes, "block texture").unwrap();
let instant = std::time::Instant::now();
let texture = Texture::from_bytes(
render_device,
render_queue,
include_bytes!("../assets/atlas.png"),
"Block texture atlas",
)
.unwrap();
println!("loading block texture atlas took {:?}", instant.elapsed());
(
*block_type,
render_device.create_bind_group(&wgpu::BindGroupDescriptor {
label: Some("block texture bind group"),
layout: &bind_group_layout,
entries: &[
wgpu::BindGroupEntry {
binding: 0,
resource: wgpu::BindingResource::Sampler(&sampler),
},
wgpu::BindGroupEntry {
binding: 1,
resource: wgpu::BindingResource::TextureView(&texture.view),
},
],
}),
)
})
.collect();
let bind_group = render_device.create_bind_group(&wgpu::BindGroupDescriptor {
label: Some("Block texture atlas bind group"),
layout: &bind_group_layout,
entries: &[
wgpu::BindGroupEntry {
binding: 0,
resource: wgpu::BindingResource::Sampler(&sampler),
},
wgpu::BindGroupEntry {
binding: 1,
resource: wgpu::BindingResource::TextureView(&texture.view),
},
],
});
(bind_group_layout, bind_groups)
(bind_group_layout, bind_group)
}
fn create_camera(swap_chain_descriptor: &wgpu::SwapChainDescriptor) -> (Camera, Projection) {
@ -249,7 +232,7 @@ impl WorldState {
vertex: wgpu::VertexState {
module: &shader,
entry_point: "main",
buffers: &[Vertex::desc(), Instance::desc()],
buffers: &[Vertex::desc()],
},
fragment: Some(wgpu::FragmentState {
module: &shader,
@ -267,11 +250,7 @@ impl WorldState {
topology: wgpu::PrimitiveTopology::TriangleList,
strip_index_format: None,
front_face: wgpu::FrontFace::Ccw,
cull_mode: if wireframe {
None
} else {
Some(wgpu::Face::Back)
},
cull_mode: Some(wgpu::Face::Back),
polygon_mode: if wireframe {
wgpu::PolygonMode::Line
} else {
@ -295,47 +274,29 @@ impl WorldState {
})
}
fn create_instances(
render_device: &wgpu::Device,
world: &World,
) -> (
Vec<(BlockType, Vector3<i32>, Vec<Instance>)>,
AHashMap<(BlockType, Vector3<i32>), wgpu::Buffer>,
) {
let instance_lists = world.to_instances();
let instance_buffers = instance_lists
.iter()
.map(|(block_type, offset, _)| {
let buffer = render_device.create_buffer(&BufferDescriptor {
label: Some("instance_buffer"),
size: (size_of::<Instance>() * 16 * 16 * 16) as BufferAddress,
usage: wgpu::BufferUsage::VERTEX | wgpu::BufferUsage::COPY_DST,
mapped_at_creation: false,
});
((*block_type, *offset), buffer)
})
.collect();
(instance_lists, instance_buffers)
}
pub fn update_chunk(&mut self, render_queue: &wgpu::Queue) {
pub fn update_chunk(&mut self, render_device: &wgpu::Device) {
let instant = Instant::now();
self.instance_lists = self.world.to_instances();
for (block_type, offset, instance_list) in &self.instance_lists {
if let Some(instance_buffer) = self.instance_buffers.get_mut(&(*block_type, *offset)) {
render_queue.write_buffer(instance_buffer, 0, bytemuck::cast_slice(&instance_list));
} else {
todo!();
}
let world_geometry = self.world.to_instances();
self.chunk_buffers.clear();
for (chunk_vertices, chunk_indices) in world_geometry {
self.chunk_buffers.push((
render_device.create_buffer_init(&BufferInitDescriptor {
label: None,
contents: &bytemuck::cast_slice(&chunk_vertices),
usage: wgpu::BufferUsage::VERTEX,
}),
render_device.create_buffer_init(&BufferInitDescriptor {
label: None,
contents: &bytemuck::cast_slice(&chunk_indices),
usage: wgpu::BufferUsage::INDEX,
}),
chunk_indices.len(),
));
}
let elapsed = instant.elapsed();
println!("Chunk update took {:?}", elapsed);
println!("World update took {:?}", elapsed);
}
pub fn new(
@ -343,10 +304,9 @@ impl WorldState {
render_queue: &wgpu::Queue,
swap_chain_descriptor: &wgpu::SwapChainDescriptor,
) -> WorldState {
// let chunk = Chunk::generate(0, 0, 0);
let world = World::generate();
let (world_texture_layout, texture_bind_groups) =
let (world_texture_layout, texture_bind_group) =
Self::create_textures(&render_device, &render_queue);
let (camera, projection) = Self::create_camera(&swap_chain_descriptor);
@ -366,25 +326,6 @@ impl WorldState {
],
);
let vertex_buffer = render_device.create_buffer_init(&BufferInitDescriptor {
label: Some("vertex_buffer"),
contents: bytemuck::cast_slice(cube::VERTICES),
usage: wgpu::BufferUsage::VERTEX,
});
let grass_vertex_buffer = render_device.create_buffer_init(&BufferInitDescriptor {
label: Some("grass vertex buffer"),
contents: bytemuck::cast_slice(cube::VERTICES_GRASS),
usage: wgpu::BufferUsage::VERTEX,
});
let index_buffer = render_device.create_buffer_init(&BufferInitDescriptor {
label: Some("index_buffer"),
contents: bytemuck::cast_slice(cube::INDICES),
usage: wgpu::BufferUsage::INDEX,
});
let (instance_lists, instance_buffers) = Self::create_instances(&render_device, &world);
let depth_texture =
Texture::create_depth_texture(&render_device, &swap_chain_descriptor, "depth_texture");
@ -393,20 +334,16 @@ impl WorldState {
uniforms,
uniform_buffer,
uniform_bind_group,
texture_bind_groups,
texture_bind_group,
camera,
projection,
instance_lists,
vertex_buffer,
vertex_buffer_grass: grass_vertex_buffer,
index_buffer,
instance_buffers,
depth_texture,
light_bind_group,
world,
chunk_buffers: Vec::new(),
};
world_state.update_chunk(&render_queue);
world_state.update_chunk(render_device);
world_state
}