veloren/voxygen/src/mesh/vol.rs

231 lines
7.0 KiB
Rust
Raw Normal View History

use vek::*;
use crate::render::{
mesh::{Mesh, Quad},
Pipeline,
};
/// Given volume, position, and cardinal directions, compute each vertex's 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.
2019-09-27 10:06:32 +00:00
#[allow(unsafe_code)]
2019-09-27 13:03:08 +00:00
fn get_ao_quad(
2019-06-19 14:55:26 +00:00
shift: Vec3<i32>,
dirs: &[Vec3<i32>],
darknesses: &[[[f32; 3]; 3]; 3],
) -> Vec4<(f32, f32)> {
dirs.windows(2)
2019-07-04 12:02:26 +00:00
.map(|offs| {
2019-09-27 10:06:32 +00:00
let vox_opaque = |pos: Vec3<i32>| {
let pos = (pos + 1).map(|e| e as usize);
unsafe {
darknesses
.get_unchecked(pos.z)
.get_unchecked(pos.y)
.get_unchecked(pos.x)
<= &0.0
}
};
let (s1, s2) = (
2019-09-27 10:06:32 +00:00
vox_opaque(shift + offs[0]),
vox_opaque(shift + offs[1]),
/*
vol.get(pos + shift + offs[0])
.map(&is_opaque)
.unwrap_or(false),
vol.get(pos + shift + offs[1])
.map(&is_opaque)
.unwrap_or(false),
2019-09-27 10:06:32 +00:00
*/
);
let mut darkness = 0.0;
for x in 0..2 {
for y in 0..2 {
let dark_pos = shift + offs[0] * x + offs[1] * y + 1;
2019-09-27 10:06:32 +00:00
darkness += unsafe {
darknesses
.get_unchecked(dark_pos.z as usize)
.get_unchecked(dark_pos.y as usize)
.get_unchecked(dark_pos.x as usize)
} / 4.0;
}
}
2019-06-18 11:33:18 +00:00
(
darkness,
if s1 && s2 {
0.0
} else {
2019-09-27 11:46:20 +00:00
let corner = vox_opaque(shift + offs[0] + offs[1]);
// Map both 1 and 2 neighbors to 0.5 occlusion.
if s1 || s2 || corner { 0.5 } else { 1.0 }
},
)
})
2019-06-18 21:37:48 +00:00
.collect::<Vec4<(f32, f32)>>()
}
2019-09-24 10:28:40 +00:00
#[allow(unsafe_code)]
2019-09-27 13:03:08 +00:00
fn get_col_quad(dirs: &[Vec3<i32>], cols: &[[[Rgba<u8>; 3]; 3]; 3]) -> Vec4<Rgb<f32>> {
2019-09-24 06:42:09 +00:00
dirs.windows(2)
.map(|offs| {
2019-09-27 10:06:32 +00:00
let primary_col = Rgb::from(cols[1][1][1]).map(|e: u8| e as f32);
2019-09-24 06:42:09 +00:00
let mut color = Rgb::zero();
let mut total = 0.0;
for x in 0..2 {
for y in 0..2 {
2019-09-24 10:28:40 +00:00
let col_pos = offs[0] * x + offs[1] * y + 1;
2019-09-27 10:06:32 +00:00
let col = unsafe {
2019-09-24 10:28:40 +00:00
cols.get_unchecked(col_pos.z as usize)
.get_unchecked(col_pos.y as usize)
.get_unchecked(col_pos.x as usize)
2019-09-27 10:06:32 +00:00
};
if col.a > 0 {
let col = Rgb::new(col.r, col.g, col.b).map(|e| e as f32);
if Vec3::<f32>::from(primary_col).distance_squared(Vec3::from(col))
2020-02-07 19:53:38 +00:00
< (0.025f32 * 256.0).powf(2.0)
2019-09-24 06:42:09 +00:00
{
2019-09-27 10:06:32 +00:00
color += col;
total += 256.0;
2019-09-24 06:42:09 +00:00
}
}
}
}
2019-09-24 10:28:40 +00:00
color / total
2019-09-24 06:42:09 +00:00
})
.collect()
}
// Utility function
2019-06-18 21:37:48 +00:00
fn create_quad<P: Pipeline, F: Fn(Vec3<f32>, Vec3<f32>, Rgb<f32>, f32, f32) -> P::Vertex>(
origin: Vec3<f32>,
unit_x: Vec3<f32>,
unit_y: Vec3<f32>,
norm: Vec3<f32>,
2019-09-24 06:42:09 +00:00
cols: Vec4<Rgb<f32>>,
2019-06-18 21:37:48 +00:00
darkness_ao: Vec4<(f32, f32)>,
vcons: &F,
) -> Quad<P> {
2019-06-18 21:37:48 +00:00
let darkness = darkness_ao.map(|e| e.0);
let ao = darkness_ao.map(|e| e.1);
2019-09-27 13:03:08 +00:00
let ao_map = ao;
2019-09-24 17:56:51 +00:00
if ao[0].min(ao[2]).min(darkness[0]).min(darkness[2])
< ao[1].min(ao[3]).min(darkness[1]).min(darkness[3])
{
Quad::new(
2019-09-24 06:42:09 +00:00
vcons(origin + unit_y, norm, cols[3], darkness[3], ao_map[3]),
vcons(origin, norm, cols[0], darkness[0], ao_map[0]),
vcons(origin + unit_x, norm, cols[1], darkness[1], ao_map[1]),
vcons(
origin + unit_x + unit_y,
norm,
cols[2],
darkness[2],
ao_map[2],
),
)
} else {
Quad::new(
2019-09-24 06:42:09 +00:00
vcons(origin, norm, cols[0], darkness[0], ao_map[0]),
vcons(origin + unit_x, norm, cols[1], darkness[1], ao_map[1]),
vcons(
origin + unit_x + unit_y,
norm,
cols[2],
darkness[2],
ao_map[2],
),
vcons(origin + unit_y, norm, cols[3], darkness[3], ao_map[3]),
)
}
}
pub fn push_vox_verts<P: Pipeline>(
mesh: &mut Mesh<P>,
faces: [bool; 6],
offs: Vec3<f32>,
2019-09-27 10:06:32 +00:00
cols: &[[[Rgba<u8>; 3]; 3]; 3],
vcons: impl Fn(Vec3<f32>, Vec3<f32>, Rgb<f32>, f32, f32) -> P::Vertex,
2019-06-18 11:33:18 +00:00
darknesses: &[[[f32; 3]; 3]; 3],
) {
let (x, y, z) = (Vec3::unit_x(), Vec3::unit_y(), Vec3::unit_z());
// -x
if faces[0] {
mesh.push_quad(create_quad(
offs,
Vec3::unit_z(),
Vec3::unit_y(),
-Vec3::unit_x(),
2019-09-27 13:03:08 +00:00
get_col_quad(&[-z, -y, z, y, -z], cols),
get_ao_quad(-Vec3::unit_x(), &[-z, -y, z, y, -z], darknesses),
&vcons,
));
}
// +x
if faces[1] {
mesh.push_quad(create_quad(
offs + Vec3::unit_x(),
Vec3::unit_y(),
Vec3::unit_z(),
Vec3::unit_x(),
2019-09-27 13:03:08 +00:00
get_col_quad(&[-y, -z, y, z, -y], cols),
get_ao_quad(Vec3::unit_x(), &[-y, -z, y, z, -y], darknesses),
&vcons,
));
}
// -y
if faces[2] {
mesh.push_quad(create_quad(
offs,
Vec3::unit_x(),
Vec3::unit_z(),
-Vec3::unit_y(),
2019-09-27 13:03:08 +00:00
get_col_quad(&[-x, -z, x, z, -x], cols),
get_ao_quad(-Vec3::unit_y(), &[-x, -z, x, z, -x], darknesses),
&vcons,
));
}
// +y
if faces[3] {
mesh.push_quad(create_quad(
offs + Vec3::unit_y(),
Vec3::unit_z(),
Vec3::unit_x(),
Vec3::unit_y(),
2019-09-27 13:03:08 +00:00
get_col_quad(&[-z, -x, z, x, -z], cols),
get_ao_quad(Vec3::unit_y(), &[-z, -x, z, x, -z], darknesses),
&vcons,
));
}
// -z
if faces[4] {
mesh.push_quad(create_quad(
offs,
Vec3::unit_y(),
Vec3::unit_x(),
-Vec3::unit_z(),
2019-09-27 13:03:08 +00:00
get_col_quad(&[-y, -x, y, x, -y], cols),
get_ao_quad(-Vec3::unit_z(), &[-y, -x, y, x, -y], darknesses),
&vcons,
));
}
// +z
if faces[5] {
mesh.push_quad(create_quad(
offs + Vec3::unit_z(),
Vec3::unit_x(),
Vec3::unit_y(),
Vec3::unit_z(),
2019-09-27 13:03:08 +00:00
get_col_quad(&[-x, -y, x, y, -x], cols),
get_ao_quad(Vec3::unit_z(), &[-x, -y, x, y, -x], darknesses),
&vcons,
));
}
}