Better trilinear interpolation

This commit is contained in:
Marc Gilleron 2022-05-02 15:47:31 +01:00
parent d145a30816
commit 2f2ab384a6
4 changed files with 22 additions and 17 deletions

View File

@ -41,7 +41,7 @@ float get_sdf_interpolated(const Volume_F &f, Vector3 pos) {
const float s011 = f(Vector3i(c.x, c.y + 1, c.z + 1));
const float s111 = f(Vector3i(c.x + 1, c.y + 1, c.z + 1));
return math::interpolate(s000, s100, s101, s001, s010, s110, s111, s011, to_vec3f(math::fract(pos)));
return math::interpolate_trilinear(s000, s100, s101, s001, s010, s110, s111, s011, to_vec3f(math::fract(pos)));
}
// Binary search can be more accurate than linear regression because the SDF can be inaccurate in the first place.

View File

@ -67,9 +67,9 @@ inline HermiteValue get_interpolated_hermite_value(const VoxelBufferInternal &vo
Vector3f rpos = pos - Vector3f(x0, y0, z0);
HermiteValue v;
v.sdf = math::interpolate(v0.sdf, v1.sdf, v2.sdf, v3.sdf, v4.sdf, v5.sdf, v6.sdf, v7.sdf, rpos);
v.gradient = math::interpolate(v0.gradient, v1.gradient, v2.gradient, v3.gradient, v4.gradient, v5.gradient,
v6.gradient, v7.gradient, rpos);
v.sdf = math::interpolate_trilinear(v0.sdf, v1.sdf, v2.sdf, v3.sdf, v4.sdf, v5.sdf, v6.sdf, v7.sdf, rpos);
v.gradient = math::interpolate_trilinear(v0.gradient, v1.gradient, v2.gradient, v3.gradient, v4.gradient,
v5.gradient, v6.gradient, v7.gradient, rpos);
return v;
}

View File

@ -125,7 +125,7 @@ bool can_split(Vector3i node_origin, int node_size, const VoxelAccess &voxels, f
HermiteValue value = get_hermite_value(voxels.buffer, pos.x, pos.y, pos.z);
float interpolated_value = math::interpolate(v0, v1, v2, v3, v4, v5, v6, v7, positions_ratio[i]);
float interpolated_value = math::interpolate_trilinear(v0, v1, v2, v3, v4, v5, v6, v7, positions_ratio[i]);
float gradient_magnitude = value.gradient.length();
if (gradient_magnitude < FLT_EPSILON) {

View File

@ -179,7 +179,9 @@ inline Vector3f operator*(float p_scalar, const Vector3f &v) {
namespace math {
// Trilinear interpolation between corner values of a cube.
// Trilinear interpolation between corner values of a unit-sized cube.
// `v***` arguments are corner values named as `vXYZ`, where a coordinate is 0 or 1 on the cube.
// Coordinates of `p` are in 0..1, but are not clamped so extrapolation is possible.
//
// 6---------------7
// /| /|
@ -193,20 +195,23 @@ namespace math {
// |/ |/ |/
// 1---------------0 X----o
//
// p000, p100, p101, p001, p010, p110, p111, p011
template <typename T>
inline T interpolate(const T v0, const T v1, const T v2, const T v3, const T v4, const T v5, const T v6, const T v7,
Vector3f position) {
const float one_min_x = 1.f - position.x;
const float one_min_y = 1.f - position.y;
const float one_min_z = 1.f - position.z;
const float one_min_x_one_min_y = one_min_x * one_min_y;
const float x_one_min_y = position.x * one_min_y;
inline T interpolate_trilinear(const T v000, const T v100, const T v101, const T v001, const T v010, const T v110,
const T v111, const T v011, Vector3f p) {
//
const T v00 = v000 + p.x * (v100 - v000);
const T v10 = v010 + p.x * (v110 - v010);
const T v01 = v001 + p.x * (v101 - v001);
const T v11 = v011 + p.x * (v111 - v011);
T res = one_min_z * (v0 * one_min_x_one_min_y + v1 * x_one_min_y + v4 * one_min_x * position.y);
res += position.z * (v3 * one_min_x_one_min_y + v2 * x_one_min_y + v7 * one_min_x * position.y);
res += position.x * position.y * (v5 * one_min_z + v6 * position.z);
const T v0 = v00 + p.y * (v10 - v00);
const T v1 = v01 + p.y * (v11 - v01);
return res;
const T v = v0 + p.z * (v1 - v0);
return v;
}
}
} // namespace math