Merge branch '12-terrain-ao' into 'master'

Add terrain and figure ambient occlusion

Closes #12

See merge request veloren/veloren!84

Former-commit-id: 943648d9ca3399e07a275946487d3431ba3832de
This commit is contained in:
Forest Anderson 2019-04-29 13:14:36 +00:00
commit c95bee9838
4 changed files with 205 additions and 235 deletions

View File

@ -1,11 +1,9 @@
mod vol;
pub mod segment;
pub mod terrain;
// Crate
use crate::render::{
self,
Mesh,
};
use crate::render::{self, Mesh};
pub trait Meshable {
type Pipeline: render::Pipeline;

View File

@ -3,43 +3,20 @@ use vek::*;
// Project
use common::{
vol::{
Vox,
SizedVol,
ReadVol,
},
figure::Segment,
vol::{ReadVol, SizedVol, Vox},
};
// Crate
use crate::{
mesh::Meshable,
render::{
self,
Mesh,
Quad,
FigurePipeline,
},
mesh::{vol, Meshable},
render::{self, FigurePipeline, Mesh, Quad},
};
type FigureVertex = <FigurePipeline as render::Pipeline>::Vertex;
// Utility function
// TODO: Evaluate how useful this is
fn create_quad(
origin: Vec3<f32>,
unit_x: Vec3<f32>,
unit_y: Vec3<f32>,
norm: Vec3<f32>,
col: Rgb<f32>,
bone: u8,
) -> Quad<FigurePipeline> {
Quad::new(
FigureVertex::new(origin, norm, col, bone),
FigureVertex::new(origin + unit_x, norm, col, bone),
FigureVertex::new(origin + unit_x + unit_y, norm, col, bone),
FigureVertex::new(origin + unit_y, norm, col, bone),
)
fn create_vertex(origin: Vec3<f32>, norm: Vec3<f32>, col: Rgb<f32>) -> FigureVertex {
FigureVertex::new(origin, norm, col, 0)
}
impl Meshable for Segment {
@ -50,97 +27,17 @@ impl Meshable for Segment {
let mut mesh = Mesh::new();
for pos in self.iter_positions() {
if let Some(col) = self
.get(pos)
.ok()
.and_then(|vox| vox.get_color())
{
if let Some(col) = self.get(pos).ok().and_then(|vox| vox.get_color()) {
let col = col.map(|e| e as f32 / 255.0);
// -x
if self.get(pos - Vec3::unit_x())
.map(|v| v.is_empty())
.unwrap_or(true)
{
mesh.push_quad(create_quad(
offs + pos.map(|e| e as f32) + Vec3::unit_y(),
-Vec3::unit_y(),
Vec3::unit_z(),
-Vec3::unit_x(),
col,
0,
));
}
// +x
if self.get(pos + Vec3::unit_x())
.map(|v| v.is_empty())
.unwrap_or(true)
{
mesh.push_quad(create_quad(
offs + pos.map(|e| e as f32) + Vec3::unit_x(),
Vec3::unit_y(),
Vec3::unit_z(),
Vec3::unit_x(),
col,
0,
));
}
// -y
if self.get(pos - Vec3::unit_y())
.map(|v| v.is_empty())
.unwrap_or(true)
{
mesh.push_quad(create_quad(
offs + pos.map(|e| e as f32),
Vec3::unit_x(),
Vec3::unit_z(),
-Vec3::unit_y(),
col,
0,
));
}
// +y
if self.get(pos + Vec3::unit_y())
.map(|v| v.is_empty())
.unwrap_or(true)
{
mesh.push_quad(create_quad(
offs + pos.map(|e| e as f32) + Vec3::unit_y(),
Vec3::unit_z(),
Vec3::unit_x(),
Vec3::unit_y(),
col,
0,
));
}
// -z
if self.get(pos - Vec3::unit_z())
.map(|v| v.is_empty())
.unwrap_or(true)
{
mesh.push_quad(create_quad(
offs + pos.map(|e| e as f32),
Vec3::unit_y(),
Vec3::unit_x(),
-Vec3::unit_z(),
col,
0,
));
}
// +z
if self.get(pos + Vec3::unit_z())
.map(|v| v.is_empty())
.unwrap_or(true)
{
mesh.push_quad(create_quad(
offs + pos.map(|e| e as f32) + Vec3::unit_z(),
Vec3::unit_x(),
Vec3::unit_y(),
Vec3::unit_z(),
col,
0,
));
}
vol::push_vox_verts(
&mut mesh,
self,
pos,
offs + pos.map(|e| e as f32),
col,
create_vertex,
);
}
}

View File

@ -3,45 +3,19 @@ use vek::*;
// Project
use common::{
vol::{
Vox,
SizedVol,
ReadVol,
},
volumes::dyna::Dyna,
terrain::Block,
vol::{ReadVol, SizedVol, Vox},
volumes::dyna::Dyna,
};
// Crate
use crate::{
mesh::Meshable,
render::{
self,
Mesh,
Quad,
TerrainPipeline,
},
mesh::{vol, Meshable},
render::{self, Mesh, Quad, TerrainPipeline},
};
type TerrainVertex = <TerrainPipeline as render::Pipeline>::Vertex;
// Utility function
// TODO: Evaluate how useful this is
fn create_quad(
origin: Vec3<f32>,
unit_x: Vec3<f32>,
unit_y: Vec3<f32>,
norm: Vec3<f32>,
col: Rgb<f32>,
) -> Quad<TerrainPipeline> {
Quad::new(
TerrainVertex::new(origin, norm, col),
TerrainVertex::new(origin + unit_x, norm, col),
TerrainVertex::new(origin + unit_x + unit_y, norm, col),
TerrainVertex::new(origin + unit_y, norm, col),
)
}
impl<M> Meshable for Dyna<Block, M> {
type Pipeline = TerrainPipeline;
type Supplement = ();
@ -52,95 +26,17 @@ impl<M> Meshable for Dyna<Block, M> {
for pos in self
.iter_positions()
.filter(|pos| pos.map(|e| e >= 1).reduce_and())
.filter(|pos| pos.map2(self.get_size(), |e, sz| e < sz as i32 - 1).reduce_and())
.filter(|pos| {
pos.map2(self.get_size(), |e, sz| e < sz as i32 - 1)
.reduce_and()
})
{
let offs = pos.map(|e| e as f32 - 1.0);
if let Some(col) = self
.get(pos)
.ok()
.and_then(|vox| vox.get_color())
{
if let Some(col) = self.get(pos).ok().and_then(|vox| vox.get_color()) {
let col = col.map(|e| e as f32 / 255.0);
// -x
if self.get(pos - Vec3::unit_x())
.map(|v| v.is_empty())
.unwrap_or(true)
{
mesh.push_quad(create_quad(
offs,
Vec3::unit_z(),
Vec3::unit_y(),
-Vec3::unit_x(),
col,
));
}
// +x
if self.get(pos + Vec3::unit_x())
.map(|v| v.is_empty())
.unwrap_or(true)
{
mesh.push_quad(create_quad(
offs + Vec3::unit_x(),
Vec3::unit_y(),
Vec3::unit_z(),
Vec3::unit_x(),
col,
));
}
// -y
if self.get(pos - Vec3::unit_y())
.map(|v| v.is_empty())
.unwrap_or(true)
{
mesh.push_quad(create_quad(
offs,
Vec3::unit_x(),
Vec3::unit_z(),
-Vec3::unit_y(),
col,
));
}
// +y
if self.get(pos + Vec3::unit_y())
.map(|v| v.is_empty())
.unwrap_or(true)
{
mesh.push_quad(create_quad(
offs + Vec3::unit_y(),
Vec3::unit_z(),
Vec3::unit_x(),
Vec3::unit_y(),
col,
));
}
// -z
if self.get(pos - Vec3::unit_z())
.map(|v| v.is_empty())
.unwrap_or(true)
{
mesh.push_quad(create_quad(
offs,
Vec3::unit_y(),
Vec3::unit_x(),
-Vec3::unit_z(),
col,
));
}
// +z
if self.get(pos + Vec3::unit_z())
.map(|v| v.is_empty())
.unwrap_or(true)
{
mesh.push_quad(create_quad(
offs + Vec3::unit_z(),
Vec3::unit_x(),
Vec3::unit_y(),
Vec3::unit_z(),
col,
));
}
vol::push_vox_verts(&mut mesh, self, pos, offs, col, TerrainVertex::new);
}
}

179
voxygen/src/mesh/vol.rs Normal file
View File

@ -0,0 +1,179 @@
use vek::*;
use common::vol::{ReadVol, Vox};
use crate::render::{
mesh::{Mesh, Quad},
Pipeline,
};
/// Given a volume, a position and the cardinal directions, compute each vertex' AO value
/// `dirs` should be a slice of length 5 so that the sliding window of size 2 over the slice
/// yields each vertex' adjacent positions.
fn get_ao_quad<V: ReadVol>(vol: &V, pos: Vec3<i32>, dirs: &[Vec3<i32>]) -> Vec4<f32> {
dirs.windows(2)
.map(|offs| {
let (s1, s2) = (
vol.get(pos + offs[0])
.map(|v| v.is_empty() as i32)
.unwrap_or(1),
vol.get(pos + offs[1])
.map(|v| v.is_empty() as i32)
.unwrap_or(1),
);
if s1 == 0 && s2 == 0 {
0
} else {
let corner = vol
.get(pos + offs[0] + offs[1])
.map(|v| v.is_empty() as i32)
.unwrap_or(1);
s1 + s2 + corner
}
})
.map(|i| i as f32 / 3.0)
.collect::<Vec4<f32>>()
}
// Utility function
fn create_quad<P: Pipeline, F: Fn(Vec3<f32>, Vec3<f32>, Rgb<f32>) -> P::Vertex>(
origin: Vec3<f32>,
unit_x: Vec3<f32>,
unit_y: Vec3<f32>,
norm: Vec3<f32>,
col: Rgb<f32>,
ao: Vec4<f32>,
vcons: &F,
) -> Quad<P> {
let ao_scale = 1.0;
let dark = col * (1.0 - ao_scale);
if ao[0] + ao[2] < ao[1] + ao[3] {
Quad::new(
vcons(origin + unit_y, norm, Rgb::lerp(dark, col, ao[3])),
vcons(origin, norm, Rgb::lerp(dark, col, ao[0])),
vcons(origin + unit_x, norm, Rgb::lerp(dark, col, ao[1])),
vcons(origin + unit_x + unit_y, norm, Rgb::lerp(dark, col, ao[2])),
)
} else {
Quad::new(
vcons(origin, norm, Rgb::lerp(dark, col, ao[0])),
vcons(origin + unit_x, norm, Rgb::lerp(dark, col, ao[1])),
vcons(origin + unit_x + unit_y, norm, Rgb::lerp(dark, col, ao[2])),
vcons(origin + unit_y, norm, Rgb::lerp(dark, col, ao[3])),
)
}
}
pub fn push_vox_verts<
V: ReadVol,
P: Pipeline,
F: Fn(Vec3<f32>, Vec3<f32>, Rgb<f32>) -> P::Vertex,
>(
mesh: &mut Mesh<P>,
vol: &V,
pos: Vec3<i32>,
offs: Vec3<f32>,
col: Rgb<f32>,
vcons: F,
) {
let (x, y, z) = (Vec3::unit_x(), Vec3::unit_y(), Vec3::unit_z());
// -x
if vol
.get(pos - Vec3::unit_x())
.map(|v| v.is_empty())
.unwrap_or(true)
{
mesh.push_quad(create_quad(
offs,
Vec3::unit_z(),
Vec3::unit_y(),
-Vec3::unit_x(),
col,
get_ao_quad(vol, pos - Vec3::unit_x(), &[-z, -y, z, y, -z]),
&vcons,
));
}
// +x
if vol
.get(pos + Vec3::unit_x())
.map(|v| v.is_empty())
.unwrap_or(true)
{
mesh.push_quad(create_quad(
offs + Vec3::unit_x(),
Vec3::unit_y(),
Vec3::unit_z(),
Vec3::unit_x(),
col,
get_ao_quad(vol, pos + Vec3::unit_x(), &[-y, -z, y, z, -y]),
&vcons,
));
}
// -y
if vol
.get(pos - Vec3::unit_y())
.map(|v| v.is_empty())
.unwrap_or(true)
{
mesh.push_quad(create_quad(
offs,
Vec3::unit_x(),
Vec3::unit_z(),
-Vec3::unit_y(),
col,
get_ao_quad(vol, pos - Vec3::unit_y(), &[-x, -z, x, z, -x]),
&vcons,
));
}
// +y
if vol
.get(pos + Vec3::unit_y())
.map(|v| v.is_empty())
.unwrap_or(true)
{
mesh.push_quad(create_quad(
offs + Vec3::unit_y(),
Vec3::unit_z(),
Vec3::unit_x(),
Vec3::unit_y(),
col,
get_ao_quad(vol, pos + Vec3::unit_y(), &[-z, -x, z, x, -z]),
&vcons,
));
}
// -z
if vol
.get(pos - Vec3::unit_z())
.map(|v| v.is_empty())
.unwrap_or(true)
{
mesh.push_quad(create_quad(
offs,
Vec3::unit_y(),
Vec3::unit_x(),
-Vec3::unit_z(),
col,
get_ao_quad(vol, pos - Vec3::unit_z(), &[-y, -x, y, x, -y]),
&vcons,
));
}
// +z
if vol
.get(pos + Vec3::unit_z())
.map(|v| v.is_empty())
.unwrap_or(true)
{
mesh.push_quad(create_quad(
offs + Vec3::unit_z(),
Vec3::unit_x(),
Vec3::unit_y(),
Vec3::unit_z(),
col,
get_ao_quad(vol, pos + Vec3::unit_z(), &[-x, -y, x, y, -x]),
&vcons,
));
}
}