Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Density mesh terrain #188

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ tiff = { path = "lib/tiff" }
bytemuck = "1"
byteorder = "1.0"
cgmath = { version = "0.18", features = ["rand"] }
density-mesh-core = { version = "1.5", optional = true }
futures = "0.3"
glsl-to-spirv = { version = "0.1", optional = true }
log = "0.4"
Expand Down
3 changes: 2 additions & 1 deletion bin/boilerplate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,8 @@ impl Harness {
Terrain::RayTraced { .. }
| Terrain::RayMipTraced { .. }
| Terrain::Sliced { .. }
| Terrain::Painted { .. } => wgpu::Limits::downlevel_webgl2_defaults(),
| Terrain::Painted { .. }
| Terrain::Mesh { .. } => wgpu::Limits::downlevel_webgl2_defaults(),
Terrain::Scattered { .. } => wgpu::Limits::default(),
};
if options.uses_level {
Expand Down
26 changes: 26 additions & 0 deletions res/shader/terrain/mesh.wgsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//!include globals.inc surface.inc color.inc

struct Varyings {
[[location(0)]] vpos: vec4<f32>;
[[builtin(position)]] proj_pos: vec4<f32>;
};

[[stage(vertex)]]
fn main_vs(
[[location(0)]] pos: vec2<f32>,
) -> Varyings {
let surface = get_surface(pos);
let vpos = vec4<f32>(pos, surface.low_alt, 1.0);
return Varyings(vpos, u_Globals.view_proj * vpos);
}


//imported: Surface, u_TextureScale, get_surface, evaluate_color

[[stage(fragment)]]
fn main_fs(in: Varyings) -> [[location(0)]] vec4<f32> {
let surface = get_surface(in.vpos.xy);
let ty = surface.low_type;
let lit_factor = 1.0;
return evaluate_color(ty, surface.tex_coord, in.vpos.z / u_Surface.texture_scale.z, lit_factor);
}
1 change: 1 addition & 0 deletions src/config/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ pub enum Terrain {
Scattered {
density: [u32; 3],
},
Mesh,
}

#[derive(Copy, Clone, Deserialize)]
Expand Down
2 changes: 0 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
#![deny(
trivial_casts,
trivial_numeric_casts,
unused,
unused_qualifications,
rust_2018_compatibility,
rust_2018_idioms,
future_incompatible,
Expand Down
203 changes: 202 additions & 1 deletion src/render/terrain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ struct Geometry {

impl Geometry {
fn new(vertices: &[Vertex], indices: &[u16], device: &wgpu::Device) -> Self {
Geometry {
Self {
vertex_buf: device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some("terrain-vertex"),
contents: bytemuck::cast_slice(vertices),
Expand All @@ -144,6 +144,25 @@ impl Geometry {
num_indices: indices.len() as u32,
}
}

#[cfg(feature = "density-mesh-core")]
fn with_capacity(vertex_count: usize, index_count: usize, device: &wgpu::Device) -> Self {
Self {
vertex_buf: device.create_buffer(&wgpu::BufferDescriptor {
label: Some("terrain-vertex"),
size: (vertex_count * mem::size_of::<Vertex>()) as wgpu::BufferAddress,
usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST,
mapped_at_creation: false,
}),
index_buf: device.create_buffer(&wgpu::BufferDescriptor {
label: Some("terrain-index"),
size: index_count as wgpu::BufferAddress * 2,
usage: wgpu::BufferUsages::INDEX | wgpu::BufferUsages::COPY_DST,
mapped_at_creation: false,
}),
num_indices: index_count as u32,
}
}
}

enum Kind {
Expand Down Expand Up @@ -174,6 +193,15 @@ enum Kind {
compute_groups: [u32; 3],
density: [u32; 3],
},
#[cfg(feature = "density-mesh-core")]
Mesh {
pipeline: wgpu::RenderPipeline,
geo: Geometry,
vertex_capacity: usize,
index_capacity: usize,
is_dirty: bool,
generator: density_mesh_core::generator::DensityMeshGenerator,
},
}

pub struct Flood {
Expand Down Expand Up @@ -337,6 +365,50 @@ impl Context {
})
}

#[cfg(feature = "density-mesh-core")]
fn create_mesh_pipeline(
layout: &wgpu::PipelineLayout,
device: &wgpu::Device,
color_format: wgpu::TextureFormat,
) -> wgpu::RenderPipeline {
let shader = super::load_shader("terrain/mesh", device).unwrap();
device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some("terrain-mesh"),
layout: Some(layout),
vertex: wgpu::VertexState {
module: &shader,
entry_point: "main_vs",
buffers: &[wgpu::VertexBufferLayout {
array_stride: 2 * 4,
step_mode: wgpu::VertexStepMode::Vertex,
attributes: &[wgpu::VertexAttribute {
offset: 0,
format: wgpu::VertexFormat::Float32x2,
shader_location: 0,
}],
}],
},
fragment: Some(wgpu::FragmentState {
module: &shader,
entry_point: "main_fs",
targets: &[color_format.into()],
}),
primitive: wgpu::PrimitiveState {
topology: wgpu::PrimitiveTopology::TriangleList,
..Default::default()
},
depth_stencil: Some(wgpu::DepthStencilState {
format: DEPTH_FORMAT,
depth_write_enabled: true,
depth_compare: wgpu::CompareFunction::Less,
stencil: Default::default(),
bias: Default::default(),
}),
multisample: wgpu::MultisampleState::default(),
multiview: None,
})
}

fn create_scatter_pipelines(
layout: &wgpu::PipelineLayout,
device: &wgpu::Device,
Expand Down Expand Up @@ -895,6 +967,68 @@ impl Context {
density,
}
}
#[cfg(not(feature = "density-mesh-core"))]
settings::Terrain::Mesh => {
panic!("Feature 'density-mesh-core' is not enabled");
}
#[cfg(feature = "density-mesh-core")]
settings::Terrain::Mesh => {
use density_mesh_core::prelude::*;
let mut raw_data =
Vec::with_capacity(extent.width as usize * extent.height as usize);
{
let mut value = 0;
for (i, (&h, &m)) in level.height.iter().zip(level.meta.iter()).enumerate() {
if i & 1 == 0 || m & level::DOUBLE_LEVEL == 0 {
value = h;
}
raw_data.push(value);
}
}
let map =
DensityMap::new(extent.width as usize, extent.height as usize, 1, raw_data)
.unwrap();
let settings = GenerateDensityMeshSettings {
points_separation: PointsSeparation::Constant(16.0),
visibility_threshold: 0.3,
steepness_threshold: 0.3,
max_iterations: 8,
extrude_size: None,
keep_invisible_triangles: true,
};
// create density mesh.
let generator = DensityMeshGenerator::new(Vec::new(), map, settings);

/*{
generator.process_wait().unwrap();
let mut image = image::DynamicImage::ImageRgba8(
density_mesh_image::generate_image_from_densitymap(generator.map(), false),
);
density_mesh_image::apply_mesh_on_map(&mut image, generator.mesh().unwrap());
image
.save("heightmap.live.png")
.expect("Cannot save output image");
}*/

let pipeline = Self::create_mesh_pipeline(
&pipeline_layout,
device,
global.color_format,
);

let vertex_capacity = 4;
let index_capacity = 4;
let geo = Geometry::with_capacity(vertex_capacity, index_capacity, device);

Kind::Mesh {
pipeline,
geo,
vertex_capacity,
index_capacity,
is_dirty: true,
generator,
}
}
};

