Skip to content

Commit ff3de6e

Browse files
committed
Add support for temporal mesh in vtkF3DMemoryMesh and scene API
1 parent cb79173 commit ff3de6e

File tree

7 files changed

+166
-37
lines changed

7 files changed

+166
-37
lines changed

library/private/scene_impl.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ class scene_impl : public scene
3434
scene& add(const std::filesystem::path& filePath) override;
3535
scene& add(const std::vector<std::filesystem::path>& filePath) override;
3636
scene& add(const std::vector<std::string>& filePathStrings) override;
37-
scene& add(const mesh_t& mesh) override;
37+
scene& add(const mesh_t& mesh, const double timeStamp = 0) override;
3838
scene& clear() override;
3939
int addLight(const light_state_t& lightState) const override;
4040
int getLightCount() const override;

library/public/scene.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ class F3D_EXPORT scene
6060
/**
6161
* Add and load provided mesh into the scene
6262
*/
63-
virtual scene& add(const mesh_t& mesh) = 0;
63+
virtual scene& add(const mesh_t& mesh, const double timeStamp = 0) = 0;
6464

6565
///@{
6666
/**

library/src/scene_impl.cxx

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,9 @@ class scene_impl::internals
192192
animationManager AnimationManager;
193193

194194
vtkNew<vtkF3DMetaImporter> MetaImporter;
195+
vtkNew<vtkF3DMemoryMesh> VtkSource;
196+
vtkNew<vtkF3DGenericImporter> MemoryMeshImporter;
197+
bool MemoryMeshLoaded;
195198
};
196199

197200
//----------------------------------------------------------------------------
@@ -296,7 +299,7 @@ scene& scene_impl::add(const std::vector<fs::path>& filePaths)
296299
}
297300

298301
//----------------------------------------------------------------------------
299-
scene& scene_impl::add(const mesh_t& mesh)
302+
scene& scene_impl::add(const mesh_t& mesh, const double timeStamp)
300303
{
301304
// sanity checks
302305
auto [valid, err] = mesh.isValid();
@@ -305,17 +308,32 @@ scene& scene_impl::add(const mesh_t& mesh)
305308
throw scene::load_failure_exception(err);
306309
}
307310

308-
vtkNew<vtkF3DMemoryMesh> vtkSource;
309-
vtkSource->SetPoints(mesh.points);
310-
vtkSource->SetNormals(mesh.normals);
311-
vtkSource->SetTCoords(mesh.texture_coordinates);
312-
vtkSource->SetFaces(mesh.face_sides, mesh.face_indices);
313-
314-
vtkSmartPointer<vtkF3DGenericImporter> importer = vtkSmartPointer<vtkF3DGenericImporter>::New();
315-
importer->SetInternalReader(vtkSource);
311+
auto& memoryMesh = Internals->VtkSource;
312+
auto& importer = this->Internals->MemoryMeshImporter;
316313

317314
log::debug("Loading 3D scene from memory");
318-
this->Internals->Load({ importer });
315+
316+
memoryMesh->SetPoints(mesh.points, timeStamp);
317+
memoryMesh->SetNormals(mesh.normals, timeStamp);
318+
memoryMesh->SetTCoords(mesh.texture_coordinates, timeStamp);
319+
memoryMesh->SetFaces(mesh.face_sides, mesh.face_indices, timeStamp);
320+
321+
if (!this->Internals->MemoryMeshLoaded)
322+
{
323+
importer->SetInternalReader(memoryMesh);
324+
Internals->Load({ importer });
325+
this->Internals->MemoryMeshLoaded = true;
326+
}
327+
else
328+
{
329+
memoryMesh->Modified();
330+
memoryMesh->Update();
331+
332+
importer->Modified();
333+
importer->Update();
334+
this->Internals->AnimationManager.Initialize();
335+
}
336+
319337
return *this;
320338
}
321339

@@ -327,7 +345,6 @@ scene& scene_impl::clear()
327345

328346
// Clear the window of all actors
329347
this->Internals->Window.Initialize();
330-
331348
return *this;
332349
}
333350

library/testing/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ list(APPEND libf3dSDKTests_list
1010
TestSDKInteractorDropFullScene.cxx
1111
TestSDKInteractorCommand.cxx
1212
TestSDKSceneFromMemory.cxx
13+
TestSDKSceneTemporalFromMemory.cxx
1314
TestSDKScene.cxx
1415
TestSDKLog.cxx
1516
TestSDKMultiColoring.cxx
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
#include "PseudoUnitTest.h"
2+
3+
#include <engine.h>
4+
#include <image.h>
5+
#include <log.h>
6+
#include <scene.h>
7+
#include <window.h>
8+
9+
#include <cmath>
10+
#include <sstream>
11+
#include <string>
12+
#include <vector>
13+
14+
int TestSDKSceneTemporalFromMemory([[maybe_unused]] int argc, [[maybe_unused]] char* argv[])
15+
{
16+
PseudoUnitTest test;
17+
18+
f3d::log::setVerboseLevel(f3d::log::VerboseLevel::DEBUG);
19+
f3d::engine eng = f3d::engine::create(true);
20+
f3d::scene& sce = eng.getScene();
21+
f3d::window& win = eng.getWindow().setSize(300, 300);
22+
23+
std::string texturePath = std::string(argv[1]) + "data/world.png";
24+
eng.getOptions().model.color.texture = texturePath;
25+
const std::string outputPath = std::string(argv[2]);
26+
const std::string frame0Path = outputPath + "TestSDKSceneTemporalFromMemory_frame0.png";
27+
const std::string frame1Path = outputPath + "TestSDKSceneTemporalFromMemory_frame1.png";
28+
29+
const std::vector<float> basePoints{ 0.f, 0.f, 0.f, 0.f, 1.f, 0.f, 1.f, 0.f, 0.f, 1.f, 1.f, 0.f };
30+
const std::vector<float> translatedPoints{ 0.25f, 0.f, 0.f, 0.25f, 1.f, 0.f, 1.25f, 0.f, 0.f,
31+
1.25f, 1.f, 0.f };
32+
const std::vector<float> normals{ 0.f, 0.f, -1.f, 0.f, 0.f, -1.f, 0.f, 0.f, -1.f, 0.f, 0.f,
33+
-1.f };
34+
const std::vector<float> tcoords{ 0.f, 0.f, 0.f, 1.f, 1.f, 0.f, 1.f, 1.f };
35+
const std::vector<unsigned int> faceSides{ 3, 3 };
36+
const std::vector<unsigned int> faceIndices{ 0, 1, 2, 1, 3, 2 };
37+
38+
f3d::mesh_t meshFrame0{ basePoints, normals, tcoords, faceSides, faceIndices };
39+
f3d::mesh_t meshFrame1{ translatedPoints, normals, tcoords, faceSides, faceIndices };
40+
41+
test("add temporal mesh sequence", [&]() {
42+
sce.add(meshFrame0, 0.0);
43+
sce.add(meshFrame1, 1.0);
44+
});
45+
46+
test("animation time range", [&]() {
47+
auto range = sce.animationTimeRange();
48+
return std::abs(range.first - 0.0) < 1e-6 && std::abs(range.second - 1.0) < 1e-6;
49+
});
50+
51+
const std::string baselinePath = std::string(argv[1]) + "baselines/TestSDKSceneFromMemory.png";
52+
test("qualitative baseline comparison", [&]() {
53+
sce.loadAnimationTime(0.0);
54+
f3d::image frame0 = win.renderToImage();
55+
frame0.save(frame0Path);
56+
f3d::image baseline(baselinePath);
57+
double error = frame0.compare(baseline);
58+
if (error > 0.05)
59+
{
60+
std::ostringstream stream;
61+
stream << "baseline difference is " << error;
62+
throw stream.str();
63+
}
64+
});
65+
66+
test("quantitative temporal difference", [&]() {
67+
sce.loadAnimationTime(0.0);
68+
f3d::image frame0 = win.renderToImage();
69+
frame0.save(frame0Path);
70+
sce.loadAnimationTime(1.0);
71+
f3d::image frame1 = win.renderToImage();
72+
frame1.save(frame1Path);
73+
double error = frame0.compare(frame1);
74+
if (error <= 0.01)
75+
{
76+
std::ostringstream stream;
77+
stream << "frame delta is " << error;
78+
throw stream.str();
79+
}
80+
});
81+
82+
return test.result();
83+
}

vtkext/private/module/vtkF3DMemoryMesh.cxx

Lines changed: 41 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
#include "vtkF3DMemoryMesh.h"
22

3-
#include "vtkDataArrayRange.h"
43
#include "vtkFloatArray.h"
54
#include "vtkIdTypeArray.h"
65
#include "vtkInformationVector.h"
76
#include "vtkObjectFactory.h"
87
#include "vtkPointData.h"
98
#include "vtkSMPTools.h"
10-
11-
#include <numeric>
9+
#include <vtkInformation.h>
10+
#include <vtkStreamingDemandDrivenPipeline.h>
1211

1312
vtkStandardNewMacro(vtkF3DMemoryMesh);
1413

@@ -46,30 +45,30 @@ vtkF3DMemoryMesh::vtkF3DMemoryMesh()
4645
vtkF3DMemoryMesh::~vtkF3DMemoryMesh() = default;
4746

4847
//------------------------------------------------------------------------------
49-
void vtkF3DMemoryMesh::SetPoints(const std::vector<float>& positions)
48+
void vtkF3DMemoryMesh::SetPoints(const std::vector<float>& positions, const double timeStamp)
5049
{
5150
vtkNew<vtkPoints> points;
5251
points->SetDataTypeToFloat();
5352
points->SetData(ConvertToFloatArray<3>(positions));
5453

55-
this->Mesh->SetPoints(points);
54+
this->Meshes[timeStamp]->SetPoints(points);
5655
}
5756

5857
//------------------------------------------------------------------------------
59-
void vtkF3DMemoryMesh::SetNormals(const std::vector<float>& normals)
58+
void vtkF3DMemoryMesh::SetNormals(const std::vector<float>& normals, const double timeStamp)
6059
{
61-
this->Mesh->GetPointData()->SetNormals(ConvertToFloatArray<3>(normals));
60+
this->Meshes[timeStamp]->GetPointData()->SetNormals(ConvertToFloatArray<3>(normals));
6261
}
6362

6463
//------------------------------------------------------------------------------
65-
void vtkF3DMemoryMesh::SetTCoords(const std::vector<float>& tcoords)
64+
void vtkF3DMemoryMesh::SetTCoords(const std::vector<float>& tcoords, const double timeStamp)
6665
{
67-
this->Mesh->GetPointData()->SetTCoords(ConvertToFloatArray<2>(tcoords));
66+
this->Meshes[timeStamp]->GetPointData()->SetTCoords(ConvertToFloatArray<2>(tcoords));
6867
}
6968

7069
//------------------------------------------------------------------------------
71-
void vtkF3DMemoryMesh::SetFaces(
72-
const std::vector<unsigned int>& faceSizes, const std::vector<unsigned int>& faceIndices)
70+
void vtkF3DMemoryMesh::SetFaces(const std::vector<unsigned int>& faceSizes,
71+
const std::vector<unsigned int>& faceIndices, const double timeStamp)
7372
{
7473
vtkNew<vtkIdTypeArray> offsets;
7574
vtkNew<vtkIdTypeArray> connectivity;
@@ -97,16 +96,44 @@ void vtkF3DMemoryMesh::SetFaces(
9796
vtkNew<vtkCellArray> polys;
9897
polys->SetData(offsets, connectivity);
9998

100-
this->Mesh->SetPolys(polys);
99+
this->Meshes[timeStamp]->SetPolys(polys);
100+
}
101+
102+
//------------------------------------------------------------------------------
103+
int vtkF3DMemoryMesh::RequestInformation(vtkInformation* vtkNotUsed(request),
104+
vtkInformationVector** vtkNotUsed(inputVector), vtkInformationVector* outputVector)
105+
{
106+
// timeRange = {map_min, map_max}, map_min always <= map_max
107+
const auto timeRange = std::array<double, 2>{ Meshes.begin()->first, Meshes.rbegin()->first };
108+
109+
vtkInformation* outInfo = outputVector->GetInformationObject(0);
110+
outInfo->Set(vtkStreamingDemandDrivenPipeline::TIME_RANGE(), timeRange.data(), 2);
111+
112+
return 1;
101113
}
102114

103115
//------------------------------------------------------------------------------
104116
int vtkF3DMemoryMesh::RequestData(vtkInformation* vtkNotUsed(request),
105117
vtkInformationVector** vtkNotUsed(inputVector), vtkInformationVector* outputVector)
106118
{
107-
vtkPolyData* output = vtkPolyData::GetData(outputVector->GetInformationObject(0));
119+
vtkInformation* outInfo = outputVector->GetInformationObject(0);
120+
vtkPolyData* output = vtkPolyData::GetData(outInfo);
108121

109-
output->ShallowCopy(this->Mesh);
122+
if (outInfo->Has(vtkStreamingDemandDrivenPipeline::UPDATE_TIME_STEP()) && !this->Meshes.empty())
123+
{
124+
const double requestedTimeValue =
125+
outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_TIME_STEP());
126+
auto iter = Meshes.upper_bound(requestedTimeValue);
127+
if (iter != Meshes.begin())
128+
{
129+
iter = std::prev(iter);
130+
}
131+
output->ShallowCopy(iter->second);
132+
}
133+
else
134+
{
135+
output->ShallowCopy(this->Meshes[0.0]);
136+
}
110137

111138
return 1;
112139
}

vtkext/private/module/vtkF3DMemoryMesh.h

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,52 +18,53 @@ class vtkF3DMemoryMesh : public vtkPolyDataAlgorithm
1818
vtkTypeMacro(vtkF3DMemoryMesh, vtkPolyDataAlgorithm);
1919

2020
/**
21-
* Set contiguous list of positions.
21+
* Set contiguous list of positions for a given timestamp, 0 by default.
2222
* Length of the list must be a multiple of 3.
2323
* The list is copied internally.
2424
*/
25-
void SetPoints(const std::vector<float>& positions);
25+
void SetPoints(const std::vector<float>& positions, const double timeStamp = 0);
2626

