Skip to content

Commit

Permalink
Add various tests for HalfGrid: LevelSetAdvect, Interpolation, Morpho…
Browse files Browse the repository at this point in the history
…logy, Grid, LevelSetUtil, RayIntersector, etc.

Signed-off-by: apradhana <[email protected]>
  • Loading branch information
apradhana committed Nov 5, 2024
1 parent e48ac90 commit a113cfc
Show file tree
Hide file tree
Showing 16 changed files with 669 additions and 241 deletions.
7 changes: 7 additions & 0 deletions openvdb/openvdb/Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,13 @@ template<typename FromType, typename ToType> struct CopyConstness<const FromType
};
/// @endcond

////////////////////////////////////////

template<class T>
struct is_floating_point : std::is_floating_point<T> { };

template<>
struct is_floating_point<math::half> : std::is_floating_point<float> { };

////////////////////////////////////////

Expand Down
3 changes: 2 additions & 1 deletion openvdb/openvdb/tools/Diagnostics.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#define OPENVDB_TOOLS_DIAGNOSTICS_HAS_BEEN_INCLUDED

#include <openvdb/Grid.h>
#include <openvdb/Types.h> // for openvdb::is_floating_point
#include <openvdb/math/Math.h>
#include <openvdb/math/Vec3.h>
#include <openvdb/math/Stencils.h>
Expand Down Expand Up @@ -428,7 +429,7 @@ template<typename GridT,
struct CheckNormGrad
{
using ValueType = typename GridT::ValueType;
static_assert(std::is_floating_point<ValueType>::value,
static_assert(openvdb::is_floating_point<ValueType>::value,
"openvdb::tools::CheckNormGrad requires a scalar, floating-point grid");
using TileIterT = TreeIterT;
using VoxelIterT = typename tree::IterTraits<typename TreeIterT::NodeT,
Expand Down
2 changes: 1 addition & 1 deletion openvdb/openvdb/tools/RayIntersector.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ class LevelSetRayIntersector
using TreeT = typename GridT::TreeType;

static_assert(NodeLevel >= -1 && NodeLevel < int(TreeT::DEPTH)-1, "NodeLevel out of range");
static_assert(std::is_floating_point<ValueT>::value,
static_assert(openvdb::is_floating_point<ValueT>::value,
"level set grids must have scalar, floating-point value types");

/// @brief Constructor
Expand Down
23 changes: 23 additions & 0 deletions openvdb/openvdb/unittest/TestDiagnostics.cc
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,29 @@ TEST_F(TestDiagnostics, testDiagnose)
}
}// testDiagnose

TEST_F(TestDiagnostics, testDiagnoseHalf)
{
using namespace openvdb;
using half = openvdb::math::half;

const half radius = 4.3f;
const openvdb::Vec3H center(half(15.8), half(13.2), half(16.7));
const half voxelSize = 0.1f, width = 2.0f, gamma=voxelSize*width;

HalfGrid::Ptr gridSphere =
tools::createLevelSetSphere<HalfGrid>(radius, center, voxelSize, width);

{// check norm of gradient of sphere w/o mask
tools::CheckNormGrad<HalfGrid> c(*gridSphere, 0.75f, 1.25f);
tools::Diagnose<HalfGrid> d(*gridSphere);
std::string str = d.check(c, false, true, false, false);
//std::cerr << "NormGrad:\n" << str;
EXPECT_TRUE(str.empty());
EXPECT_EQ(0, int(d.valueCount()));
EXPECT_EQ(0, int(d.failureCount()));
}
}// testDiagnoseHalf

TEST_F(TestDiagnostics, testCheckLevelSet)
{
using namespace openvdb;
Expand Down
1 change: 1 addition & 0 deletions openvdb/openvdb/unittest/TestGrid.cc
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ class ProxyTree: public openvdb::TreeBase
public:
using ValueType = int;
using BuildType = int;
using ComputeType = int;
using LeafNodeType = void;
using ValueAllCIter = void;
using ValueAllIter = void;
Expand Down
105 changes: 62 additions & 43 deletions openvdb/openvdb/unittest/TestLevelSetRayIntersector.cc
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@ class TestLevelSetRayIntersector : public ::testing::Test
};


TEST_F(TestLevelSetRayIntersector, tests)
template<typename GridT>
void
testLevelSetRayIntersectorImpl()
{
using namespace openvdb;
typedef math::Ray<double> RayT;
Expand All @@ -45,9 +47,9 @@ TEST_F(TestLevelSetRayIntersector, tests)
const Vec3f c(20.0f, 0.0f, 0.0f);
const float s = 0.5f, w = 2.0f;

FloatGrid::Ptr ls = tools::createLevelSetSphere<FloatGrid>(r, c, s, w);
typename GridT::Ptr ls = tools::createLevelSetSphere<GridT>(r, c, s, w);

tools::LevelSetRayIntersector<FloatGrid> lsri(*ls);
tools::LevelSetRayIntersector<GridT> lsri(*ls);

const Vec3T dir(1.0, 0.0, 0.0);
const Vec3T eye(2.0, 0.0, 0.0);
Expand All @@ -73,9 +75,9 @@ TEST_F(TestLevelSetRayIntersector, tests)
const Vec3f c(20.0f, 0.0f, 0.0f);
const float s = 0.5f, w = 2.0f;

FloatGrid::Ptr ls = tools::createLevelSetSphere<FloatGrid>(r, c, s, w);
typename GridT::Ptr ls = tools::createLevelSetSphere<GridT>(r, c, s, w);

tools::LevelSetRayIntersector<FloatGrid> lsri(*ls);
tools::LevelSetRayIntersector<GridT> lsri(*ls);

const Vec3T dir(1.0,-0.0,-0.0);
const Vec3T eye(2.0, 0.0, 0.0);
Expand All @@ -101,74 +103,79 @@ TEST_F(TestLevelSetRayIntersector, tests)
const Vec3f c(0.0f, 20.0f, 0.0f);
const float s = 1.5f, w = 2.0f;

FloatGrid::Ptr ls = tools::createLevelSetSphere<FloatGrid>(r, c, s, w);
typename GridT::Ptr ls = tools::createLevelSetSphere<GridT>(r, c, s, w);

tools::LevelSetRayIntersector<FloatGrid> lsri(*ls);
tools::LevelSetRayIntersector<GridT> lsri(*ls);

const Vec3T dir(0.0, 1.0, 0.0);
const Vec3T eye(0.0,-2.0, 0.0);
RayT ray(eye, dir);
Vec3T xyz(0);
Real time = 0;
constexpr double tolerance = std::is_floating_point_v<typename GridT::ValueType> ? 1e-6 : 1e-3;

EXPECT_TRUE(lsri.intersectsWS(ray, xyz, time));
ASSERT_DOUBLES_APPROX_EQUAL( 0.0, xyz[0]);
ASSERT_DOUBLES_APPROX_EQUAL(15.0, xyz[1]);
ASSERT_DOUBLES_APPROX_EQUAL( 0.0, xyz[2]);
ASSERT_DOUBLES_APPROX_EQUAL(17.0, time);
EXPECT_NEAR( 0.0, xyz[0], tolerance);
EXPECT_NEAR(15.0, xyz[1], tolerance);
EXPECT_NEAR( 0.0, xyz[2], tolerance);
EXPECT_NEAR(17.0, time, tolerance);
double t0=0, t1=0;
EXPECT_TRUE(ray.intersects(c, r, t0, t1));
ASSERT_DOUBLES_APPROX_EQUAL(t0, time);
EXPECT_NEAR(t0, time, tolerance);
//std::cerr << "\nray("<<t0<<")="<<ray(t0)<<std::endl;
//std::cerr << "Intersection at xyz = " << xyz << std::endl;
ASSERT_DOUBLES_APPROX_EQUAL( 0.0, ray(t0)[0]);
ASSERT_DOUBLES_APPROX_EQUAL(15.0, ray(t0)[1]);
ASSERT_DOUBLES_APPROX_EQUAL( 0.0, ray(t0)[2]);
EXPECT_NEAR( 0.0, ray(t0)[0], tolerance);
EXPECT_NEAR(15.0, ray(t0)[1], tolerance);
EXPECT_NEAR( 0.0, ray(t0)[2], tolerance);
}

{// voxel intersection against a level set sphere
const float r = 5.0f;
const Vec3f c(0.0f, 20.0f, 0.0f);
const float s = 1.5f, w = 2.0f;

FloatGrid::Ptr ls = tools::createLevelSetSphere<FloatGrid>(r, c, s, w);
typename GridT::Ptr ls = tools::createLevelSetSphere<GridT>(r, c, s, w);

tools::LevelSetRayIntersector<FloatGrid> lsri(*ls);
tools::LevelSetRayIntersector<GridT> lsri(*ls);

const Vec3T dir(-0.0, 1.0,-0.0);
const Vec3T eye( 0.0,-2.0, 0.0);
RayT ray(eye, dir);
Vec3T xyz(0);
Real time = 0;
constexpr double tolerance = std::is_floating_point_v<typename GridT::ValueType> ? 1e-6 : 1e-3;

EXPECT_TRUE(lsri.intersectsWS(ray, xyz, time));
ASSERT_DOUBLES_APPROX_EQUAL( 0.0, xyz[0]);
ASSERT_DOUBLES_APPROX_EQUAL(15.0, xyz[1]);
ASSERT_DOUBLES_APPROX_EQUAL( 0.0, xyz[2]);
ASSERT_DOUBLES_APPROX_EQUAL(17.0, time);
EXPECT_NEAR( 0.0, xyz[0], tolerance);
EXPECT_NEAR(15.0, xyz[1], tolerance);
EXPECT_NEAR( 0.0, xyz[2], tolerance);
EXPECT_NEAR(17.0, time, tolerance);
double t0=0, t1=0;
EXPECT_TRUE(ray.intersects(c, r, t0, t1));
ASSERT_DOUBLES_APPROX_EQUAL(t0, time);
EXPECT_NEAR(t0, time, tolerance);
//std::cerr << "\nray("<<t0<<")="<<ray(t0)<<std::endl;
//std::cerr << "Intersection at xyz = " << xyz << std::endl;
ASSERT_DOUBLES_APPROX_EQUAL( 0.0, ray(t0)[0]);
ASSERT_DOUBLES_APPROX_EQUAL(15.0, ray(t0)[1]);
ASSERT_DOUBLES_APPROX_EQUAL( 0.0, ray(t0)[2]);
EXPECT_NEAR( 0.0, ray(t0)[0], tolerance);
EXPECT_NEAR(15.0, ray(t0)[1], tolerance);
EXPECT_NEAR( 0.0, ray(t0)[2], tolerance);
}

{// voxel intersection against a level set sphere
const float r = 5.0f;
const Vec3f c(0.0f, 0.0f, 20.0f);
const float s = 1.0f, w = 3.0f;

FloatGrid::Ptr ls = tools::createLevelSetSphere<FloatGrid>(r, c, s, w);
typename GridT::Ptr ls = tools::createLevelSetSphere<GridT>(r, c, s, w);

typedef tools::LinearSearchImpl<FloatGrid> SearchImplT;
tools::LevelSetRayIntersector<FloatGrid, SearchImplT, -1> lsri(*ls);
typedef tools::LinearSearchImpl<GridT> SearchImplT;
tools::LevelSetRayIntersector<GridT, SearchImplT, -1> lsri(*ls);

const Vec3T dir(0.0, 0.0, 1.0);
const Vec3T eye(0.0, 0.0, 4.0);
RayT ray(eye, dir);
Vec3T xyz(0);
Real time = 0;

EXPECT_TRUE(lsri.intersectsWS(ray, xyz, time));
ASSERT_DOUBLES_APPROX_EQUAL( 0.0, xyz[0]);
ASSERT_DOUBLES_APPROX_EQUAL( 0.0, xyz[1]);
Expand All @@ -189,10 +196,10 @@ TEST_F(TestLevelSetRayIntersector, tests)
const Vec3f c(0.0f, 0.0f, 20.0f);
const float s = 1.0f, w = 3.0f;

FloatGrid::Ptr ls = tools::createLevelSetSphere<FloatGrid>(r, c, s, w);
typename GridT::Ptr ls = tools::createLevelSetSphere<GridT>(r, c, s, w);

typedef tools::LinearSearchImpl<FloatGrid> SearchImplT;
tools::LevelSetRayIntersector<FloatGrid, SearchImplT, -1> lsri(*ls);
typedef tools::LinearSearchImpl<GridT> SearchImplT;
tools::LevelSetRayIntersector<GridT, SearchImplT, -1> lsri(*ls);

const Vec3T dir(-0.0,-0.0, 1.0);
const Vec3T eye( 0.0, 0.0, 4.0);
Expand Down Expand Up @@ -220,10 +227,10 @@ TEST_F(TestLevelSetRayIntersector, tests)
const Vec3f c(0.0f, 0.0f, 20.0f);
const float s = 1.0f, w = 3.0f;

FloatGrid::Ptr ls = tools::createLevelSetSphere<FloatGrid>(r, c, s, w);
typename GridT::Ptr ls = tools::createLevelSetSphere<GridT>(r, c, s, w);

typedef tools::LinearSearchImpl<FloatGrid> SearchImplT;
tools::LevelSetRayIntersector<FloatGrid, SearchImplT, -1> lsri(*ls);
typedef tools::LinearSearchImpl<GridT> SearchImplT;
tools::LevelSetRayIntersector<GridT, SearchImplT, -1> lsri(*ls);

const Vec3T dir(-0.0,-0.0, 1.0);
const Vec3T eye( 0.0, 0.0, 4.0);
Expand Down Expand Up @@ -251,41 +258,43 @@ TEST_F(TestLevelSetRayIntersector, tests)
const Vec3f c(10.0f, 10.0f, 10.0f);
const float s = 1.0f, w = 3.0f;

FloatGrid::Ptr ls = tools::createLevelSetSphere<FloatGrid>(r, c, s, w);
typename GridT::Ptr ls = tools::createLevelSetSphere<GridT>(r, c, s, w);

tools::LevelSetRayIntersector<FloatGrid> lsri(*ls);
tools::LevelSetRayIntersector<GridT> lsri(*ls);

Vec3T dir(1.0, 1.0, 1.0); dir.normalize();
const Vec3T eye(0.0, 0.0, 0.0);
RayT ray(eye, dir);
//std::cerr << "ray: " << ray << std::endl;
Vec3T xyz(0);
Real time = 0;
constexpr double tolerance = std::is_floating_point_v<typename GridT::ValueType> ? 1e-6 : 2e-5;

EXPECT_TRUE(lsri.intersectsWS(ray, xyz, time));
//std::cerr << "\nIntersection at xyz = " << xyz << std::endl;
//analytical intersection test
double t0=0, t1=0;
EXPECT_TRUE(ray.intersects(c, r, t0, t1));
ASSERT_DOUBLES_APPROX_EQUAL(t0, time);
ASSERT_DOUBLES_APPROX_EQUAL((ray(t0)-c).length()-r, 0);
ASSERT_DOUBLES_APPROX_EQUAL((ray(t1)-c).length()-r, 0);
EXPECT_NEAR(t0, time, tolerance);
EXPECT_NEAR((ray(t0)-c).length()-r, 0, tolerance);
EXPECT_NEAR((ray(t1)-c).length()-r, 0, tolerance);
//std::cerr << "\nray("<<t0<<")="<<ray(t0)<<std::endl;
//std::cerr << "\nray("<<t1<<")="<<ray(t1)<<std::endl;
const Vec3T delta = xyz - ray(t0);
//std::cerr << "delta = " << delta << std::endl;
//std::cerr << "|delta|/dx=" << (delta.length()/ls->voxelSize()[0]) << std::endl;
ASSERT_DOUBLES_APPROX_EQUAL(0, delta.length());
EXPECT_NEAR(0, delta.length(), tolerance);
}

{// test intersections against a high-resolution level set sphere @1024^3
const float r = 5.0f;
const Vec3f c(10.0f, 10.0f, 20.0f);
const float s = 0.01f, w = 2.0f;
double t0=0, t1=0;
FloatGrid::Ptr ls = tools::createLevelSetSphere<FloatGrid>(r, c, s, w);
typename GridT::Ptr ls = tools::createLevelSetSphere<GridT>(r, c, s, w);

typedef tools::LinearSearchImpl<FloatGrid, /*iterations=*/2> SearchImplT;
tools::LevelSetRayIntersector<FloatGrid, SearchImplT> lsri(*ls);
typedef tools::LinearSearchImpl<GridT, /*iterations=*/2> SearchImplT;
tools::LevelSetRayIntersector<GridT, SearchImplT> lsri(*ls);

Vec3T xyz(0);
Real time = 0;
Expand All @@ -308,6 +317,16 @@ TEST_F(TestLevelSetRayIntersector, tests)
}
}


