materials, brick and nodes structure, preparing for world generation
This commit is contained in:
+46
-3
@@ -5,19 +5,62 @@ use winit::{
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
mod camera_controller; use camera_controller::CameraController;
|
mod camera_controller; use camera_controller::CameraController;
|
||||||
|
mod world_gen; use world_gen::WorldGen;
|
||||||
use crate::renderer::Renderer;
|
use crate::renderer::Renderer;
|
||||||
|
//use crate::renderer::BrickData;
|
||||||
|
|
||||||
pub struct App {
|
pub struct App {
|
||||||
pub window: Window,
|
pub window: Window,
|
||||||
pub renderer: Renderer,
|
pub renderer: Renderer,
|
||||||
|
world_gen: WorldGen,
|
||||||
camera_controller: CameraController,
|
camera_controller: CameraController,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl App {
|
impl App {
|
||||||
pub fn new(window: Window, renderer: Renderer) -> Self {
|
pub fn new(window: Window) -> Self {
|
||||||
|
let mut renderer = futures::executor::block_on(Renderer::new(&window));
|
||||||
let camera_controller = CameraController::new();
|
let camera_controller = CameraController::new();
|
||||||
Self { window, renderer, camera_controller }
|
let mut world_gen = WorldGen::new();
|
||||||
|
|
||||||
|
|
||||||
|
// let start = std::time::Instant::now();
|
||||||
|
// for x in 0..128 {
|
||||||
|
// for z in 0..128 {
|
||||||
|
// // Dirt
|
||||||
|
// for y in 0..31 {
|
||||||
|
// renderer.set_voxel(x, y, z, 1);
|
||||||
|
// }
|
||||||
|
// // Grass
|
||||||
|
// renderer.set_voxel(x, 31, z, 2);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// println!("Generated in {}ms", start.elapsed().as_millis());
|
||||||
|
|
||||||
|
|
||||||
|
let start = std::time::Instant::now();
|
||||||
|
for bx in 0..4 {
|
||||||
|
for bz in 0..4 {
|
||||||
|
|
||||||
|
let brick_id = renderer.brick_get_id(bx, 0, bz);
|
||||||
|
renderer.brick_mark_changed(brick_id);
|
||||||
|
for x in 0..32 {
|
||||||
|
for z in 0..32 {
|
||||||
|
// Dirt
|
||||||
|
for y in 0..31 {
|
||||||
|
renderer.brick_set_voxel(brick_id, x, y, z, 1);
|
||||||
|
}
|
||||||
|
// Grass
|
||||||
|
renderer.brick_set_voxel(brick_id, x, 31, z, 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println!("Generated in {}ms", start.elapsed().as_millis());
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Self { window, renderer, camera_controller, world_gen }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn input(&mut self, event: Arc<Event<()>>) {
|
pub fn input(&mut self, event: Arc<Event<()>>) {
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
use std::sync::Arc;
|
||||||
|
use crate::renderer::Renderer;
|
||||||
|
|
||||||
|
pub struct WorldGen {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WorldGen {
|
||||||
|
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self{}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn generate(&mut self, renderer: Renderer) {
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-2
@@ -20,8 +20,7 @@ fn main() {
|
|||||||
.with_inner_size(LogicalSize::new(1280.0, 720.0))
|
.with_inner_size(LogicalSize::new(1280.0, 720.0))
|
||||||
.build(&events)
|
.build(&events)
|
||||||
.expect("Failed to create window");
|
.expect("Failed to create window");
|
||||||
let _renderer = futures::executor::block_on(Renderer::new(&_window));
|
let mut app = App::new(_window);
|
||||||
let mut app = App::new(_window, _renderer);
|
|
||||||
|
|
||||||
// Stats
|
// Stats
|
||||||
let mut fps_timer = std::time::Instant::now();
|
let mut fps_timer = std::time::Instant::now();
|
||||||
|
|||||||
@@ -1,42 +1,22 @@
|
|||||||
use wgpu::util::DeviceExt;
|
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
use rand::prelude::*;
|
|
||||||
|
|
||||||
const BRICK_SIZE : usize = 32; // 32x32x32 brick size
|
use crate::renderer::buffers::{BRICK_SIZE, BRICK_NUM, BRICK_LEN};
|
||||||
const BRICK_NUM : usize = 10000; // x bricks in texture
|
|
||||||
|
|
||||||
const BRICK_LEN : usize = BRICK_SIZE*BRICK_SIZE*BRICK_SIZE;
|
|
||||||
const DATA_LEN : usize = BRICK_LEN * BRICK_NUM;
|
const DATA_LEN : usize = BRICK_LEN * BRICK_NUM;
|
||||||
|
|
||||||
struct BrickData {
|
|
||||||
pub data: Box<[u8]>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BrickData {
|
|
||||||
|
|
||||||
pub fn new() -> Self {
|
|
||||||
let data = vec![0_u8; DATA_LEN].into_boxed_slice();
|
|
||||||
Self { data }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set(&mut self, brick: usize, x: usize, y: usize, z: usize, value: u8)
|
|
||||||
{
|
|
||||||
let local_idx = x + BRICK_SIZE * (y + BRICK_SIZE * z);
|
|
||||||
let offset = brick * BRICK_LEN;
|
|
||||||
self.data[offset + local_idx] = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
pub struct BrickBuffer {
|
pub struct BrickBuffer {
|
||||||
bricks: BrickData,
|
pub bricks: Box<[u8]>,
|
||||||
|
pub free_brick: usize,
|
||||||
texture: wgpu::Texture,
|
texture: wgpu::Texture,
|
||||||
size: wgpu::Extent3d,
|
|
||||||
pub bind_layout: wgpu::BindGroupLayout,
|
pub bind_layout: wgpu::BindGroupLayout,
|
||||||
pub bind_group: wgpu::BindGroup
|
pub bind_group: wgpu::BindGroup
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BrickBuffer {
|
impl BrickBuffer {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create buffer in memory and gpu
|
||||||
|
*/
|
||||||
pub fn new(device: &wgpu::Device) -> Self {
|
pub fn new(device: &wgpu::Device) -> Self {
|
||||||
|
|
||||||
// Create texture
|
// Create texture
|
||||||
@@ -93,36 +73,24 @@ impl BrickBuffer {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Data
|
// Data
|
||||||
let mut bricks = BrickData::new();
|
let mut bricks = vec![0_u8; DATA_LEN].into_boxed_slice();
|
||||||
|
bricks[0] = 1;
|
||||||
println!("Brick buffer size: {} MB", DATA_LEN as f32 / 1024.0 / 1024.0);
|
println!("Brick buffer size: {} MB", DATA_LEN as f32 / 1024.0 / 1024.0);
|
||||||
|
|
||||||
let mut rng = rand::thread_rng();
|
|
||||||
for x in 0..32 {
|
|
||||||
for y in 0..32 {
|
|
||||||
for z in 0..32 {
|
|
||||||
let value = if rng.gen::<f32>()> 0.99 { 1 } else { 0 };
|
|
||||||
bricks.set(0, x, y, z, value);
|
|
||||||
bricks.set(1, x, 0, z, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bricks.set(1, 20, 5, 16, 1);
|
|
||||||
|
|
||||||
// Done
|
// Done
|
||||||
Self { bricks, texture, size, bind_layout, bind_group }
|
Self { bricks, texture, bind_layout, bind_group, free_brick: 0 }
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Write brick data to gpu, should be called to apply changes
|
Write brick data to gpu, should be called to apply changes
|
||||||
offset: Brick index to copy
|
offset: Brick index to copy
|
||||||
*/
|
*/
|
||||||
pub fn write(&mut self, queue: &wgpu::Queue, offset: usize)
|
pub fn write(&mut self, queue: &wgpu::Queue, brick: usize) {
|
||||||
{
|
|
||||||
// Get first brick
|
// Get first brick
|
||||||
let brick_offset = offset*BRICK_LEN;
|
let brick_offset = brick*BRICK_LEN;
|
||||||
let brick_bytes : [u8;BRICK_LEN] = self.bricks.data[brick_offset..brick_offset+BRICK_LEN].try_into().unwrap();
|
let brick_bytes : [u8;BRICK_LEN] = self.bricks[brick_offset..brick_offset+BRICK_LEN].try_into().unwrap();
|
||||||
let brick_size = wgpu::Extent3d{ width: BRICK_SIZE as u32, height: BRICK_SIZE as u32, depth: BRICK_SIZE as u32 };
|
let brick_size = wgpu::Extent3d{ width: BRICK_SIZE as u32, height: BRICK_SIZE as u32, depth: BRICK_SIZE as u32 };
|
||||||
let brick_origin = wgpu::Origin3d{ x:0, y:0, z: (offset*BRICK_SIZE) as u32 };
|
let brick_origin = wgpu::Origin3d{ x:0, y:0, z: (brick*BRICK_SIZE) as u32 };
|
||||||
|
|
||||||
// Write
|
// Write
|
||||||
queue.write_texture(
|
queue.write_texture(
|
||||||
@@ -132,4 +100,13 @@ impl BrickBuffer {
|
|||||||
brick_size
|
brick_size
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn next_brick(&mut self) -> usize {
|
||||||
|
if self.free_brick >= self.bricks.len() {
|
||||||
|
panic!("No more free bricks! we should consider reusing bricks...");
|
||||||
|
}
|
||||||
|
|
||||||
|
self.free_brick += 1;
|
||||||
|
self.free_brick
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
use wgpu::util::DeviceExt;
|
||||||
|
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Default, Debug, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
|
||||||
|
struct Material {
|
||||||
|
pub albedo: [f32; 4],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Material {
|
||||||
|
pub fn set_albedo(&mut self, r: f32, g: f32, b:f32)
|
||||||
|
{
|
||||||
|
self.albedo[0] = r;
|
||||||
|
self.albedo[1] = g;
|
||||||
|
self.albedo[2] = b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub struct MaterialBuffer {
|
||||||
|
materials: [Material; 256],
|
||||||
|
pub buffer: wgpu::Buffer,
|
||||||
|
pub bind_layout: wgpu::BindGroupLayout,
|
||||||
|
pub bind_group: wgpu::BindGroup
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MaterialBuffer {
|
||||||
|
|
||||||
|
pub fn new(device: &wgpu::Device) -> Self {
|
||||||
|
// Create values
|
||||||
|
let mut materials: [Material; 256] = [Default::default(); 256];
|
||||||
|
materials[0].set_albedo(0.41,0.33,0.20);
|
||||||
|
materials[1].set_albedo(0.49,0.74,0.00);
|
||||||
|
|
||||||
|
// Create buffer
|
||||||
|
let buffer = device.create_buffer_init(
|
||||||
|
&wgpu::util::BufferInitDescriptor {
|
||||||
|
label: Some("Materials buffer"),
|
||||||
|
contents: bytemuck::cast_slice(&materials),
|
||||||
|
usage: wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// Create bind group
|
||||||
|
let bind_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
||||||
|
entries: &[
|
||||||
|
wgpu::BindGroupLayoutEntry {
|
||||||
|
binding: 0,
|
||||||
|
visibility: wgpu::ShaderStage::FRAGMENT,
|
||||||
|
ty: wgpu::BindingType::Buffer {
|
||||||
|
ty: wgpu::BufferBindingType::Uniform,
|
||||||
|
has_dynamic_offset: false,
|
||||||
|
min_binding_size: None,
|
||||||
|
},
|
||||||
|
count: None,
|
||||||
|
}
|
||||||
|
],
|
||||||
|
label: Some("Materials buffer layout"),
|
||||||
|
});
|
||||||
|
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||||
|
layout: &bind_layout,
|
||||||
|
entries: &[
|
||||||
|
wgpu::BindGroupEntry {
|
||||||
|
binding: 0,
|
||||||
|
resource: buffer.as_entire_binding(),
|
||||||
|
}
|
||||||
|
],
|
||||||
|
label: Some("Materials buffer group"),
|
||||||
|
});
|
||||||
|
|
||||||
|
// Done
|
||||||
|
MaterialBuffer { buffer, materials, bind_layout, bind_group }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,9 +1,20 @@
|
|||||||
|
|
||||||
|
// Consts
|
||||||
|
|
||||||
|
pub const WORLD_SIZE: usize = 32;
|
||||||
|
pub const NUM_NODES: usize = (WORLD_SIZE*WORLD_SIZE*WORLD_SIZE) as usize;
|
||||||
|
|
||||||
|
pub const BRICK_SIZE : usize = 32; // 32x32x32 brick size
|
||||||
|
pub const BRICK_NUM : usize = 32768; // max bricks in texture
|
||||||
|
pub const BRICK_LEN : usize = BRICK_SIZE*BRICK_SIZE*BRICK_SIZE;
|
||||||
|
|
||||||
|
// Import names
|
||||||
|
|
||||||
mod node_buffer;
|
mod node_buffer;
|
||||||
pub use node_buffer::NodeBuffer;
|
pub use node_buffer::NodeBuffer;
|
||||||
|
|
||||||
mod brick_buffer;
|
mod brick_buffer;
|
||||||
pub use brick_buffer::BrickBuffer;
|
pub use brick_buffer::{BrickBuffer};
|
||||||
|
|
||||||
mod uniform_buffer;
|
mod uniform_buffer;
|
||||||
pub use uniform_buffer::UniformBuffer;
|
pub use uniform_buffer::UniformBuffer;
|
||||||
@@ -12,3 +23,6 @@ pub use uniform_buffer::UniformValues;
|
|||||||
mod raster_buffer;
|
mod raster_buffer;
|
||||||
pub use raster_buffer::RasterBuffer;
|
pub use raster_buffer::RasterBuffer;
|
||||||
pub use raster_buffer::Vertex;
|
pub use raster_buffer::Vertex;
|
||||||
|
|
||||||
|
mod material_buffer;
|
||||||
|
pub use material_buffer::MaterialBuffer;
|
||||||
@@ -1,31 +1,10 @@
|
|||||||
use byteorder::{ByteOrder, LittleEndian};
|
use byteorder::{ByteOrder, LittleEndian};
|
||||||
use rand::prelude::*;
|
use rand::prelude::*;
|
||||||
|
|
||||||
// 4x4x4 nodes
|
use crate::renderer::buffers::{WORLD_SIZE, NUM_NODES};
|
||||||
const WORLD_SIZE: usize = 32;
|
|
||||||
const NUM_NODES: usize = (WORLD_SIZE*WORLD_SIZE*WORLD_SIZE) as usize;
|
|
||||||
|
|
||||||
struct NodeData {
|
|
||||||
pub data: Box<[u32]>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl NodeData {
|
|
||||||
|
|
||||||
pub fn new() -> Self {
|
|
||||||
let data = vec![0_u32; NUM_NODES].into_boxed_slice();
|
|
||||||
Self { data }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set(&mut self, x: usize, y: usize, z: usize, value: u32)
|
|
||||||
{
|
|
||||||
let idx = x + WORLD_SIZE * (y + WORLD_SIZE * z);
|
|
||||||
self.data[idx] = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
pub struct NodeBuffer {
|
pub struct NodeBuffer {
|
||||||
nodes: NodeData,
|
pub nodes: Box<[u32]>,
|
||||||
texture: wgpu::Texture,
|
texture: wgpu::Texture,
|
||||||
size: wgpu::Extent3d,
|
size: wgpu::Extent3d,
|
||||||
pub bind_layout: wgpu::BindGroupLayout,
|
pub bind_layout: wgpu::BindGroupLayout,
|
||||||
@@ -90,23 +69,8 @@ impl NodeBuffer {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Data
|
// Data
|
||||||
let mut nodes = NodeData::new();
|
let nodes = vec![0_u32; NUM_NODES].into_boxed_slice();
|
||||||
|
println!("Node buffer size: {} MB", nodes.len() as f32 * 4.0 / 1024.0 / 1024.0);
|
||||||
// let mut rng = rand::thread_rng();
|
|
||||||
// for x in 0..WORLD_SIZE {
|
|
||||||
// for y in 0..WORLD_SIZE {
|
|
||||||
// for z in 0..WORLD_SIZE {
|
|
||||||
// let value = if rng.gen::<f32>()> 0.5 { 1 } else { 0 };
|
|
||||||
// nodes.set(x, y, z, value);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
for i in 0..WORLD_SIZE {
|
|
||||||
nodes.set(i, 0, 0, 1);
|
|
||||||
nodes.set(0, i, 0, 1);
|
|
||||||
nodes.set(0, 0, i, 1);
|
|
||||||
}
|
|
||||||
nodes.set(0, 0, 0, 2);
|
|
||||||
|
|
||||||
// Done
|
// Done
|
||||||
Self { nodes, texture, size, bind_layout, bind_group }
|
Self { nodes, texture, size, bind_layout, bind_group }
|
||||||
@@ -115,7 +79,7 @@ impl NodeBuffer {
|
|||||||
pub fn write(&mut self, queue: &wgpu::Queue) {
|
pub fn write(&mut self, queue: &wgpu::Queue) {
|
||||||
// Convert 32 bit values to 8 bit
|
// Convert 32 bit values to 8 bit
|
||||||
let mut bytes = [0_u8; NUM_NODES*4];
|
let mut bytes = [0_u8; NUM_NODES*4];
|
||||||
LittleEndian::write_u32_into(&self.nodes.data, &mut bytes);
|
LittleEndian::write_u32_into(&self.nodes, &mut bytes);
|
||||||
|
|
||||||
// Write
|
// Write
|
||||||
queue.write_texture(
|
queue.write_texture(
|
||||||
|
|||||||
+86
-13
@@ -1,6 +1,8 @@
|
|||||||
use winit::{window::Window, dpi::PhysicalSize};
|
use winit::{window::Window, dpi::PhysicalSize};
|
||||||
|
|
||||||
mod buffers; use buffers::{NodeBuffer, BrickBuffer, UniformBuffer, RasterBuffer, Vertex};
|
mod buffers;
|
||||||
|
use buffers::{NodeBuffer, BrickBuffer, UniformBuffer, RasterBuffer, Vertex, MaterialBuffer};
|
||||||
|
|
||||||
pub mod camera; use camera::Camera;
|
pub mod camera; use camera::Camera;
|
||||||
|
|
||||||
|
|
||||||
@@ -16,9 +18,11 @@ pub struct Renderer {
|
|||||||
uniform_buffer: UniformBuffer,
|
uniform_buffer: UniformBuffer,
|
||||||
node_buffer: NodeBuffer,
|
node_buffer: NodeBuffer,
|
||||||
brick_buffer: BrickBuffer,
|
brick_buffer: BrickBuffer,
|
||||||
|
material_buffer: MaterialBuffer,
|
||||||
// Other
|
// Other
|
||||||
pub camera: Camera,
|
pub camera: Camera,
|
||||||
start: std::time::Instant
|
start: std::time::Instant,
|
||||||
|
changed_bricks: Vec<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Renderer {
|
impl Renderer {
|
||||||
@@ -82,6 +86,9 @@ impl Renderer {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initializes renderer and all buffers
|
||||||
|
*/
|
||||||
pub async fn new(window: &Window) -> Self {
|
pub async fn new(window: &Window) -> Self {
|
||||||
|
|
||||||
// Create surface and pick device
|
// Create surface and pick device
|
||||||
@@ -107,24 +114,29 @@ impl Renderer {
|
|||||||
// Buffers
|
// Buffers
|
||||||
let uniform_buffer = UniformBuffer::new(&device);
|
let uniform_buffer = UniformBuffer::new(&device);
|
||||||
let raster_buffer = RasterBuffer::new(&device);
|
let raster_buffer = RasterBuffer::new(&device);
|
||||||
|
let node_buffer = NodeBuffer::new(&device);
|
||||||
let mut node_buffer = NodeBuffer::new(&device);
|
let brick_buffer = BrickBuffer::new(&device);
|
||||||
node_buffer.write(&queue);
|
let material_buffer = MaterialBuffer::new(&device);
|
||||||
|
|
||||||
let mut brick_buffer = BrickBuffer::new(&device);
|
|
||||||
brick_buffer.write(&queue, 0);
|
|
||||||
brick_buffer.write(&queue, 1);
|
|
||||||
|
|
||||||
// Pipeline
|
// Pipeline
|
||||||
let pipeline = Self::create_pipeline(&device, &swapchain_desc, &[&uniform_buffer.bind_layout, &node_buffer.bind_layout, &brick_buffer.bind_layout]);
|
let bind_layouts = [
|
||||||
|
&uniform_buffer.bind_layout,
|
||||||
let start = std::time::Instant::now();
|
&node_buffer.bind_layout,
|
||||||
|
&brick_buffer.bind_layout,
|
||||||
|
&material_buffer.bind_layout
|
||||||
|
];
|
||||||
|
let pipeline = Self::create_pipeline(&device, &swapchain_desc, &bind_layouts);
|
||||||
|
|
||||||
// Save values in app
|
// Save values in app
|
||||||
println!("Initialized");
|
println!("Initialized");
|
||||||
Self { surface, device, queue, swapchain_desc, swapchain, pipeline, raster_buffer, uniform_buffer, node_buffer, brick_buffer, camera, start }
|
let start = std::time::Instant::now();
|
||||||
|
let changed_bricks: Vec<usize> = Vec::new();
|
||||||
|
Self { surface, device, queue, swapchain_desc, swapchain, pipeline, raster_buffer, uniform_buffer, node_buffer, brick_buffer, material_buffer, camera, start, changed_bricks }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Recreates swapchain with new resolution
|
||||||
|
*/
|
||||||
pub fn resize(&mut self, new_size: Option<PhysicalSize<u32>>) {
|
pub fn resize(&mut self, new_size: Option<PhysicalSize<u32>>) {
|
||||||
if let Some(size) = new_size {
|
if let Some(size) = new_size {
|
||||||
// Minimized or manually resized to 0
|
// Minimized or manually resized to 0
|
||||||
@@ -139,12 +151,24 @@ impl Renderer {
|
|||||||
self.swapchain = self.device.create_swap_chain(&self.surface, &self.swapchain_desc);
|
self.swapchain = self.device.create_swap_chain(&self.surface, &self.swapchain_desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Actually renders the frame
|
||||||
|
*/
|
||||||
pub fn render(&mut self) -> Result<(), wgpu::SwapChainError> {
|
pub fn render(&mut self) -> Result<(), wgpu::SwapChainError> {
|
||||||
|
|
||||||
// Update uniform buffer
|
// Update uniform buffer
|
||||||
self.uniform_buffer.values.update(&self.camera, self.start.elapsed().as_secs_f32());
|
self.uniform_buffer.values.update(&self.camera, self.start.elapsed().as_secs_f32());
|
||||||
self.queue.write_buffer(&self.uniform_buffer.buffer, 0, bytemuck::cast_slice(&[self.uniform_buffer.values]));
|
self.queue.write_buffer(&self.uniform_buffer.buffer, 0, bytemuck::cast_slice(&[self.uniform_buffer.values]));
|
||||||
|
|
||||||
|
// Update changed nodes
|
||||||
|
if self.changed_bricks.len() > 0 {
|
||||||
|
self.node_buffer.write(&self.queue);
|
||||||
|
for node in &self.changed_bricks {
|
||||||
|
self.brick_buffer.write(&self.queue, *node);
|
||||||
|
}
|
||||||
|
self.changed_bricks.clear();
|
||||||
|
}
|
||||||
|
|
||||||
// Get next frame to render to
|
// Get next frame to render to
|
||||||
let frame = self.swapchain.get_current_frame()?.output;
|
let frame = self.swapchain.get_current_frame()?.output;
|
||||||
|
|
||||||
@@ -171,6 +195,7 @@ impl Renderer {
|
|||||||
render_pass.set_bind_group(0, &self.uniform_buffer.bind_group, &[]);
|
render_pass.set_bind_group(0, &self.uniform_buffer.bind_group, &[]);
|
||||||
render_pass.set_bind_group(1, &self.node_buffer.bind_group, &[]);
|
render_pass.set_bind_group(1, &self.node_buffer.bind_group, &[]);
|
||||||
render_pass.set_bind_group(2, &self.brick_buffer.bind_group, &[]);
|
render_pass.set_bind_group(2, &self.brick_buffer.bind_group, &[]);
|
||||||
|
render_pass.set_bind_group(3, &self.material_buffer.bind_group, &[]);
|
||||||
// Vertices and indices
|
// Vertices and indices
|
||||||
render_pass.set_vertex_buffer(0, self.raster_buffer.vertex_buffer.slice(..));
|
render_pass.set_vertex_buffer(0, self.raster_buffer.vertex_buffer.slice(..));
|
||||||
render_pass.set_index_buffer(self.raster_buffer.index_buffer.slice(..), wgpu::IndexFormat::Uint16);
|
render_pass.set_index_buffer(self.raster_buffer.index_buffer.slice(..), wgpu::IndexFormat::Uint16);
|
||||||
@@ -183,4 +208,52 @@ impl Renderer {
|
|||||||
// Return ok
|
// Return ok
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create or update brick at given location
|
||||||
|
*/
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn set_voxel(&mut self, x: usize, y: usize, z:usize, value: u8)
|
||||||
|
{
|
||||||
|
let brick_id = self.brick_get_id(x/32, y/32, z/32 );
|
||||||
|
self.brick_set_voxel(brick_id, x%32, y%32, z%32, value);
|
||||||
|
self.brick_mark_changed(brick_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create or update brick at given location
|
||||||
|
*/
|
||||||
|
pub fn brick_set_voxel(&mut self, brick_id:usize, x: usize, y: usize, z:usize, value: u8)
|
||||||
|
{
|
||||||
|
let voxel_id = x + buffers::BRICK_SIZE * (y + buffers::BRICK_SIZE * z);
|
||||||
|
let brick_offset = brick_id * buffers::BRICK_LEN;
|
||||||
|
self.brick_buffer.bricks[brick_offset + voxel_id] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Gets brick id
|
||||||
|
*/
|
||||||
|
pub fn brick_get_id(&mut self, x: usize, y: usize, z:usize) -> usize {
|
||||||
|
// Get node
|
||||||
|
let node_idx = x + buffers::WORLD_SIZE * (y + buffers::WORLD_SIZE * z);
|
||||||
|
let mut node_value = self.node_buffer.nodes[node_idx];
|
||||||
|
|
||||||
|
// Use new brick if neccesary
|
||||||
|
if node_value == 0 {
|
||||||
|
node_value = self.brick_buffer.next_brick() as u32;
|
||||||
|
self.node_buffer.nodes[node_idx] = node_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get brick id from node value
|
||||||
|
(node_value - 1) as usize
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Marks brick as changed
|
||||||
|
*/
|
||||||
|
pub fn brick_mark_changed(&mut self, brick_id:usize) {
|
||||||
|
if !self.changed_bricks.contains(&brick_id) {
|
||||||
|
self.changed_bricks.push(brick_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Binary file not shown.
@@ -1,28 +1,9 @@
|
|||||||
|
|
||||||
/*
|
|
||||||
point: Hit point
|
|
||||||
view: View vector (camera ray)
|
|
||||||
normal: Normal vector
|
|
||||||
*/
|
|
||||||
vec3 solve(vec3 hitPoint, vec3 view, vec3 normal)
|
|
||||||
{
|
|
||||||
// Lighting
|
|
||||||
vec3 light_color = vec3(1.0, 1.0, 1.0);
|
|
||||||
vec3 light_dir = normalize(hitPoint-vec3(0.0, 1.5, 4.0));
|
|
||||||
|
|
||||||
vec3 ambient = light_color * 0.1;
|
|
||||||
vec3 diffuse = light_color * max(1.0-dot(normal, light_dir), 0.0);
|
|
||||||
vec3 specular = light_color * pow(max(dot(view, reflect(-light_dir, normal)), 0.0), 32);
|
|
||||||
|
|
||||||
// Combine colors
|
|
||||||
vec3 object_color = vec3(0.0, 0.1, 0.5);
|
|
||||||
return (ambient + diffuse + specular) * object_color;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* origin: Point hit on the node
|
* origin: Point hit on the node
|
||||||
* dir: Camera view direction (ray direction)
|
* dir: Camera view direction (ray direction)
|
||||||
* addr: Number given by node, afaik brick offset in brick array
|
* incAxis: Last axis that was used to increment position
|
||||||
|
* addr: Number given by node, brick offset in brick array
|
||||||
*/
|
*/
|
||||||
vec4 castBricks(vec3 origin, vec3 start, vec3 dir, vec3 incAxis, uint addr)
|
vec4 castBricks(vec3 origin, vec3 start, vec3 dir, vec3 incAxis, uint addr)
|
||||||
{
|
{
|
||||||
@@ -38,14 +19,12 @@ vec4 castBricks(vec3 origin, vec3 start, vec3 dir, vec3 incAxis, uint addr)
|
|||||||
vec3 rayInv = 1.0/dir;
|
vec3 rayInv = 1.0/dir;
|
||||||
vec3 raySign = sign(dir);
|
vec3 raySign = sign(dir);
|
||||||
vec3 dist = (pos-origin+0.5 + raySign*0.5) * rayInv;
|
vec3 dist = (pos-origin+0.5 + raySign*0.5) * rayInv;
|
||||||
|
|
||||||
ivec3 offset = ivec3(0, 0, (addr-1)*32);
|
ivec3 offset = ivec3(0, 0, (addr-1)*32);
|
||||||
|
|
||||||
vec3 tmp = abs(raySign);
|
|
||||||
for(int i=0;i<110;i++)
|
for(int i=0;i<110;i++)
|
||||||
{
|
{
|
||||||
// Get brick
|
// Get brick
|
||||||
uint brick = texelFetch(bricksTexture, offset+ivec3(pos), 0).r;
|
uint brick = texelFetch(_BricksTexture, offset+ivec3(pos), 0).r;
|
||||||
if(brick != 0)
|
if(brick != 0)
|
||||||
{
|
{
|
||||||
// Hit point
|
// Hit point
|
||||||
@@ -55,7 +34,7 @@ vec4 castBricks(vec3 origin, vec3 start, vec3 dir, vec3 incAxis, uint addr)
|
|||||||
|
|
||||||
// Normal vector (negate previous increment axis and mult by sign)
|
// Normal vector (negate previous increment axis and mult by sign)
|
||||||
vec3 normal = -incAxis * raySign;
|
vec3 normal = -incAxis * raySign;
|
||||||
return vec4(solve(hitPoint, dir, normal), 1.0);
|
return vec4(solve(hitPoint, dir, normal, brick-1), 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get new closest axis to increment
|
// Get new closest axis to increment
|
||||||
@@ -68,7 +47,7 @@ vec4 castBricks(vec3 origin, vec3 start, vec3 dir, vec3 incAxis, uint addr)
|
|||||||
if(pos.x > 31 || pos.y > 31 || pos.z > 31) { break; }
|
if(pos.x > 31 || pos.y > 31 || pos.z > 31) { break; }
|
||||||
}
|
}
|
||||||
|
|
||||||
return vec4(0.5,0.5,0.5, 0.0);
|
return vec4(1.0,0.0,0.5,0.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -93,16 +72,13 @@ vec3 castNodes(vec3 origin, vec3 dir)
|
|||||||
for(int i=0;i<110;i++)
|
for(int i=0;i<110;i++)
|
||||||
{
|
{
|
||||||
// Get node
|
// Get node
|
||||||
uint node = texelFetch(nodesTexture, ivec3(pos), 0).r;
|
uint node = texelFetch(_NodesTexture, ivec3(pos), 0).r;
|
||||||
if(node != 0)
|
if(node != 0)
|
||||||
{
|
{
|
||||||
// Hit point
|
// Hit point
|
||||||
vec3 mini = (pos-origin+0.5 - raySign*0.5) * rayInv;
|
vec3 mini = (pos-origin+0.5 - raySign*0.5) * rayInv;
|
||||||
float len = max(0.0, max(mini.x, max(mini.y, mini.z)));
|
float len = max(0.0, max(mini.x, max(mini.y, mini.z)));
|
||||||
vec3 hitPoint = origin + dir * len;
|
vec3 hitPoint = origin + dir * len;
|
||||||
// Normal vector (negate previous increment axis and mult by sign)
|
|
||||||
//vec3 normal = -incAxis * raySign;
|
|
||||||
//return solve(hitPoint, dir, normal);
|
|
||||||
|
|
||||||
// Cast brick
|
// Cast brick
|
||||||
vec4 result = castBricks(pos, hitPoint, dir, incAxis, node);
|
vec4 result = castBricks(pos, hitPoint, dir, incAxis, node);
|
||||||
|
|||||||
@@ -1,91 +0,0 @@
|
|||||||
|
|
||||||
// Returns nearest distance to and object id from given point
|
|
||||||
vec2 map(in vec3 pos)
|
|
||||||
{
|
|
||||||
vec2 d1 = vec2(sdPlane(pos), 1);
|
|
||||||
vec2 d2 = vec2(sdSphere(pos - vec3(0.0, 2.0, 5.0)), 2);
|
|
||||||
vec2 d3 = vec2(sdSphere(pos - vec3(0.0, 3.0, 3.0)), 3);
|
|
||||||
return sdUnion(sdUnion(d1, d2), d3);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns distance to and object id that has been intersected by ray
|
|
||||||
vec2 intersect(in vec3 ro, in vec3 rd)
|
|
||||||
{
|
|
||||||
float depth = NEAR;
|
|
||||||
for(int i=0;i<MAX_STEPS;i++)
|
|
||||||
{
|
|
||||||
// Travel through map
|
|
||||||
vec2 dist = map(ro + rd * depth);
|
|
||||||
if(dist.x < EPSILON)
|
|
||||||
{
|
|
||||||
// Hit something
|
|
||||||
return vec2(depth, dist.y);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Move further
|
|
||||||
depth += dist.x;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Nothing found
|
|
||||||
return vec2(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
vec3 estimateNormal(vec3 p)
|
|
||||||
{
|
|
||||||
return normalize(vec3(
|
|
||||||
map(vec3(p.x + EPSILON, p.y, p.z)).x - map(vec3(p.x - EPSILON, p.y, p.z)).x,
|
|
||||||
map(vec3(p.x, p.y + EPSILON, p.z)).x - map(vec3(p.x, p.y - EPSILON, p.z)).x,
|
|
||||||
map(vec3(p.x, p.y, p.z + EPSILON)).x - map(vec3(p.x, p.y, p.z - EPSILON)).x
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
vec3 raymarch(in vec3 ro, in vec3 rd)
|
|
||||||
{
|
|
||||||
// Light dir
|
|
||||||
vec3 ld = normalize(vec3(-0.5, 2.0, -0.2));
|
|
||||||
|
|
||||||
vec2 result = intersect(ro, rd);
|
|
||||||
if(result.y > 0.0)
|
|
||||||
{
|
|
||||||
// Calculate intersection point, normal vector and reflection vector
|
|
||||||
vec3 pos = ro + rd * result.x;
|
|
||||||
vec3 nor = estimateNormal(pos);
|
|
||||||
vec3 ref = reflect(rd, nor);
|
|
||||||
|
|
||||||
// Light
|
|
||||||
vec3 light = vec3(1);
|
|
||||||
|
|
||||||
float dif = clamp( dot( nor, ld ), 0.0, 1.0 );
|
|
||||||
light += 2.20*dif*vec3(1.30,1.00,0.70);
|
|
||||||
|
|
||||||
vec3 hal = normalize( ld-rd );
|
|
||||||
float spe = pow( clamp( dot( nor, hal ), 0.0, 1.0 ),16.0);
|
|
||||||
spe *= dif;
|
|
||||||
spe *= 0.04+0.96*pow(clamp(1.0-dot(hal,ld),0.0,1.0),5.0);
|
|
||||||
light += 5.00*spe*vec3(1.30,1.00,0.70);
|
|
||||||
|
|
||||||
//float diffuse = max(dot(norm, -ld), 0);
|
|
||||||
//color *= diffuse;
|
|
||||||
|
|
||||||
//vec3 ldr = normalize(reflect(-ld, norm));
|
|
||||||
//float specular = max(dot(ldr, rd), 0.0);
|
|
||||||
//specular = pow(specular, 3);
|
|
||||||
//color += vec3(0.2) * specular;
|
|
||||||
|
|
||||||
//float scatter = pow(1.0-dot(rd, -norm), 2);
|
|
||||||
|
|
||||||
// Calculate color
|
|
||||||
vec3 color = vec3(0);
|
|
||||||
if(result.y == 1) color = vec3(0.0, 0.1, 0.01);
|
|
||||||
else if(result.y == 2) color = vec3(0.5, 0.7, 0.05);
|
|
||||||
else if(result.y == 3) color = vec3(0.0, 0.2, 0.7);
|
|
||||||
|
|
||||||
// Return
|
|
||||||
color *= light;
|
|
||||||
return color;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return vec3(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+19
-16
@@ -1,38 +1,41 @@
|
|||||||
// shader.frag
|
// shader.frag
|
||||||
#version 450
|
#version 450
|
||||||
|
|
||||||
|
struct Material {
|
||||||
|
vec4 albedo;
|
||||||
|
};
|
||||||
|
|
||||||
// Variables
|
// Variables
|
||||||
layout(location=0) in vec2 vert_uv;
|
layout(location=0) in vec2 vert_uv;
|
||||||
layout(location=0) out vec4 out_color;
|
layout(location=0) out vec4 out_color;
|
||||||
|
|
||||||
layout(set=0, binding=0) uniform Uniforms
|
layout(set=0,binding=0) uniform Uniforms {
|
||||||
{
|
mat4 _ViewMatrix;
|
||||||
mat4 _viewMatrix;
|
mat4 _ProjMatrixInv;
|
||||||
mat4 _projMatrixInv;
|
|
||||||
vec3 _CamPos;
|
vec3 _CamPos;
|
||||||
float _Time;
|
float _Time;
|
||||||
};
|
};
|
||||||
|
layout(set=1,binding=0) uniform usampler3D _NodesTexture;
|
||||||
//layout(set = 1, binding = 0) uniform texture3D node_tex;
|
layout(set=2,binding=0) uniform usampler3D _BricksTexture;
|
||||||
//layout(set = 1, binding = 1) uniform usampler3D node_sampl;
|
layout(set=3, binding=0) uniform Materials {
|
||||||
layout(set=1,binding=0) uniform usampler3D nodesTexture;
|
Material _Materials[256];
|
||||||
layout(set=2,binding=0) uniform usampler3D bricksTexture;
|
};
|
||||||
|
|
||||||
// Defines
|
// Defines
|
||||||
#define PI 3.141592
|
// #define PI 3.141592
|
||||||
#define EPSILON 0.01
|
// #define EPSILON 0.01
|
||||||
#define NEAR 0.01
|
// #define NEAR 0.01
|
||||||
#define MAX_STEPS 200
|
|
||||||
|
|
||||||
// Include
|
// Include
|
||||||
#include "shapes.cginc"
|
#include "shading.cginc"
|
||||||
#include "raycasting.cginc"
|
#include "raycasting.cginc"
|
||||||
|
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
// Calculate ray direction
|
// Calculate ray direction
|
||||||
vec3 view_dir = (_projMatrixInv * vec4(vert_uv, 0, 1)).xyz;
|
vec3 view_dir = (_ProjMatrixInv * vec4(vert_uv, 0, 1)).xyz;
|
||||||
vec3 ray_dir = normalize(_viewMatrix * vec4(view_dir,0)).xyz;
|
vec3 ray_dir = normalize(_ViewMatrix * vec4(view_dir,0)).xyz;
|
||||||
|
|
||||||
// Raycast
|
// Raycast
|
||||||
out_color = vec4(castNodes(_CamPos, ray_dir), 1.0);
|
out_color = vec4(castNodes(_CamPos, ray_dir), 1.0);
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
/*
|
||||||
|
point: Hit point
|
||||||
|
view: View vector (camera ray)
|
||||||
|
normal: Normal vector
|
||||||
|
*/
|
||||||
|
vec3 solve(vec3 hitPoint, vec3 view, vec3 normal, uint brick)
|
||||||
|
{
|
||||||
|
// Lighting
|
||||||
|
vec3 light_color = vec3(1.0, 1.0, 1.0);
|
||||||
|
vec3 light_dir = normalize(hitPoint-vec3(0.0, 1.5, 4.0));
|
||||||
|
|
||||||
|
vec3 ambient = light_color * 0.1;
|
||||||
|
vec3 diffuse = light_color * max(1.0-dot(normal, light_dir), 0.0);
|
||||||
|
vec3 specular = light_color * pow(max(dot(view, reflect(-light_dir, normal)), 0.0), 32);
|
||||||
|
|
||||||
|
// Combine colors
|
||||||
|
vec3 object_color = _Materials[brick].albedo.rgb;//vec3(0.0, 0.1, 0.5);
|
||||||
|
return (ambient + diffuse + specular) * object_color;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user