let shadow_kind = match *shadow_config {
Expand Down Expand Up @@ -993,6 +1127,14 @@ impl Context {
*clear_pipeline = clear;
*copy_pipeline = copy;
}
#[cfg(feature = "density-mesh-core")]
Kind::Mesh { ref mut pipeline, .. } => {
*pipeline = Self::create_mesh_pipeline(
&self.pipeline_layout,
device,
self.color_format,
);
}
}

match self.shadow_kind {
Expand Down Expand Up @@ -1225,6 +1367,58 @@ impl Context {
density[2],
);
}
#[cfg(feature = "density-mesh-core")]
Kind::Mesh { ref mut geo, ref mut vertex_capacity, ref mut index_capacity, ref mut is_dirty, pipeline: _, ref mut generator } => {
if *is_dirty {
*is_dirty = false;
generator
//.process_wait()
.process_wait_tracked(|progress, limit, _| println!("{}/{}", progress, limit))
.unwrap();
let mesh = generator.mesh().unwrap();

if mesh.points.len() > *vertex_capacity {
*vertex_capacity = mesh.points.len() * 6 / 4;
geo.vertex_buf = device.create_buffer(&wgpu::BufferDescriptor {
label: Some("terrain-vertex"),
size: *vertex_capacity as wgpu::BufferAddress * 2 * 4,
usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST,
mapped_at_creation: false,
});
}
if mesh.triangles.len() * 3 > *index_capacity {
*index_capacity = mesh.triangles.len() * 3 * 6 / 4;
geo.index_buf = device.create_buffer(&wgpu::BufferDescriptor {
label: Some("terrain-index"),
size: *index_capacity as wgpu::BufferAddress * 2,
usage: wgpu::BufferUsages::INDEX | wgpu::BufferUsages::COPY_DST,
mapped_at_creation: false,
});
}
geo.num_indices = mesh.triangles.len() as u32 * 3;

//TODO: avoid heap alloc
let temp_vert = mesh.points.iter().map(|coord| [coord.x, coord.y]).collect::<Vec<_>>();
let staging_vert = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: None,
contents: bytemuck::cast_slice(&temp_vert),
usage: wgpu::BufferUsages::COPY_SRC,
});
encoder.copy_buffer_to_buffer(&staging_vert, 0, &geo.vertex_buf, 0, 4 * 2 * temp_vert.len() as wgpu::BufferAddress);

let mut temp_ind = mesh.triangles.iter().map(|tri| [tri.a as u16, tri.b as u16, tri.c as u16]).collect::<Vec<_>>();
// make sure the copy size is aligned to 4
if temp_ind.len() & 1 == 1 {
temp_ind.push([0, 0, 0]);
}
let staging_ind = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: None,
contents: bytemuck::cast_slice(&temp_ind),
usage: wgpu::BufferUsages::COPY_SRC,
});
encoder.copy_buffer_to_buffer(&staging_ind, 0, &geo.index_buf, 0, 2 * 3 * temp_ind.len() as wgpu::BufferAddress);
}
}
_ => {}
}
}
Expand Down Expand Up @@ -1317,6 +1511,13 @@ impl Context {
pass.set_bind_group(2, bind_group, &[]);
pass.draw(0..4, 0..1);
}
#[cfg(feature = "density-mesh-core")]
Kind::Mesh { ref pipeline, ref geo, .. } => {
pass.set_pipeline(pipeline);
pass.set_index_buffer(geo.index_buf.slice(..), wgpu::IndexFormat::Uint16);
pass.set_vertex_buffer(0, geo.vertex_buf.slice(..));
pass.draw_indexed(0..geo.num_indices, 0, 0..1);
}
}
}

Expand Down