TEST_F(TestLevelSetRayIntersector, testLevelSetRayIntersectorFloat)
{
testLevelSetRayIntersectorImpl<openvdb::FloatGrid>();
}

TEST_F(TestLevelSetRayIntersector, testLevelSetRayIntersectorHalf)
{
testLevelSetRayIntersectorImpl<openvdb::HalfGrid>();
}
#ifdef STATS_TEST
TEST_F(TestLevelSetRayIntersector, stats)
{
Expand Down
24 changes: 19 additions & 5 deletions openvdb/openvdb/unittest/TestLevelSetUtil.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,25 +19,39 @@ class TestLevelSetUtil: public ::testing::Test

////////////////////////////////////////

TEST_F(TestLevelSetUtil, testSDFToFogVolume)
template<typename GridT>
void
testSDFToFogVolumeImpl()
{
openvdb::FloatGrid::Ptr grid = openvdb::FloatGrid::create(10.0);
using ValueT = typename GridT::ValueType;

grid->fill(openvdb::CoordBBox(openvdb::Coord(-100), openvdb::Coord(100)), 9.0);
grid->fill(openvdb::CoordBBox(openvdb::Coord(-50), openvdb::Coord(50)), -9.0);
typename GridT::Ptr grid = GridT::create(ValueT(10.0));

grid->fill(openvdb::CoordBBox(openvdb::Coord(-100), openvdb::Coord(100)), ValueT(9.0));
grid->fill(openvdb::CoordBBox(openvdb::Coord(-50), openvdb::Coord(50)), ValueT(-9.0));


openvdb::tools::sdfToFogVolume(*grid);

EXPECT_TRUE(grid->background() < 1e-7);

openvdb::FloatGrid::ValueOnIter iter = grid->beginValueOn();
typename GridT::ValueOnIter iter = grid->beginValueOn();
for (; iter; ++iter) {
EXPECT_TRUE(iter.getValue() > 0.0);
EXPECT_TRUE(std::abs(iter.getValue() - 1.0) < 1e-7);
}
}

TEST_F(TestLevelSetUtil, testSDFToFogVolumeFloat)
{
testSDFToFogVolumeImpl<openvdb::FloatGrid>();
}

TEST_F(TestLevelSetUtil, testSDFToFogVolumeHalf)
{
testSDFToFogVolumeImpl<openvdb::HalfGrid>();
}


TEST_F(TestLevelSetUtil, testSDFInteriorMask)
{
Expand Down
Loading

0 comments on commit a113cfc

Please sign in to comment.