Terrain !

This commit is contained in:
2026-09-03 23:23:43 +02:00
parent 2fbce4ab81
commit b826de15a6
6 changed files with 902 additions and 177 deletions
+197 -62
View File
@@ -4,6 +4,7 @@ use core::sync;
use std::cell::RefCell;
use std::collections::HashMap;
use std::fs::File;
use std::hash::Hash;
use std::rc::Rc;
use std::sync::Arc;
use std::sync::atomic::AtomicBool;
@@ -13,6 +14,8 @@ use bytemuck::Pod;
use bytemuck::Zeroable;
use crevice::std140::AsStd140;
use crevice::std430::AsStd430;
use egui::Color32;
use egui::Label;
use egui::emath::fast_midpoint;
use egui::mutex::Mutex;
use egui_plot::BarChart;
@@ -21,6 +24,9 @@ use glam::Vec3;
use glam::Vec4;
use itertools::Itertools;
use rand::random;
use rayon::iter::IndexedParallelIterator;
use rayon::iter::IntoParallelRefIterator;
use rayon::iter::ParallelIterator;
use wgpu::BindGroup;
use wgpu::BindGroupEntry;
use wgpu::BindGroupLayoutDescriptor;
@@ -54,6 +60,7 @@ use wgpu::util::DownloadBuffer;
use wgpu::util::StagingBelt;
use winit::application::ApplicationHandler;
use winit::event::DeviceEvent;
use winit::event::MouseScrollDelta;
use winit::event::WindowEvent;
use winit::event_loop;
use winit::event_loop::ActiveEventLoop;
@@ -66,9 +73,14 @@ use winit::window::WindowId;
use crate::camera::Camera;
use crate::egui_renderer::EguiRenderer;
use crate::producers::BallGenerator;
use crate::producers::ChunkedProducer;
use crate::producers::Producer;
use crate::producers::SineGenerator;
use crate::producers::TerrainGenerator;
use crate::voxel::cache::CacheNodeRequest;
use crate::voxel::cache::CacheResponse;
use crate::voxel::cache::ColorBytes;
use crate::voxel::cache::DestinationElement;
use crate::voxel::cache::LocationPoolElement;
use crate::voxel::cache::RequestBuffer;
@@ -103,6 +115,10 @@ struct State
pipeline: RenderPipeline,
voxel_cache: Arc<Mutex<VoxelCache<4>>>,
terrain_generator: Arc<TerrainGenerator<4>>,
chunk_pos_map: Arc<HashMap<u32, (usize, usize, usize)>>,
instance_buffer: Buffer,
instance_count: usize,
usage_vec: Arc<Mutex<Vec<usize>>>,
insertion_debounce: bool,
@@ -123,6 +139,16 @@ struct Immediates
frame_timestamp: u32,
}
#[derive(Debug, Clone, Copy, Zeroable, Pod)]
#[repr(C)]
struct InstanceAttribute
{
x: f32,
y: f32,
z: f32,
id: u32,
}
impl State
{
async fn new(display: OwnedDisplayHandle, window: Arc<Window>) -> State
@@ -141,7 +167,7 @@ impl State
.unwrap();
let (device, queue) = adapter
.request_device(&wgpu::DeviceDescriptor {
required_features: Features::IMMEDIATES,
required_features: Features::IMMEDIATES | Features::SHADER_EARLY_DEPTH_TEST,
required_limits: wgpu::Limits {
max_immediate_size: 112,
max_storage_buffers_per_shader_stage: 16,
@@ -160,9 +186,34 @@ impl State
let egui_renderer = EguiRenderer::new(&device, surface_format, &window);
let mut voxel_cache = VoxelCache::<4>::new(16000, device.clone(), queue.clone());
let id = voxel_cache.structure_table.allocate_structure(true);
println!("id: {id}");
let mut voxel_cache = VoxelCache::<4>::new(100_000, device.clone(), queue.clone());
let terrain_generator = TerrainGenerator::<4>::new(5, "vxls_height.tif", 0.2, "img.jpg");
let mut chunk_pos_map = HashMap::new();
let chunk_instances = (0..terrain_generator.chunk_width)
.cartesian_product(0..terrain_generator.chunk_height)
.cartesian_product(0..terrain_generator.chunk_alt)
.map(|((x, z), y)| {
let chunk_id = voxel_cache.structure_table.allocate_structure(true);
//dbg!(chunk_id);
chunk_pos_map.insert(chunk_id, (x, y, z));
InstanceAttribute {
x: x as f32,
y: y as f32,
z: z as f32,
id: chunk_id,
}
})
.collect::<Vec<_>>();
let instance_count = chunk_instances.len();
let instance_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some("Instance buffer"),
contents: bytemuck::cast_slice(chunk_instances.as_slice()),
usage: BufferUsages::COPY_DST | BufferUsages::VERTEX,
});
let shader_module = device.create_shader_module(wgpu::ShaderModuleDescriptor {
label: Some("Main shader module"),
@@ -187,13 +238,28 @@ impl State
module: &shader_module,
entry_point: Some("chunk"),
compilation_options: Default::default(),
buffers: &[],
buffers: &[Some(wgpu::VertexBufferLayout {
array_stride: (size_of::<f32>() * 3 + size_of::<u32>()) as u64,
step_mode: wgpu::VertexStepMode::Instance,
attributes: &[
wgpu::VertexAttribute {
format: wgpu::VertexFormat::Float32x3,
offset: 0,
shader_location: 0,
},
wgpu::VertexAttribute {
format: wgpu::VertexFormat::Uint32,
offset: (size_of::<f32>() * 3) as u64,
shader_location: 1,
},
],
})],
},
primitive: wgpu::PrimitiveState {
topology: wgpu::PrimitiveTopology::TriangleList,
strip_index_format: None,
front_face: wgpu::FrontFace::Ccw,
cull_mode: None,
cull_mode: Some(wgpu::Face::Front),
unclipped_depth: false,
polygon_mode: wgpu::PolygonMode::Fill,
conservative: false,
@@ -201,7 +267,7 @@ impl State
depth_stencil: Some(wgpu::DepthStencilState {
format: wgpu::TextureFormat::Depth24PlusStencil8,
depth_write_enabled: Some(true),
depth_compare: Some(wgpu::CompareFunction::LessEqual),
depth_compare: Some(wgpu::CompareFunction::Less),
stencil: wgpu::StencilState::default(),
bias: wgpu::DepthBiasState::default(),
}),
@@ -235,6 +301,10 @@ impl State
voxel_cache: Arc::new(Mutex::new(voxel_cache)),
insertion_debounce: false,
camera: Default::default(),
instance_buffer,
instance_count,
terrain_generator: Arc::new(terrain_generator),
chunk_pos_map: chunk_pos_map.into(),
};
// Configure surface for the first time
@@ -323,9 +393,7 @@ impl State
fn render(&mut self)
{
self.camera.update();
// Write random shit in request buffer
let mut belt = StagingBelt::new(self.device.clone(), size_of::<u32>() as u64);
self.voxel_cache.lock().next_frame();
// Create texture view.
// NOTE: We must handle Timeout because the surface may be unavailable
@@ -395,6 +463,7 @@ impl State
});
renderpass.set_pipeline(&self.pipeline);
renderpass.set_vertex_buffer(0, self.instance_buffer.slice(..));
renderpass.set_bind_group(0, Some(&self.voxel_cache.lock().bind_group()), &[]);
let imm = [Immediates {
view_proj: self.camera.view_proj(),
@@ -402,7 +471,7 @@ impl State
frame_timestamp: self.voxel_cache.lock().current_timestamp(),
}];
renderpass.set_immediates(0, unsafe { as_raw_bytes(&imm) });
renderpass.draw(0..36, 0..1);
renderpass.draw(0..36, 0..(self.instance_count as u32));
// End the renderpass.
drop(renderpass);
@@ -410,14 +479,20 @@ impl State
let requests = self.device.create_buffer(&wgpu::BufferDescriptor {
label: Some("dummy_dumb_dinky_aaaahhh_buffer"),
size: 16 * 256,
size: 16 * 1024,
usage: BufferUsages::STORAGE | BufferUsages::COPY_SRC,
mapped_at_creation: false,
});
self.voxel_cache
.lock()
.cache_post_render(&mut encoder, requests.clone());
if !self
.camera
.pressed_keyset
.contains(&winit::keyboard::KeyCode::KeyF)
{
self.voxel_cache
.lock()
.cache_post_render(&mut encoder, requests.clone());
}
// If you wanted to call any drawing commands, they would go here.
{
@@ -425,6 +500,17 @@ impl State
egui::Window::new("Window ! ").resizable(true).show(
self.egui_renderer.context(),
|ui| {
if self
.camera
.pressed_keyset
.contains(&winit::keyboard::KeyCode::KeyF)
{
ui.label(
egui::RichText::new("Cache paused")
.color(Color32::RED)
.size(28.),
);
}
egui_plot::Plot::new("Plot").show(ui, |plot_ui| {
plot_ui.bar_chart(BarChart::new(
"histo",
@@ -488,17 +574,24 @@ impl State
self.insertion_debounce = false;
}
if (self
// if (self
// .camera
// .pressed_keyset
// .contains(&winit::keyboard::KeyCode::KeyF))
// && !self.insertion_debounce
// {
if !self
.camera
.pressed_keyset
.contains(&winit::keyboard::KeyCode::KeyF))
&& !self.insertion_debounce
.contains(&winit::keyboard::KeyCode::KeyF)
{
self.insertion_debounce = true;
let request_count = self.voxel_cache.lock().total_request_count();
let cloned_cache = self.voxel_cache.clone();
let cloned_device = self.device.clone();
let cloned_queue = self.queue.clone();
let cloned_generator = self.terrain_generator.clone();
let cloned_map = self.chunk_pos_map.clone();
let (tx, rx) = sync_channel(1);
DownloadBuffer::read_buffer(
&self.device.clone(),
@@ -513,58 +606,88 @@ impl State
let cache_node_requests: Vec<CacheNodeRequest> =
bytemuck::pod_collect_to_vec(&buffer.unwrap());
let mut sine_gen = SineGenerator::<4>::new(4);
let generator = cloned_generator;
let gen_test = SineGenerator::<4>::new(5);
let mut structure_nodes = vec![];
let mut color_nodes = vec![];
let mut color_nodes: Vec<[ColorBytes; 64]> = vec![];
let mut location_nodes = vec![];
let mut destinations = vec![];
for request in cache_node_requests.iter().take(request_count as usize)
{
let location;
let node;
if request.child_index == u32::MAX
{
// Produce root node
node = sine_gen.produce_node(0, 0, 0, 0);
location = LocationPoolElement {
structure_id: 0,
structure_locator: NTreeNodeLocator::<4>::root().as_usize() as u32,
};
}
else
{
// Figure out depth of request
let locator = NTreeNodeLocator::<4>::from_usize(
request.structure_locator as usize,
);
let depth = locator.depth();
//let (x, y, z) = locator.node_location();
let child_x = request.child_index / (4 * 4);
let child_y = (request.child_index % (4 * 4)) / 4;
let child_z = request.child_index % 4;
cache_node_requests
.par_iter()
.take(request_count as usize)
.map(|request| {
// Unpack structure id
let (chunk_x, chunk_y, chunk_z) =
*cloned_map.get(&request.structure_id).unwrap();
let child_locator =
locator.child(child_x as usize, child_y as usize, child_z as usize);
let location;
let node;
if request.child_index == u32::MAX
{
// Produce root node
node =
generator.produce_node(0, 0, 0, 0, (chunk_x, chunk_y, chunk_z));
location = LocationPoolElement {
structure_id: request.structure_id,
structure_locator: NTreeNodeLocator::<4>::root().as_usize()
as u32,
};
}
else
{
// Figure out depth of request
let locator = NTreeNodeLocator::<4>::from_usize(
request.structure_locator as usize,
);
let depth = locator.depth();
//let (x, y, z) = locator.node_location();
let (nx, ny, nz) = child_locator.node_location();
let child_z = request.child_index / (4 * 4);
let child_y = (request.child_index % (4 * 4)) / 4;
let child_x = request.child_index % 4;
node = sine_gen.produce_node(depth + 1, nx, ny, nz);
let child_locator = locator.child(
child_x as usize,
child_y as usize,
child_z as usize,
);
location = LocationPoolElement {
structure_id: 0,
structure_locator: child_locator.as_usize() as u32,
};
}
let (nx, ny, nz) = child_locator.node_location();
structure_nodes.push(node.structure);
color_nodes.push(node.colors);
location_nodes.push(location);
destinations.push(DestinationElement {
node: request.node_index,
child: request.child_index,
node = generator.produce_node(
depth + 1,
nx,
ny,
nz,
(chunk_x, chunk_y, chunk_z),
);
location = LocationPoolElement {
structure_id: request.structure_id,
structure_locator: child_locator.as_usize() as u32,
};
}
(
node.structure,
node.colors,
location,
DestinationElement {
node: request.node_index,
child: request.child_index,
},
)
})
.collect::<Vec<_>>()
.into_iter()
.for_each(|data| {
structure_nodes.push(data.0);
color_nodes.push(std::array::from_fn(|i| data.1[i].into()));
location_nodes.push(data.2);
destinations.push(data.3);
});
}
if structure_nodes.len() != 0
{
@@ -607,7 +730,7 @@ impl State
}
},
);
println!("Total request count: {}", request_count);
//println!("Total request count: {}", request_count);
loop
{
if rx.try_recv().is_ok()
@@ -617,10 +740,17 @@ impl State
let _ = self.device.poll(wgpu::wgt::PollType::Poll);
}
self.voxel_cache.lock().next_frame();
drop(rx);
}
}
pub fn mouse_wheel(&mut self, delta: MouseScrollDelta)
{
if let MouseScrollDelta::LineDelta(_, y) = delta
{
self.camera.speed += y * (self.camera.speed * 0.05);
}
}
}
#[derive(Default)]
@@ -679,6 +809,11 @@ impl ApplicationHandler for App
// here as this event is always followed up by redraw request.
state.resize(size);
}
WindowEvent::MouseWheel { delta, .. } =>
{
state.mouse_wheel(delta);
}
_ => (),
}
}