Options to compute fast normals in MarchingCubes
Adds ComputeFastNormalsForStructured and ComputeFastNormalsForUnstructured flags to the marching cubes filter.
This commit is contained in:
parent
74f1a0bf8b
commit
08fb95d5ee
@ -68,12 +68,36 @@ public:
|
|||||||
VTKM_CONT
|
VTKM_CONT
|
||||||
bool GetMergeDuplicatePoints() const { return this->Worklet.GetMergeDuplicatePoints(); }
|
bool GetMergeDuplicatePoints() const { return this->Worklet.GetMergeDuplicatePoints(); }
|
||||||
|
|
||||||
|
/// Set/Get whether normals should be generated. Off by default. If enabled,
|
||||||
|
/// the default behaviour is to generate high quality normals for structured
|
||||||
|
/// datasets, using gradients, and generate fast normals for unstructured
|
||||||
|
/// datasets based on the result triangle mesh.
|
||||||
|
///
|
||||||
VTKM_CONT
|
VTKM_CONT
|
||||||
void SetGenerateNormals(bool on) { this->GenerateNormals = on; }
|
void SetGenerateNormals(bool on) { this->GenerateNormals = on; }
|
||||||
|
|
||||||
VTKM_CONT
|
VTKM_CONT
|
||||||
bool GetGenerateNormals() const { return this->GenerateNormals; }
|
bool GetGenerateNormals() const { return this->GenerateNormals; }
|
||||||
|
|
||||||
|
/// Set/Get whether the fast path should be used for normals computation for
|
||||||
|
/// structured datasets. Off by default.
|
||||||
|
VTKM_CONT
|
||||||
|
void SetComputeFastNormalsForStructured(bool on) { this->ComputeFastNormalsForStructured = on; }
|
||||||
|
VTKM_CONT
|
||||||
|
bool GetComputeFastNormalsForStructured() const { return this->ComputeFastNormalsForStructured; }
|
||||||
|
|
||||||
|
/// Set/Get whether the fast path should be used for normals computation for
|
||||||
|
/// unstructured datasets. On by default.
|
||||||
|
VTKM_CONT
|
||||||
|
void SetComputeFastNormalsForUnstructured(bool on)
|
||||||
|
{
|
||||||
|
this->ComputeFastNormalsForUnstructured = on;
|
||||||
|
}
|
||||||
|
VTKM_CONT
|
||||||
|
bool GetComputeFastNormalsForUnstructured() const
|
||||||
|
{
|
||||||
|
return this->ComputeFastNormalsForUnstructured;
|
||||||
|
}
|
||||||
|
|
||||||
VTKM_CONT
|
VTKM_CONT
|
||||||
void SetNormalArrayName(const std::string& name) { this->NormalArrayName = name; }
|
void SetNormalArrayName(const std::string& name) { this->NormalArrayName = name; }
|
||||||
|
|
||||||
@ -100,6 +124,8 @@ public:
|
|||||||
private:
|
private:
|
||||||
std::vector<vtkm::Float64> IsoValues;
|
std::vector<vtkm::Float64> IsoValues;
|
||||||
bool GenerateNormals;
|
bool GenerateNormals;
|
||||||
|
bool ComputeFastNormalsForStructured;
|
||||||
|
bool ComputeFastNormalsForUnstructured;
|
||||||
std::string NormalArrayName;
|
std::string NormalArrayName;
|
||||||
vtkm::worklet::MarchingCubes Worklet;
|
vtkm::worklet::MarchingCubes Worklet;
|
||||||
};
|
};
|
||||||
|
@ -20,22 +20,42 @@
|
|||||||
|
|
||||||
#include <vtkm/cont/ArrayHandleIndex.h>
|
#include <vtkm/cont/ArrayHandleIndex.h>
|
||||||
#include <vtkm/cont/CellSetSingleType.h>
|
#include <vtkm/cont/CellSetSingleType.h>
|
||||||
|
#include <vtkm/cont/CellSetStructured.h>
|
||||||
#include <vtkm/cont/DynamicArrayHandle.h>
|
#include <vtkm/cont/DynamicArrayHandle.h>
|
||||||
#include <vtkm/cont/DynamicCellSet.h>
|
#include <vtkm/cont/DynamicCellSet.h>
|
||||||
|
|
||||||
#include <vtkm/worklet/DispatcherMapTopology.h>
|
#include <vtkm/worklet/DispatcherMapTopology.h>
|
||||||
#include <vtkm/worklet/ScatterCounting.h>
|
#include <vtkm/worklet/ScatterCounting.h>
|
||||||
|
#include <vtkm/worklet/SurfaceNormals.h>
|
||||||
|
|
||||||
namespace vtkm
|
namespace vtkm
|
||||||
{
|
{
|
||||||
namespace filter
|
namespace filter
|
||||||
{
|
{
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
|
template <typename CellSetList>
|
||||||
|
bool IsCellSetStructured(const vtkm::cont::DynamicCellSetBase<CellSetList>& cellset)
|
||||||
|
{
|
||||||
|
if (cellset.template IsType<vtkm::cont::CellSetStructured<1>>() ||
|
||||||
|
cellset.template IsType<vtkm::cont::CellSetStructured<2>>() ||
|
||||||
|
cellset.template IsType<vtkm::cont::CellSetStructured<3>>())
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} // anonymous namespace
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
inline VTKM_CONT MarchingCubes::MarchingCubes()
|
inline VTKM_CONT MarchingCubes::MarchingCubes()
|
||||||
: vtkm::filter::FilterDataSetWithField<MarchingCubes>()
|
: vtkm::filter::FilterDataSetWithField<MarchingCubes>()
|
||||||
, IsoValues()
|
, IsoValues()
|
||||||
, GenerateNormals(false)
|
, GenerateNormals(false)
|
||||||
|
, ComputeFastNormalsForStructured(false)
|
||||||
|
, ComputeFastNormalsForUnstructured(true)
|
||||||
, NormalArrayName("normals")
|
, NormalArrayName("normals")
|
||||||
, Worklet()
|
, Worklet()
|
||||||
{
|
{
|
||||||
@ -138,7 +158,11 @@ inline VTKM_CONT vtkm::filter::ResultDataSet MarchingCubes::DoExecute(
|
|||||||
//worklet with the design
|
//worklet with the design
|
||||||
//But I think we should get this to compile before we tinker with
|
//But I think we should get this to compile before we tinker with
|
||||||
//a more efficient api
|
//a more efficient api
|
||||||
if (this->GenerateNormals)
|
|
||||||
|
bool generateHighQualityNormals = IsCellSetStructured(cells)
|
||||||
|
? !this->ComputeFastNormalsForStructured
|
||||||
|
: !this->ComputeFastNormalsForUnstructured;
|
||||||
|
if (this->GenerateNormals && generateHighQualityNormals)
|
||||||
{
|
{
|
||||||
outputCells = this->Worklet.Run(&ivalues[0],
|
outputCells = this->Worklet.Run(&ivalues[0],
|
||||||
static_cast<vtkm::Id>(ivalues.size()),
|
static_cast<vtkm::Id>(ivalues.size()),
|
||||||
@ -162,6 +186,16 @@ inline VTKM_CONT vtkm::filter::ResultDataSet MarchingCubes::DoExecute(
|
|||||||
|
|
||||||
if (this->GenerateNormals)
|
if (this->GenerateNormals)
|
||||||
{
|
{
|
||||||
|
if (!generateHighQualityNormals)
|
||||||
|
{
|
||||||
|
Vec3HandleType faceNormals;
|
||||||
|
vtkm::worklet::FacetedSurfaceNormals faceted;
|
||||||
|
faceted.Run(outputCells, vertices, faceNormals, device);
|
||||||
|
|
||||||
|
vtkm::worklet::SmoothSurfaceNormals smooth;
|
||||||
|
smooth.Run(outputCells, faceNormals, normals, device);
|
||||||
|
}
|
||||||
|
|
||||||
vtkm::cont::Field normalField(this->NormalArrayName, vtkm::cont::Field::ASSOC_POINTS, normals);
|
vtkm::cont::Field normalField(this->NormalArrayName, vtkm::cont::Field::ASSOC_POINTS, normals);
|
||||||
output.AddField(normalField);
|
output.AddField(normalField);
|
||||||
}
|
}
|
||||||
|
@ -22,8 +22,11 @@
|
|||||||
#include <vtkm/cont/ArrayHandleUniformPointCoordinates.h>
|
#include <vtkm/cont/ArrayHandleUniformPointCoordinates.h>
|
||||||
#include <vtkm/cont/CellSetSingleType.h>
|
#include <vtkm/cont/CellSetSingleType.h>
|
||||||
#include <vtkm/cont/DataSet.h>
|
#include <vtkm/cont/DataSet.h>
|
||||||
|
#include <vtkm/cont/DataSetBuilderUniform.h>
|
||||||
|
#include <vtkm/cont/DataSetFieldAdd.h>
|
||||||
#include <vtkm/cont/DynamicArrayHandle.h>
|
#include <vtkm/cont/DynamicArrayHandle.h>
|
||||||
#include <vtkm/cont/testing/Testing.h>
|
#include <vtkm/cont/testing/Testing.h>
|
||||||
|
#include <vtkm/filter/CleanGrid.h>
|
||||||
|
|
||||||
#include <vtkm/filter/MarchingCubes.h>
|
#include <vtkm/filter/MarchingCubes.h>
|
||||||
|
|
||||||
@ -398,10 +401,119 @@ void TestMarchingCubesCustomPolicy()
|
|||||||
"Should have some coordinates");
|
"Should have some coordinates");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
vtkm::cont::DataSet MakeNormalsTestDataSet()
|
||||||
|
{
|
||||||
|
vtkm::cont::DataSetBuilderUniform dsb;
|
||||||
|
vtkm::Id3 dimensions(3, 4, 4);
|
||||||
|
vtkm::cont::DataSet dataSet = dsb.Create(dimensions);
|
||||||
|
|
||||||
|
vtkm::cont::DataSetFieldAdd dsf;
|
||||||
|
const int nVerts = 48;
|
||||||
|
vtkm::Float32 vars[nVerts] = { 60.764f, 107.555f, 80.524f, 63.639f, 131.087f, 83.4f,
|
||||||
|
98.161f, 165.608f, 117.921f, 37.353f, 84.145f, 57.114f,
|
||||||
|
95.202f, 162.649f, 114.962f, 115.896f, 215.56f, 135.657f,
|
||||||
|
150.418f, 250.081f, 170.178f, 71.791f, 139.239f, 91.552f,
|
||||||
|
95.202f, 162.649f, 114.962f, 115.896f, 215.56f, 135.657f,
|
||||||
|
150.418f, 250.081f, 170.178f, 71.791f, 139.239f, 91.552f,
|
||||||
|
60.764f, 107.555f, 80.524f, 63.639f, 131.087f, 83.4f,
|
||||||
|
98.161f, 165.608f, 117.921f, 37.353f, 84.145f, 57.114f };
|
||||||
|
|
||||||
|
//Set point and cell scalar
|
||||||
|
dsf.AddPointField(dataSet, "pointvar", vars, nVerts);
|
||||||
|
|
||||||
|
return dataSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestNormals(const vtkm::cont::DataSet& dataset, bool structured)
|
||||||
|
{
|
||||||
|
const vtkm::Id numVerts = 16;
|
||||||
|
|
||||||
|
const vtkm::Vec<vtkm::FloatDefault, 3> hq[numVerts] = {
|
||||||
|
{ 0.1510f, 0.6268f, 0.7644f }, { 0.1333f, -0.3974f, 0.9079f },
|
||||||
|
{ 0.1626f, 0.7642f, 0.6242f }, { 0.3853f, 0.6643f, 0.6405f },
|
||||||
|
{ -0.1337f, 0.7136f, 0.6876f }, { 0.7705f, -0.4212f, 0.4784f },
|
||||||
|
{ -0.7360f, -0.4452f, 0.5099f }, { 0.1234f, -0.8871f, 0.4448f },
|
||||||
|
{ 0.1626f, 0.7642f, -0.6242f }, { 0.3853f, 0.6643f, -0.6405f },
|
||||||
|
{ -0.1337f, 0.7136f, -0.6876f }, { 0.1510f, 0.6268f, -0.7644f },
|
||||||
|
{ 0.7705f, -0.4212f, -0.4784f }, { -0.7360f, -0.4452f, -0.5099f },
|
||||||
|
{ 0.1234f, -0.8871f, -0.4448f }, { 0.1333f, -0.3974f, -0.9079f }
|
||||||
|
};
|
||||||
|
|
||||||
|
const vtkm::Vec<vtkm::FloatDefault, 3> fast[numVerts] = {
|
||||||
|
{ -0.1351f, 0.4377f, 0.8889f }, { 0.2863f, -0.1721f, 0.9426f },
|
||||||
|
{ 0.3629f, 0.8155f, 0.4509f }, { 0.8486f, 0.3560f, 0.3914f },
|
||||||
|
{ -0.8315f, 0.4727f, 0.2917f }, { 0.9395f, -0.2530f, 0.2311f },
|
||||||
|
{ -0.9105f, -0.0298f, 0.4124f }, { -0.1078f, -0.9585f, 0.2637f },
|
||||||
|
{ -0.2538f, 0.8534f, -0.4553f }, { 0.8953f, 0.3902f, -0.2149f },
|
||||||
|
{ -0.8295f, 0.4188f, -0.3694f }, { 0.2434f, 0.4297f, -0.8695f },
|
||||||
|
{ 0.8951f, -0.1347f, -0.4251f }, { -0.8467f, -0.4258f, -0.3191f },
|
||||||
|
{ 0.2164f, -0.9401f, -0.2635f }, { -0.1589f, -0.1642f, -0.9735f }
|
||||||
|
};
|
||||||
|
|
||||||
|
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::FloatDefault, 3>> normals;
|
||||||
|
|
||||||
|
vtkm::filter::MarchingCubes mc;
|
||||||
|
mc.SetIsoValue(0, 200);
|
||||||
|
mc.SetGenerateNormals(true);
|
||||||
|
|
||||||
|
// Test default normals generation: high quality for structured, fast for unstructured.
|
||||||
|
auto expected = structured ? hq : fast;
|
||||||
|
|
||||||
|
auto result = mc.Execute(dataset, dataset.GetField("pointvar"));
|
||||||
|
result.GetDataSet().GetField("normals").GetData().CopyTo(normals);
|
||||||
|
VTKM_TEST_ASSERT(normals.GetNumberOfValues() == numVerts,
|
||||||
|
"Wrong number of values in normals field");
|
||||||
|
for (vtkm::Id i = 0; i < numVerts; ++i)
|
||||||
|
{
|
||||||
|
VTKM_TEST_ASSERT(test_equal(normals.GetPortalConstControl().Get(i), expected[i], 0.001),
|
||||||
|
"Result does not match expected values");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test the other normals generation method
|
||||||
|
if (structured)
|
||||||
|
{
|
||||||
|
mc.SetComputeFastNormalsForStructured(true);
|
||||||
|
expected = fast;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mc.SetComputeFastNormalsForUnstructured(false);
|
||||||
|
expected = hq;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = mc.Execute(dataset, dataset.GetField("pointvar"));
|
||||||
|
result.GetDataSet().GetField("normals").GetData().CopyTo(normals);
|
||||||
|
VTKM_TEST_ASSERT(normals.GetNumberOfValues() == numVerts,
|
||||||
|
"Wrong number of values in normals field");
|
||||||
|
for (vtkm::Id i = 0; i < numVerts; ++i)
|
||||||
|
{
|
||||||
|
VTKM_TEST_ASSERT(test_equal(normals.GetPortalConstControl().Get(i), expected[i], 0.001),
|
||||||
|
"Result does not match expected values");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestMarchingCubesNormals()
|
||||||
|
{
|
||||||
|
std::cout << "Testing MarchingCubes normals generation" << std::endl;
|
||||||
|
|
||||||
|
std::cout << "\tStructured dataset\n";
|
||||||
|
vtkm::cont::DataSet dataset = MakeNormalsTestDataSet();
|
||||||
|
TestNormals(dataset, true);
|
||||||
|
|
||||||
|
std::cout << "\tUnstructured dataset\n";
|
||||||
|
vtkm::filter::CleanGrid makeUnstructured;
|
||||||
|
makeUnstructured.SetCompactPointFields(false);
|
||||||
|
auto result = makeUnstructured.Execute(dataset);
|
||||||
|
makeUnstructured.MapFieldOntoOutput(result, dataset.GetField("pointvar"));
|
||||||
|
TestNormals(result.GetDataSet(), false);
|
||||||
|
}
|
||||||
|
|
||||||
void TestMarchingCubesFilter()
|
void TestMarchingCubesFilter()
|
||||||
{
|
{
|
||||||
TestMarchingCubesUniformGrid();
|
TestMarchingCubesUniformGrid();
|
||||||
TestMarchingCubesCustomPolicy();
|
TestMarchingCubesCustomPolicy();
|
||||||
|
TestMarchingCubesNormals();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
Loading…
Reference in New Issue
Block a user