2727
/**
28-
* Set contiguous list of normals.
28+
* Set contiguous list of normals for a given timestamp, 0 by default.
2929
* Length of the list must be a multiple of 3 (or left empty).
3030
* Must match the number of points specified in SetPoints.
3131
* The list is copied internally.
3232
* The list can be empty.
3333
*/
34-
void SetNormals(const std::vector<float>& normals);
34+
void SetNormals(const std::vector<float>& normals, const double timeStamp = 0);
3535

3636
/**
37-
* Set contiguous list of texture coordinates.
37+
* Set contiguous list of texture coordinates for a given timestamp, 0 by default.
3838
* Length of the list must be a multiple of 2 (or left empty).
3939
* Must match the number of points specified in SetPoints.
4040
* The list is copied internally.
4141
* The list can be empty.
4242
*/
43-
void SetTCoords(const std::vector<float>& tcoords);
43+
void SetTCoords(const std::vector<float>& tcoords, const double timeStamp = 0);
4444

4545
/**
46-
* Set faces by vertex indices.
46+
* Set faces by vertex indices for a given timestamp, 0 by default.
4747
* faceSizes contains the size of each face (3 is triangle, 4 is quad, etc...)
4848
* cellIndices is a contiguous array of all face indices
4949
* The length of faceIndices should be the sum of all values in faceSizes
5050
* The lists are copied internally.
5151
* The lists can be empty, resulting in a point cloud.
5252
*/
53-
void SetFaces(
54-
const std::vector<unsigned int>& faceSizes, const std::vector<unsigned int>& faceIndices);
53+
void SetFaces(const std::vector<unsigned int>& faceSizes,
54+
const std::vector<unsigned int>& faceIndices, const double timeStamp = 0);
5555

5656
protected:
5757
vtkF3DMemoryMesh();
5858
~vtkF3DMemoryMesh() override;
5959

60+
int RequestInformation(vtkInformation*, vtkInformationVector**, vtkInformationVector*) override;
6061
int RequestData(vtkInformation*, vtkInformationVector**, vtkInformationVector*) override;
6162

6263
private:
6364
vtkF3DMemoryMesh(const vtkF3DMemoryMesh&) = delete;
6465
void operator=(const vtkF3DMemoryMesh&) = delete;
6566

66-
vtkNew<vtkPolyData> Mesh;
67+
std::map<double, vtkNew<vtkPolyData>> Meshes;
6768
};
6869

6970
#endif

0 commit comments

Comments
 (0)