From ff20d5ad29138ab1d391ec2de806cd7a8d24d3c5 Mon Sep 17 00:00:00 2001 From: Vijfhoek Date: Mon, 31 May 2021 21:24:59 +0200 Subject: [PATCH] Add super cool water --- src/chunk.rs | 24 +++++++++++++--- src/cube.rs | 50 ++++++++++++++++++---------------- src/light.rs | 19 ------------- src/main.rs | 2 +- src/shaders/world.wgsl | 33 ++++++++++++++-------- src/state/mod.rs | 13 +++++---- src/state/world.rs | 62 ++++++++++++++++++++++-------------------- src/texture.rs | 6 +++- src/time.rs | 11 ++++++++ 9 files changed, 125 insertions(+), 95 deletions(-) delete mode 100644 src/light.rs create mode 100644 src/time.rs diff --git a/src/chunk.rs b/src/chunk.rs index 10547a9..3bbb1e8 100644 --- a/src/chunk.rs +++ b/src/chunk.rs @@ -15,6 +15,7 @@ pub enum BlockType { Bedrock, Sand, Gravel, + Water, } impl BlockType { @@ -28,6 +29,7 @@ impl BlockType { BlockType::Bedrock => ( 5, 5, 5, 5, 5, 5), BlockType::Sand => ( 6, 6, 6, 6, 6, 6), BlockType::Gravel => ( 7, 7, 7, 7, 7, 7), + BlockType::Water => ( 8, 8, 8, 8, 8, 8), // up to 71 }; indices } @@ -82,7 +84,7 @@ impl Chunk { let mut blocks: ChunkBlocks = Default::default(); for z in 0..CHUNK_SIZE { for x in 0..CHUNK_SIZE { - let v = terrain_noise.get_value(x, z) * 20.0 + 64.0; + let v = terrain_noise.get_value(x, z) * 20.0 + 128.0; let v = v.round() as i32; let s = stone_noise.get_value(x, z) * 20.0 + 4.5; @@ -113,6 +115,15 @@ impl Chunk { block_type: BlockType::Bedrock, }); } + if chunk_y < 128 / CHUNK_SIZE as i32 { + for y in 0..CHUNK_SIZE { + if blocks[y][z][x].is_none() { + blocks[y][z][x] = Some(Block { + block_type: BlockType::Water, + }); + } + } + } } } @@ -176,6 +187,12 @@ impl Chunk { visited.insert((x, z)); if let Some(&block_type) = &culled.get(&(x, z)) { + if block_type == BlockType::Water { + let quad = Quad::new(x as i32, z as i32, 1, 1); + quads.push((block_type, y as i32, offset, quad)); + continue; + } + // Extend horizontally let mut xmax = x + 1; for x_ in x..CHUNK_SIZE { @@ -218,9 +235,8 @@ impl Chunk { let mut vertices = Vec::new(); let mut indices = Vec::new(); for (quad_index, (block_type, y, offset, quad)) in quads.iter().enumerate() { - #[rustfmt::skip] - let v = cube::vertices(quad, *y, *offset, block_type.texture_indices()); - vertices.extend(&v); + let texture_indices = block_type.texture_indices(); + vertices.extend(&cube::vertices(quad, *y, 1.0, *offset, texture_indices)); for index in cube::INDICES { indices.push(index + quad_index as u16 * 24); diff --git a/src/cube.rs b/src/cube.rs index 863dbd9..24eb8d4 100644 --- a/src/cube.rs +++ b/src/cube.rs @@ -6,11 +6,13 @@ use crate::{quad::Quad, vertex::Vertex}; pub fn vertices( quad: &Quad, y: i32, + z_height: f32, offset: Vector3, texture_indices: (usize, usize, usize, usize, usize, usize), ) -> [Vertex; 24] { let w = quad.w as f32; let h = quad.h as f32; + let zh = z_height; let x = (quad.x + offset.x) as f32; let y = (y + offset.y) as f32; @@ -21,40 +23,40 @@ pub fn vertices( #[rustfmt::skip] let vertices = [ // Left - Vertex { position: [x, y, z ], texture_coordinates: [h, 1.0, t.0 as f32], normal: [-1.0, 0.0, 0.0] }, - Vertex { position: [x, y, z + h ], texture_coordinates: [0.0, 1.0, t.0 as f32], normal: [-1.0, 0.0, 0.0] }, - Vertex { position: [x, y + 1.0, z + h ], texture_coordinates: [0.0, 0.0, t.0 as f32], normal: [-1.0, 0.0, 0.0] }, - Vertex { position: [x, y + 1.0, z ], texture_coordinates: [h, 0.0, t.0 as f32], normal: [-1.0, 0.0, 0.0] }, + Vertex { position: [x, y, z ], texture_coordinates: [h, 1.0, t.0 as f32], normal: [-1.0, 0.0, 0.0] }, + Vertex { position: [x, y, z + h ], texture_coordinates: [0.0, 1.0, t.0 as f32], normal: [-1.0, 0.0, 0.0] }, + Vertex { position: [x, y + zh, z + h ], texture_coordinates: [0.0, 0.0, t.0 as f32], normal: [-1.0, 0.0, 0.0] }, + Vertex { position: [x, y + zh, z ], texture_coordinates: [h, 0.0, t.0 as f32], normal: [-1.0, 0.0, 0.0] }, // Right - Vertex { position: [x + w, y, z ], texture_coordinates: [0.0, 1.0, t.1 as f32], normal: [1.0, 0.0, 0.0] }, - Vertex { position: [x + w, y, z + h ], texture_coordinates: [h, 1.0, t.1 as f32], normal: [1.0, 0.0, 0.0] }, - Vertex { position: [x + w, y + 1.0, z + h ], texture_coordinates: [h, 0.0, t.1 as f32], normal: [1.0, 0.0, 0.0] }, - Vertex { position: [x + w, y + 1.0, z ], texture_coordinates: [0.0, 0.0, t.1 as f32], normal: [1.0, 0.0, 0.0] }, + Vertex { position: [x + w, y, z ], texture_coordinates: [0.0, 1.0, t.1 as f32], normal: [1.0, 0.0, 0.0] }, + Vertex { position: [x + w, y, z + h ], texture_coordinates: [h, 1.0, t.1 as f32], normal: [1.0, 0.0, 0.0] }, + Vertex { position: [x + w, y + zh, z + h ], texture_coordinates: [h, 0.0, t.1 as f32], normal: [1.0, 0.0, 0.0] }, + Vertex { position: [x + w, y + zh, z ], texture_coordinates: [0.0, 0.0, t.1 as f32], normal: [1.0, 0.0, 0.0] }, // Back - Vertex { position: [x, y, z ], texture_coordinates: [w, 1.0, t.2 as f32], normal: [0.0, 0.0, -1.0] }, - Vertex { position: [x, y + 1.0, z ], texture_coordinates: [w, 0.0, t.2 as f32], normal: [0.0, 0.0, -1.0] }, - Vertex { position: [x + w, y + 1.0, z ], texture_coordinates: [0.0, 0.0, t.2 as f32], normal: [0.0, 0.0, -1.0] }, - Vertex { position: [x + w, y, z ], texture_coordinates: [0.0, 1.0, t.2 as f32], normal: [0.0, 0.0, -1.0] }, + Vertex { position: [x, y, z ], texture_coordinates: [w, 1.0, t.2 as f32], normal: [0.0, 0.0, -1.0] }, + Vertex { position: [x, y + zh, z ], texture_coordinates: [w, 0.0, t.2 as f32], normal: [0.0, 0.0, -1.0] }, + Vertex { position: [x + w, y + zh, z ], texture_coordinates: [0.0, 0.0, t.2 as f32], normal: [0.0, 0.0, -1.0] }, + Vertex { position: [x + w, y, z ], texture_coordinates: [0.0, 1.0, t.2 as f32], normal: [0.0, 0.0, -1.0] }, // Front - Vertex { position: [x, y, z + h ], texture_coordinates: [0.0, 1.0, t.3 as f32], normal: [0.0, 0.0, 1.0] }, - Vertex { position: [x, y + 1.0, z + h ], texture_coordinates: [0.0, 0.0, t.3 as f32], normal: [0.0, 0.0, 1.0] }, - Vertex { position: [x + w, y + 1.0, z + h ], texture_coordinates: [w, 0.0, t.3 as f32], normal: [0.0, 0.0, 1.0] }, - Vertex { position: [x + w, y, z + h ], texture_coordinates: [w, 1.0, t.3 as f32], normal: [0.0, 0.0, 1.0] }, + Vertex { position: [x, y, z + h ], texture_coordinates: [0.0, 1.0, t.3 as f32], normal: [0.0, 0.0, 1.0] }, + Vertex { position: [x, y + zh, z + h ], texture_coordinates: [0.0, 0.0, t.3 as f32], normal: [0.0, 0.0, 1.0] }, + Vertex { position: [x + w, y + zh, z + h ], texture_coordinates: [w, 0.0, t.3 as f32], normal: [0.0, 0.0, 1.0] }, + Vertex { position: [x + w, y, z + h ], texture_coordinates: [w, 1.0, t.3 as f32], normal: [0.0, 0.0, 1.0] }, // Bottom - Vertex { position: [x, y, z + 0.0], texture_coordinates: [w, 0.0, t.4 as f32], normal: [0.0, -1.0, 0.0] }, - Vertex { position: [x, y, z + h ], texture_coordinates: [w, h, t.4 as f32], normal: [0.0, -1.0, 0.0] }, - Vertex { position: [x + w, y, z + h ], texture_coordinates: [0.0, h, t.4 as f32], normal: [0.0, -1.0, 0.0] }, - Vertex { position: [x + w, y, z ], texture_coordinates: [0.0, 0.0, t.4 as f32], normal: [0.0, -1.0, 0.0] }, + Vertex { position: [x, y, z + 0.0], texture_coordinates: [w, 0.0, t.4 as f32], normal: [0.0, -1.0, 0.0] }, + Vertex { position: [x, y, z + h ], texture_coordinates: [w, h, t.4 as f32], normal: [0.0, -1.0, 0.0] }, + Vertex { position: [x + w, y, z + h ], texture_coordinates: [0.0, h, t.4 as f32], normal: [0.0, -1.0, 0.0] }, + Vertex { position: [x + w, y, z ], texture_coordinates: [0.0, 0.0, t.4 as f32], normal: [0.0, -1.0, 0.0] }, // Top - Vertex { position: [x, y + 1.0, z ], texture_coordinates: [0.0, 0.0, t.5 as f32], normal: [0.0, 1.0, 0.0] }, - Vertex { position: [x, y + 1.0, z + h ], texture_coordinates: [0.0, h, t.5 as f32], normal: [0.0, 1.0, 0.0] }, - Vertex { position: [x + w, y + 1.0, z + h ], texture_coordinates: [w, h, t.5 as f32], normal: [0.0, 1.0, 0.0] }, - Vertex { position: [x + w, y + 1.0, z ], texture_coordinates: [w, 0.0, t.5 as f32], normal: [0.0, 1.0, 0.0] }, + Vertex { position: [x, y + zh, z ], texture_coordinates: [0.0, 0.0, t.5 as f32], normal: [0.0, 1.0, 0.0] }, + Vertex { position: [x, y + zh, z + h ], texture_coordinates: [0.0, h, t.5 as f32], normal: [0.0, 1.0, 0.0] }, + Vertex { position: [x + w, y + zh, z + h ], texture_coordinates: [w, h, t.5 as f32], normal: [0.0, 1.0, 0.0] }, + Vertex { position: [x + w, y + zh, z ], texture_coordinates: [w, 0.0, t.5 as f32], normal: [0.0, 1.0, 0.0] }, ]; vertices } diff --git a/src/light.rs b/src/light.rs deleted file mode 100644 index 6c332b1..0000000 --- a/src/light.rs +++ /dev/null @@ -1,19 +0,0 @@ -use cgmath::Vector3; - -#[repr(C)] -#[derive(Debug, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)] -pub struct Light { - pub position: [f32; 3], - pub _padding: u32, - pub color: [f32; 3], -} - -impl Light { - pub fn new(position: Vector3, color: Vector3) -> Self { - Self { - position: position.into(), - _padding: 0, - color: color.into(), - } - } -} diff --git a/src/main.rs b/src/main.rs index 9199fe5..0ac8f6f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,7 @@ mod camera; mod chunk; mod cube; -mod light; +mod time; mod quad; mod state; mod texture; diff --git a/src/shaders/world.wgsl b/src/shaders/world.wgsl index de57041..d844cef 100644 --- a/src/shaders/world.wgsl +++ b/src/shaders/world.wgsl @@ -5,16 +5,15 @@ struct Uniforms { }; [[block]] -struct Light { - position: vec3; - color: vec3; +struct Time { + time: f32; }; [[group(1), binding(0)]] var uniforms: Uniforms; [[group(2), binding(0)]] -var light: Light; +var time: Time; struct VertexInput { [[location(0)]] position: vec3; @@ -32,9 +31,18 @@ struct VertexOutput { [[stage(vertex)]] fn main(model: VertexInput) -> VertexOutput { var out: VertexOutput; - out.texture_coordinates = model.texture_coordinates; + out.world_normal = model.normal; - out.world_position = model.position; + if (model.texture_coordinates.z == 8.0) { + // water + let offset = (sin(time.time * 0.5 + model.position.x) * cos(time.time * 0.9 + model.position.y) + 2.5) / 10.0; + out.world_position = vec3(model.position.x, model.position.y - offset, model.position.z); + out.texture_coordinates = vec3(model.texture_coordinates.xy + (time.time / 10.0), 8.0 + (time.time * 10.0) % 64.0); + } else { + out.world_position = model.position; + out.texture_coordinates = model.texture_coordinates; + } + out.clip_position = uniforms.view_projection * vec4(out.world_position, 1.0); return out; } @@ -51,18 +59,21 @@ fn main(in: VertexOutput) -> [[location(0)]] vec4 { i32(in.texture_coordinates.z) ); - let ambient_strength = 0.1; - let ambient_color = light.color * ambient_strength; + let light_position = vec3(256.0, 500.0, 200.0); + let light_color = vec3(1.0, 1.0, 1.0); - let light_direction = normalize(light.position - in.world_position); + let ambient_strength = 0.1; + let ambient_color = light_color * ambient_strength; + + let light_direction = normalize(light_position - in.world_position); let view_direction = normalize(uniforms.view_position.xyz - in.world_position); let half_direction = normalize(view_direction + light_direction); let diffuse_strength = max(dot(in.world_normal, light_direction), 0.0); - let diffuse_color = light.color * diffuse_strength; + let diffuse_color = light_color * diffuse_strength; let specular_strength = pow(max(dot(in.world_normal, half_direction), 0.0), 32.0); - let specular_color = specular_strength * light.color; + let specular_color = specular_strength * light_color; var result: vec3 = (ambient_color + diffuse_color + specular_color) * object_color.xyz; diff --git a/src/state/mod.rs b/src/state/mod.rs index 018aa9b..2c89082 100644 --- a/src/state/mod.rs +++ b/src/state/mod.rs @@ -3,7 +3,7 @@ mod world; use std::time::Duration; -use cgmath::{InnerSpace, Rad}; +use cgmath::{InnerSpace, Rad, Vector3}; use winit::{ event::{DeviceEvent, ElementState, KeyboardInput, VirtualKeyCode}, window::Window, @@ -219,20 +219,23 @@ impl State { let (yaw_sin, yaw_cos) = self.world_state.camera.yaw.0.sin_cos(); - let forward = cgmath::Vector3::new(yaw_cos, 0.0, yaw_sin).normalize(); + let forward = Vector3::new(yaw_cos, 0.0, yaw_sin).normalize(); self.world_state.camera.position += forward * self.forward_speed * 15.0 * dt_secs; - let right = cgmath::Vector3::new(-yaw_sin, 0.0, yaw_cos).normalize(); + let right = Vector3::new(-yaw_sin, 0.0, yaw_cos).normalize(); self.world_state.camera.position += right * self.right_speed * 15.0 * dt_secs; - let up = cgmath::Vector3::new(0.0, 1.0, 0.0).normalize(); + let up = Vector3::new(0.0, 1.0, 0.0).normalize(); self.world_state.camera.position += up * self.up_speed * 15.0 * dt_secs; + self.world_state.update(dt, &self.render_queue); + self.update_aim(); self.world_state .uniforms .update_view_projection(&self.world_state.camera, &self.world_state.projection); + self.render_queue.write_buffer( &self.world_state.uniform_buffer, 0, @@ -280,7 +283,7 @@ impl State { let tm = &self.world_state.texture_manager; render_pass.set_bind_group(0, tm.bind_group.as_ref().unwrap(), &[]); 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_bind_group(2, &self.world_state.time_bind_group, &[]); for (chunk_vertices, chunk_indices, index_count) in &self.world_state.chunk_buffers { render_pass.set_vertex_buffer(0, chunk_vertices.slice(..)); diff --git a/src/state/world.rs b/src/state/world.rs index 89767f9..4fec407 100644 --- a/src/state/world.rs +++ b/src/state/world.rs @@ -1,13 +1,12 @@ -use std::time::Instant; +use std::time::{Duration, Instant}; -use cgmath::Vector3; use wgpu::util::{BufferInitDescriptor, DeviceExt}; use winit::dpi::PhysicalSize; use crate::{ camera::{Camera, Projection}, - light::Light, texture::{Texture, TextureManager}, + time::Time, uniforms::Uniforms, vertex::Vertex, world::World, @@ -22,10 +21,12 @@ pub struct WorldState { pub camera: Camera, pub projection: Projection, pub depth_texture: Texture, - pub light_bind_group: wgpu::BindGroup, + pub time_bind_group: wgpu::BindGroup, pub world: World, pub chunk_buffers: Vec<(wgpu::Buffer, wgpu::Buffer, usize)>, + time: Time, + time_buffer: wgpu::Buffer, } impl WorldState { @@ -39,8 +40,8 @@ impl WorldState { fn create_camera(swap_chain_descriptor: &wgpu::SwapChainDescriptor) -> (Camera, Projection) { let camera = Camera::new( - (0.0, 80.0, 0.0).into(), - cgmath::Deg(0.0).into(), + (-10.0, 140.0, -10.0).into(), + cgmath::Deg(45.0).into(), cgmath::Deg(-20.0).into(), ); @@ -106,21 +107,18 @@ impl WorldState { ) } - fn create_light( + fn create_time( render_device: &wgpu::Device, - ) -> (Light, wgpu::Buffer, wgpu::BindGroupLayout, wgpu::BindGroup) { - let light = Light::new( - Vector3::new(256.0, 500.0, 200.0), - Vector3::new(1.0, 1.0, 1.0), - ); + ) -> (Time, wgpu::Buffer, wgpu::BindGroupLayout, wgpu::BindGroup) { + let time = Time::new(); - let light_buffer = render_device.create_buffer_init(&BufferInitDescriptor { - label: Some("light_buffer"), - contents: bytemuck::cast_slice(&[light]), + let buffer = render_device.create_buffer_init(&BufferInitDescriptor { + label: Some("time_buffer"), + contents: bytemuck::cast_slice(&[time]), usage: wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST, }); - let light_bind_group_layout = + let bind_group_layout = render_device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { entries: &[wgpu::BindGroupLayoutEntry { binding: 0, @@ -132,24 +130,19 @@ impl WorldState { }, count: None, }], - label: Some("light_bind_group_layout"), + label: Some("time_bind_group_layout"), }); - let light_bind_group = render_device.create_bind_group(&wgpu::BindGroupDescriptor { - layout: &light_bind_group_layout, + let bind_group = render_device.create_bind_group(&wgpu::BindGroupDescriptor { + layout: &bind_group_layout, entries: &[wgpu::BindGroupEntry { binding: 0, - resource: light_buffer.as_entire_binding(), + resource: buffer.as_entire_binding(), }], - label: Some("light_bind_group"), + label: Some("time_bind_group"), }); - ( - light, - light_buffer, - light_bind_group_layout, - light_bind_group, - ) + (time, buffer, bind_group_layout, bind_group) } fn create_render_pipeline( @@ -253,7 +246,7 @@ impl WorldState { let (uniforms, uniform_buffer, world_uniform_layout, uniform_bind_group) = Self::create_uniforms(&camera, &projection, render_device); - let (_, _, world_light_layout, light_bind_group) = Self::create_light(&render_device); + let (time, time_buffer, time_layout, time_bind_group) = Self::create_time(&render_device); let render_pipeline = Self::create_render_pipeline( &render_device, @@ -261,7 +254,7 @@ impl WorldState { &[ &texture_manager.bind_group_layout, &world_uniform_layout, - &world_light_layout, + &time_layout, ], ); @@ -277,7 +270,11 @@ impl WorldState { camera, projection, depth_texture, - light_bind_group, + + time, + time_buffer, + time_bind_group, + world, chunk_buffers: Vec::new(), }; @@ -287,6 +284,11 @@ impl WorldState { world_state } + pub fn update(&mut self, dt: Duration, render_queue: &wgpu::Queue) { + self.time.time += dt.as_secs_f32(); + render_queue.write_buffer(&self.time_buffer, 0, &bytemuck::cast_slice(&[self.time])); + } + pub fn resize( &mut self, render_device: &wgpu::Device, diff --git a/src/texture.rs b/src/texture.rs index 257c485..4841699 100644 --- a/src/texture.rs +++ b/src/texture.rs @@ -111,7 +111,7 @@ impl Texture { } } -pub const TEXTURE_COUNT: usize = 8; +pub const TEXTURE_COUNT: usize = 72; pub struct TextureManager { pub bind_group_layout: wgpu::BindGroupLayout, @@ -174,6 +174,10 @@ impl TextureManager { self.load(device, queue, "assets/block/bedrock.png")?; // 5 self.load(device, queue, "assets/block/sand.png")?; // 6 self.load(device, queue, "assets/block/gravel.png")?; // 7 + for i in 0..64 { + let path = format!("assets/water_still_plains/frame-{}.png", i); + self.load(device, queue, &path)?; // 8 - 71 + } assert_eq!(TEXTURE_COUNT, self.textures.len()); let texture_array = device.create_texture(&wgpu::TextureDescriptor { diff --git a/src/time.rs b/src/time.rs new file mode 100644 index 0000000..ca80f48 --- /dev/null +++ b/src/time.rs @@ -0,0 +1,11 @@ +#[repr(C)] +#[derive(Debug, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)] +pub struct Time { + pub time: f32, +} + +impl Time { + pub fn new() -> Self { + Self { time: 0.0 } + } +}