Rust gpu
This commit is contained in:
@ -21,5 +21,8 @@ tiff = "0.10.3"
|
||||
wgpu = {version = "27.0.1", features = ["spirv"]}
|
||||
winit = "0.30.12"
|
||||
|
||||
[build-dependencies]
|
||||
spirv-builder = {git = "https://github.com/rust-gpu/rust-gpu"}
|
||||
|
||||
[profile.release]
|
||||
opt-level = 3
|
||||
|
||||
11
build.rs
Normal file
11
build.rs
Normal file
@ -0,0 +1,11 @@
|
||||
use spirv_builder::Capability;
|
||||
use spirv_builder::MetadataPrintout;
|
||||
use spirv_builder::SpirvBuilder;
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>>
|
||||
{
|
||||
SpirvBuilder::new("shaders", "spirv-unknown-spv1.6")
|
||||
.print_metadata(MetadataPrintout::Full)
|
||||
.build()?;
|
||||
Ok(())
|
||||
}
|
||||
7
rust-toolchain.toml
Normal file
7
rust-toolchain.toml
Normal file
@ -0,0 +1,7 @@
|
||||
[toolchain]
|
||||
channel = "nightly-2025-06-30"
|
||||
components = ["rust-src", "rustc-dev", "llvm-tools"]
|
||||
# commit_hash = 35f6036521777bdc0dcea1f980be4c192962a168
|
||||
|
||||
# Whenever changing the nightly channel, update the commit hash above, and
|
||||
# change `REQUIRED_RUST_TOOLCHAIN` in `crates/rustc_codegen_spirv/build.rs` too.
|
||||
2
shaders/.gitignore
vendored
Normal file
2
shaders/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
/target
|
||||
Cargo.lock
|
||||
10
shaders/Cargo.toml
Normal file
10
shaders/Cargo.toml
Normal file
@ -0,0 +1,10 @@
|
||||
[lib]
|
||||
crate-type = ["dylib"]
|
||||
|
||||
[package]
|
||||
name = "shaders"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
spirv-std = {git = "https://github.com/rust-gpu/rust-gpu"}
|
||||
23
shaders/src/lib.rs
Normal file
23
shaders/src/lib.rs
Normal file
@ -0,0 +1,23 @@
|
||||
#![cfg_attr(target_arch = "spirv", no_std)]
|
||||
use spirv_std::glam::Vec4;
|
||||
use spirv_std::glam::vec2;
|
||||
use spirv_std::glam::vec4;
|
||||
use spirv_std::spirv;
|
||||
|
||||
#[spirv(fragment)]
|
||||
pub fn main_fs(output: &mut Vec4)
|
||||
{
|
||||
*output = vec4(0.2, 1.0, 0.2, 1.0);
|
||||
}
|
||||
|
||||
#[spirv(vertex)]
|
||||
pub fn main_vs(#[spirv(vertex_id)] in_id: &mut u32, #[spirv(position)] out_pos: &mut Vec4)
|
||||
{
|
||||
let positions = [vec2(-1., 3.), vec2(-1., 1.), vec2(3., 1.)];
|
||||
*out_pos = Vec4::new(
|
||||
positions[*in_id as usize].x,
|
||||
positions[*in_id as usize].y,
|
||||
0.,
|
||||
1.,
|
||||
);
|
||||
}
|
||||
@ -1,166 +0,0 @@
|
||||
use std::fs::File;
|
||||
use std::io::BufReader;
|
||||
use std::path::Path;
|
||||
|
||||
use itertools::Itertools;
|
||||
use tiff::decoder::Decoder;
|
||||
use wgpu::Device;
|
||||
use wgpu::RenderPass;
|
||||
use wgpu::TextureFormat;
|
||||
|
||||
use crate::state::Camera;
|
||||
use crate::voxel_renderer::VoxelRenderer;
|
||||
|
||||
pub struct HeightMapRenderer
|
||||
{
|
||||
width: u32,
|
||||
height: u32,
|
||||
|
||||
heightmap: Vec<f32>,
|
||||
height_min: f32,
|
||||
height_max: f32,
|
||||
|
||||
alive_chunks: Vec<cgmath::Vector3<i32>>,
|
||||
eye_pos: cgmath::Vector3<f32>,
|
||||
|
||||
voxel_renderer: VoxelRenderer,
|
||||
}
|
||||
|
||||
impl HeightMapRenderer
|
||||
{
|
||||
pub fn from_image(
|
||||
path: impl AsRef<Path>,
|
||||
device: &Device,
|
||||
surface_format: TextureFormat,
|
||||
) -> Self
|
||||
{
|
||||
let file = File::open(path).unwrap();
|
||||
let mut decoder = Decoder::new(BufReader::new(file)).unwrap();
|
||||
let (width, height) = decoder.dimensions().unwrap();
|
||||
|
||||
let decoded = decoder.read_image().unwrap();
|
||||
let pixels = match decoded
|
||||
{
|
||||
tiff::decoder::DecodingResult::F32(decoded_pixels) => decoded_pixels,
|
||||
_ =>
|
||||
{
|
||||
panic!("Unsuported image format.");
|
||||
}
|
||||
};
|
||||
|
||||
Self {
|
||||
width,
|
||||
height,
|
||||
|
||||
height_min: pixels.iter().copied().reduce(f32::min).unwrap_or(0.),
|
||||
height_max: pixels.iter().copied().reduce(f32::max).unwrap_or(0.),
|
||||
|
||||
heightmap: pixels,
|
||||
alive_chunks: vec![],
|
||||
eye_pos: cgmath::Vector3::new(0., 0., 0.),
|
||||
|
||||
voxel_renderer: VoxelRenderer::new(device, surface_format),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_eye_pos(&mut self, eye_pos: cgmath::Vector3<f32>, device: &Device)
|
||||
{
|
||||
self.eye_pos = eye_pos;
|
||||
// self.voxel_renderer.set_chunks(
|
||||
// device,
|
||||
// &[
|
||||
// cgmath::Vector3::new(-1, 0, -1),
|
||||
// cgmath::Vector3::new(-1, 0, 1),
|
||||
// cgmath::Vector3::new(1, 0, -1),
|
||||
// cgmath::Vector3::new(1, 0, 1),
|
||||
// ],
|
||||
// );
|
||||
// return;
|
||||
// Compute alive chunks
|
||||
|
||||
let eye_chunk = cgmath::Vector3::new(
|
||||
eye_pos.x.floor() as i32,
|
||||
eye_pos.y.floor() as i32,
|
||||
eye_pos.z.floor() as i32,
|
||||
);
|
||||
let mut alive_chunks = vec![];
|
||||
for ((x, y), z) in (-10..=10)
|
||||
.cartesian_product(-10..=10)
|
||||
.cartesian_product(-10..=10)
|
||||
{
|
||||
let chunk = eye_chunk + cgmath::Vector3::new(x, y, z);
|
||||
if chunk.x >= 0 && chunk.z >= 0
|
||||
{
|
||||
if chunk.y == -1
|
||||
{
|
||||
alive_chunks.push(chunk);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.alive_chunks = alive_chunks;
|
||||
if !self.alive_chunks.is_empty()
|
||||
{
|
||||
self.voxel_renderer.set_chunks(device, &self.alive_chunks);
|
||||
}
|
||||
return;
|
||||
|
||||
let mut alive_chunks = vec![];
|
||||
for ((x, y), z) in (-10..=10)
|
||||
.cartesian_product(-10..=10)
|
||||
.cartesian_product(-10..=10)
|
||||
{
|
||||
let chunk = eye_chunk + cgmath::Vector3::new(x, y, z);
|
||||
if chunk.x >= 0
|
||||
&& chunk.x < (self.width / 256) as i32
|
||||
&& chunk.z >= 0
|
||||
&& chunk.z < (self.height / 256) as i32
|
||||
{
|
||||
if chunk.y == -1
|
||||
{
|
||||
alive_chunks.push(chunk);
|
||||
println!("{}, {}, {}", chunk.x, chunk.y, chunk.z);
|
||||
}
|
||||
continue;
|
||||
|
||||
let chunk_voxel_height = y * 256;
|
||||
let submit = [
|
||||
(chunk.x, chunk.z),
|
||||
(chunk.x + 1, chunk.z),
|
||||
(chunk.x, chunk.z + 1),
|
||||
(chunk.x + 1, chunk.z + 1),
|
||||
]
|
||||
.iter()
|
||||
.map(|(chunk_x, chunk_z)| {
|
||||
let voxel_x = chunk_x * 256;
|
||||
let voxel_z = chunk_z * 256;
|
||||
|
||||
let altitude =
|
||||
self.heightmap[voxel_x as usize + voxel_z as usize * self.width as usize];
|
||||
let voxel_height =
|
||||
map(altitude, self.height_min, self.height_max, 0., 100. * 256.);
|
||||
//println!("{}", voxel_height);
|
||||
(chunk_voxel_height as f32) < voxel_height
|
||||
})
|
||||
.reduce(|a, b| a || b)
|
||||
.unwrap_or(false);
|
||||
if submit
|
||||
{
|
||||
alive_chunks.push(chunk);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render(&mut self, render_pass: &mut RenderPass, camera: &Camera)
|
||||
{
|
||||
if !self.alive_chunks.is_empty()
|
||||
{}
|
||||
self.voxel_renderer.render(render_pass, camera);
|
||||
}
|
||||
}
|
||||
|
||||
fn map(x: f32, x_min: f32, x_max: f32, y_min: f32, y_max: f32) -> f32
|
||||
{
|
||||
((x - x_min) / (x_max - x_min)) * (y_max - y_min) + y_min
|
||||
}
|
||||
@ -2,11 +2,8 @@
|
||||
#![feature(generic_const_exprs)]
|
||||
|
||||
pub mod egui_renderer;
|
||||
pub mod hm_renderer;
|
||||
pub mod state;
|
||||
pub mod voxel;
|
||||
pub mod voxel_renderer;
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use winit::application::ApplicationHandler;
|
||||
|
||||
54
src/state.rs
54
src/state.rs
@ -15,6 +15,7 @@ use wgpu::Device;
|
||||
use wgpu::Extent3d;
|
||||
use wgpu::FeaturesWGPU;
|
||||
use wgpu::FeaturesWebGPU;
|
||||
use wgpu::RenderPipeline;
|
||||
use wgpu::TextureDescriptor;
|
||||
use wgpu::TextureFormat;
|
||||
use wgpu::TextureUsages;
|
||||
@ -26,7 +27,6 @@ use winit::keyboard::KeyCode;
|
||||
use winit::window::Window;
|
||||
|
||||
use crate::egui_renderer::EguiState;
|
||||
use crate::voxel_renderer::VoxelRenderer;
|
||||
|
||||
pub struct State
|
||||
{
|
||||
@ -46,8 +46,7 @@ pub struct State
|
||||
last_frame: Instant,
|
||||
|
||||
depth_buffer: TextureView,
|
||||
|
||||
voxel_renderer: VoxelRenderer,
|
||||
test_pipeline: RenderPipeline,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
@ -72,6 +71,8 @@ impl State
|
||||
{
|
||||
pub async fn new(window: Arc<Window>) -> State
|
||||
{
|
||||
let shaders = wgpu::include_spirv!(env!("shaders.spv"));
|
||||
|
||||
let instance = wgpu::Instance::new(&wgpu::InstanceDescriptor {
|
||||
backends: Backends::VULKAN,
|
||||
..wgpu::InstanceDescriptor::default()
|
||||
@ -107,9 +108,52 @@ impl State
|
||||
let cap = surface.get_capabilities(&adapter);
|
||||
let surface_format = cap.formats[0];
|
||||
|
||||
let shader_module = device.create_shader_module(shaders);
|
||||
let test_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
||||
label: Some("chunk_pipeline"),
|
||||
layout: None,
|
||||
vertex: wgpu::VertexState {
|
||||
module: &shader_module,
|
||||
entry_point: Some("vs_main"),
|
||||
buffers: &[],
|
||||
compilation_options: wgpu::PipelineCompilationOptions::default(),
|
||||
},
|
||||
fragment: Some(wgpu::FragmentState {
|
||||
module: &shader_module,
|
||||
entry_point: Some("fs_main"),
|
||||
targets: &[Some(wgpu::ColorTargetState {
|
||||
format: surface_format,
|
||||
blend: None,
|
||||
write_mask: wgpu::ColorWrites::ALL,
|
||||
})],
|
||||
compilation_options: wgpu::PipelineCompilationOptions::default(),
|
||||
}),
|
||||
primitive: wgpu::PrimitiveState {
|
||||
topology: wgpu::PrimitiveTopology::TriangleList,
|
||||
..Default::default()
|
||||
},
|
||||
depth_stencil: Some(wgpu::DepthStencilState {
|
||||
format: TextureFormat::Depth24Plus,
|
||||
depth_write_enabled: true,
|
||||
depth_compare: wgpu::CompareFunction::Less,
|
||||
stencil: wgpu::StencilState::default(),
|
||||
bias: wgpu::DepthBiasState::default(),
|
||||
}),
|
||||
multisample: wgpu::MultisampleState {
|
||||
count: 1,
|
||||
mask: !0,
|
||||
alpha_to_coverage_enabled: false,
|
||||
},
|
||||
multiview: None,
|
||||
|
||||
cache: None,
|
||||
});
|
||||
|
||||
let state = State {
|
||||
egui_state: EguiState::new(&device, surface_format, &window),
|
||||
|
||||
test_pipeline,
|
||||
|
||||
window,
|
||||
queue,
|
||||
size,
|
||||
@ -139,7 +183,6 @@ impl State
|
||||
TextureFormat::Depth24PlusStencil8,
|
||||
TextureUsages::RENDER_ATTACHMENT,
|
||||
),
|
||||
voxel_renderer: VoxelRenderer::new(&device, surface_format),
|
||||
device,
|
||||
};
|
||||
|
||||
@ -249,6 +292,9 @@ impl State
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
});
|
||||
|
||||
hm_pass.set_pipeline(&self.test_pipeline);
|
||||
hm_pass.draw(0..3, 0..1);
|
||||
}
|
||||
|
||||
// Egui Pass
|
||||
|
||||
@ -1,153 +0,0 @@
|
||||
use cgmath::EuclideanSpace;
|
||||
use cgmath::SquareMatrix;
|
||||
use crevice::std430::AsStd430;
|
||||
use wgpu::Buffer;
|
||||
use wgpu::BufferDescriptor;
|
||||
use wgpu::BufferUsages;
|
||||
use wgpu::Device;
|
||||
use wgpu::PushConstantRange;
|
||||
use wgpu::RenderPass;
|
||||
use wgpu::RenderPipeline;
|
||||
use wgpu::ShaderStages;
|
||||
use wgpu::TextureFormat;
|
||||
use wgpu::VertexAttribute;
|
||||
use wgpu::VertexBufferLayout;
|
||||
use wgpu::VertexFormat;
|
||||
use wgpu::include_wgsl;
|
||||
use wgpu::util::BufferInitDescriptor;
|
||||
use wgpu::util::DeviceExt;
|
||||
|
||||
use crate::state::Camera;
|
||||
|
||||
pub struct VoxelRenderer
|
||||
{
|
||||
chunk_instances_capacity: u32,
|
||||
chunk_instances: Buffer,
|
||||
chunk_pipeline: RenderPipeline,
|
||||
}
|
||||
|
||||
impl VoxelRenderer
|
||||
{
|
||||
pub fn new(device: &Device, surface_format: TextureFormat) -> Self
|
||||
{
|
||||
let chunk_shader_module =
|
||||
device.create_shader_module(include_wgsl!("../shaders/chunk.wgsl"));
|
||||
let chunk_pipeline_layout =
|
||||
device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
||||
label: Some("Render3D Mesh Pipeline Layout"),
|
||||
bind_group_layouts: &[],
|
||||
push_constant_ranges: &[PushConstantRange {
|
||||
stages: ShaderStages::VERTEX,
|
||||
range: 0..ChunkPushConstants::std430_size_static() as u32,
|
||||
}],
|
||||
});
|
||||
|
||||
let chunk_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
||||
label: Some("chunk_pipeline"),
|
||||
layout: Some(&chunk_pipeline_layout),
|
||||
vertex: wgpu::VertexState {
|
||||
module: &chunk_shader_module,
|
||||
entry_point: Some("vertex_main"),
|
||||
buffers: &[VertexBufferLayout {
|
||||
array_stride: size_of::<i32>() as u64 * 3,
|
||||
step_mode: wgpu::VertexStepMode::Instance,
|
||||
attributes: &[VertexAttribute {
|
||||
format: VertexFormat::Sint32x3,
|
||||
offset: 0,
|
||||
shader_location: 0,
|
||||
}],
|
||||
}],
|
||||
compilation_options: wgpu::PipelineCompilationOptions::default(),
|
||||
},
|
||||
fragment: Some(wgpu::FragmentState {
|
||||
module: &chunk_shader_module,
|
||||
entry_point: Some("fragment_main"),
|
||||
targets: &[Some(wgpu::ColorTargetState {
|
||||
format: surface_format,
|
||||
blend: None,
|
||||
write_mask: wgpu::ColorWrites::ALL,
|
||||
})],
|
||||
compilation_options: wgpu::PipelineCompilationOptions::default(),
|
||||
}),
|
||||
primitive: wgpu::PrimitiveState {
|
||||
topology: wgpu::PrimitiveTopology::TriangleList,
|
||||
..Default::default()
|
||||
},
|
||||
depth_stencil: Some(wgpu::DepthStencilState {
|
||||
format: TextureFormat::Depth24Plus,
|
||||
depth_write_enabled: true,
|
||||
depth_compare: wgpu::CompareFunction::Less,
|
||||
stencil: wgpu::StencilState::default(),
|
||||
bias: wgpu::DepthBiasState::default(),
|
||||
}),
|
||||
multisample: wgpu::MultisampleState {
|
||||
count: 1,
|
||||
mask: !0,
|
||||
alpha_to_coverage_enabled: false,
|
||||
},
|
||||
multiview: None,
|
||||
|
||||
cache: None,
|
||||
});
|
||||
|
||||
Self {
|
||||
chunk_instances_capacity: 1,
|
||||
chunk_instances: device.create_buffer(&BufferDescriptor {
|
||||
label: Some("chunk_instances_buffer"),
|
||||
size: size_of::<ChunkInstance>() as u64,
|
||||
usage: BufferUsages::VERTEX,
|
||||
mapped_at_creation: false,
|
||||
}),
|
||||
|
||||
chunk_pipeline,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_chunks(&mut self, device: &Device, chunks: &[cgmath::Vector3<i32>])
|
||||
{
|
||||
self.chunk_instances = device.create_buffer_init(&BufferInitDescriptor {
|
||||
label: Some("chunk_instances_buffer"),
|
||||
contents: unsafe {
|
||||
std::slice::from_raw_parts(
|
||||
chunks.as_ptr() as *const u8,
|
||||
std::mem::size_of_val(chunks),
|
||||
)
|
||||
},
|
||||
usage: BufferUsages::VERTEX,
|
||||
});
|
||||
self.chunk_instances_capacity = chunks.len() as u32;
|
||||
}
|
||||
|
||||
pub fn render(&mut self, render_pass: &mut RenderPass, camera: &Camera)
|
||||
{
|
||||
render_pass.set_pipeline(&self.chunk_pipeline);
|
||||
|
||||
//renderpass.set_vertex_buffer(0, self.positions_buffer.slice(..));
|
||||
render_pass.set_push_constants(
|
||||
ShaderStages::VERTEX,
|
||||
0,
|
||||
ChunkPushConstants {
|
||||
view_projection: camera.view_proj(),
|
||||
transform: cgmath::Matrix4::identity(),
|
||||
eye_position: camera.eye.to_vec(),
|
||||
}
|
||||
.as_std430()
|
||||
.as_bytes(),
|
||||
);
|
||||
render_pass.set_vertex_buffer(0, self.chunk_instances.slice(..));
|
||||
render_pass.draw(0..(6 * 2 * 3), 0..(self.chunk_instances_capacity));
|
||||
}
|
||||
}
|
||||
|
||||
struct ChunkInstance
|
||||
{
|
||||
location: cgmath::Vector3<i32>,
|
||||
}
|
||||
|
||||
#[derive(crevice::std430::AsStd430)]
|
||||
pub struct ChunkPushConstants
|
||||
{
|
||||
view_projection: cgmath::Matrix4<f32>,
|
||||
transform: cgmath::Matrix4<f32>,
|
||||
eye_position: cgmath::Vector3<f32>,
|
||||
}
|
||||
Reference in New Issue
Block a user