Merge branch 'ao-artifact-fix' into 'master'

Fix ambient occlusion artifact

See merge request veloren/veloren!89

Former-commit-id: b529f9df722d8b174b0c8e5ce9ef2d32965d7294
This commit is contained in:
Forest Anderson 2019-04-29 17:00:56 +00:00
commit 3c45d3c996

View File

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