1 #include "vtkF3DGenericImporter.h"
2
3 #include "F3DLog.h"
4 #include "F3DOptions.h"
5
6 #include <vtkActor.h>
7 #include <vtkAppendPolyData.h>
8 #include <vtkBoundingBox.h>
9 #include <vtkCellData.h>
10 #include <vtkDataObjectTreeIterator.h>
11 #include <vtkDataSetSurfaceFilter.h>
12 #include <vtkDoubleArray.h>
13 #include <vtkEventForwarderCommand.h>
14 #include <vtkImageData.h>
15 #include <vtkImageReader2.h>
16 #include <vtkImageReader2Factory.h>
17 #include <vtkImageToPoints.h>
18 #include <vtkInformation.h>
19 #include <vtkLightKit.h>
20 #include <vtkMultiBlockDataSet.h>
21 #include <vtkObjectFactory.h>
22 #include <vtkPiecewiseFunction.h>
23 #include <vtkPointData.h>
24 #include <vtkPointGaussianMapper.h>
25 #include <vtkPolyDataMapper.h>
26 #include <vtkProperty.h>
27 #include <vtkRectilinearGrid.h>
28 #include <vtkRectilinearGridToPointSet.h>
29 #include <vtkRenderer.h>
30 #include <vtkScalarBarActor.h>
31 #include <vtkScalarsToColors.h>
32 #include <vtkSmartPointer.h>
33 #include <vtkSmartVolumeMapper.h>
34 #include <vtkStreamingDemandDrivenPipeline.h>
35 #include <vtkTexture.h>
36 #include <vtkVertexGlyphFilter.h>
37 #include <vtkVolumeProperty.h>
38 #include <vtksys/SystemTools.hxx>
39
40 #include "vtkF3DPostProcessFilter.h"
41
42 vtkStandardNewMacro(vtkF3DGenericImporter);
43
44 //----------------------------------------------------------------------------
UpdateTemporalInformation()45 void vtkF3DGenericImporter::UpdateTemporalInformation()
46 {
47 if (!this->TemporalInformationUpdated)
48 {
49 if (!this->Reader->IsReaderValid())
50 {
51 F3DLog::Print(F3DLog::Severity::Info, "Reader is not valid");
52 return;
53 }
54 this->Reader->UpdateInformation();
55 vtkInformation* readerInfo = this->Reader->GetOutputInformation(0);
56
57 this->NbTimeSteps = readerInfo->Length(vtkStreamingDemandDrivenPipeline::TIME_STEPS());
58 this->TimeRange = readerInfo->Get(vtkStreamingDemandDrivenPipeline::TIME_RANGE());
59 this->TimeSteps = readerInfo->Get(vtkStreamingDemandDrivenPipeline::TIME_STEPS());
60 this->TemporalInformationUpdated = true;
61 }
62 }
63
64 //----------------------------------------------------------------------------
GetNumberOfAnimations()65 vtkIdType vtkF3DGenericImporter::GetNumberOfAnimations()
66 {
67 this->UpdateTemporalInformation();
68 return this->NbTimeSteps > 0 ? 1 : 0;
69 }
70
71 //----------------------------------------------------------------------------
GetAnimationName(vtkIdType animationIndex)72 std::string vtkF3DGenericImporter::GetAnimationName(vtkIdType animationIndex)
73 {
74 return animationIndex < this->GetNumberOfAnimations() ? "default" : "";
75 }
76
77 //----------------------------------------------------------------------------
EnableAnimation(vtkIdType animationIndex)78 void vtkF3DGenericImporter::EnableAnimation(vtkIdType animationIndex)
79 {
80 if (animationIndex < this->GetNumberOfAnimations())
81 {
82 this->AnimationEnabled = true;
83 }
84 }
85
86 //----------------------------------------------------------------------------
DisableAnimation(vtkIdType animationIndex)87 void vtkF3DGenericImporter::DisableAnimation(vtkIdType animationIndex)
88 {
89 if (animationIndex < this->GetNumberOfAnimations())
90 {
91 this->AnimationEnabled = false;
92 }
93 }
94
95 //----------------------------------------------------------------------------
IsAnimationEnabled(vtkIdType animationIndex)96 bool vtkF3DGenericImporter::IsAnimationEnabled(vtkIdType animationIndex)
97 {
98 return animationIndex < this->GetNumberOfAnimations() ? this->AnimationEnabled : false;
99 }
100
101 //----------------------------------------------------------------------------
102 #if VTK_VERSION_NUMBER >= VTK_VERSION_CHECK(9, 0, 20201016)
GetTemporalInformation(vtkIdType animationIndex,double vtkNotUsed (frameRate),int & nbTimeSteps,double timeRange[2],vtkDoubleArray * timeSteps)103 bool vtkF3DGenericImporter::GetTemporalInformation(vtkIdType animationIndex,
104 double vtkNotUsed(frameRate), int& nbTimeSteps, double timeRange[2], vtkDoubleArray* timeSteps)
105 #else
106 bool vtkF3DGenericImporter::GetTemporalInformation(vtkIdType animationIndex,
107 int& nbTimeSteps, double timeRange[2], vtkDoubleArray* timeSteps)
108 #endif
109 {
110 if (animationIndex < this->GetNumberOfAnimations())
111 {
112 nbTimeSteps = this->NbTimeSteps;
113 timeRange[0] = this->TimeRange[0];
114 timeRange[1] = this->TimeRange[1];
115 timeSteps->SetArray(this->TimeSteps, this->NbTimeSteps, 1);
116 return true;
117 }
118 return false;
119 }
120
121 //----------------------------------------------------------------------------
ImportActors(vtkRenderer * ren)122 void vtkF3DGenericImporter::ImportActors(vtkRenderer* ren)
123 {
124 if (!this->Reader->IsReaderValid())
125 {
126 F3DLog::Print(
127 F3DLog::Severity::Error, "File '", this->Reader->GetFileName(), "' cannot be read.");
128 return;
129 }
130
131 // forward progress event
132 vtkNew<vtkEventForwarderCommand> forwarder;
133 forwarder->SetTarget(this);
134 this->Reader->AddObserver(vtkCommand::ProgressEvent, forwarder);
135
136 this->PostPro->SetInputConnection(this->Reader->GetOutputPort());
137 bool ret = this->PostPro->GetExecutive()->Update();
138
139 if (!ret)
140 {
141 F3DLog::Print(
142 F3DLog::Severity::Error, "File '", this->Reader->GetFileName(), "' cannot be read.");
143 return;
144 }
145
146 bool print = (this->Options->Verbose || this->Options->NoRender);
147 if (print)
148 {
149 this->OutputDescription =
150 vtkF3DGenericImporter::GetDataObjectDescription(this->Reader->GetOutput());
151 }
152
153 if (this->Options->NoRender)
154 {
155 return;
156 }
157
158 vtkPolyData* surface = vtkPolyData::SafeDownCast(this->PostPro->GetOutput());
159 vtkImageData* image = vtkImageData::SafeDownCast(this->PostPro->GetOutput(2));
160
161 // Configure volume mapper
162 this->VolumeMapper->SetInputConnection(this->PostPro->GetOutputPort(2));
163 this->VolumeMapper->SetRequestedRenderModeToGPU();
164
165 // Configure polydata mapper
166 this->PolyDataMapper->InterpolateScalarsBeforeMappingOn();
167 this->PolyDataMapper->SetInputConnection(this->PostPro->GetOutputPort(0));
168
169 // Configure Point Gaussian mapper
170 double bounds[6];
171 surface->GetBounds(bounds);
172 vtkBoundingBox bbox(bounds);
173
174 double pointSize = 1.0;
175 if (bbox.IsValid())
176 {
177 pointSize = this->Options->PointSize * bbox.GetDiagonalLength() * 0.001;
178 }
179 this->PointGaussianMapper->SetInputConnection(this->PostPro->GetOutputPort(1));
180 this->PointGaussianMapper->SetScaleFactor(pointSize);
181 this->PointGaussianMapper->EmissiveOff();
182 this->PointGaussianMapper->SetSplatShaderCode(
183 "//VTK::Color::Impl\n"
184 "float dist = dot(offsetVCVSOutput.xy, offsetVCVSOutput.xy);\n"
185 "if (dist > 1.0) {\n"
186 " discard;\n"
187 "} else {\n"
188 " float scale = (1.0 - dist);\n"
189 " ambientColor *= scale;\n"
190 " diffuseColor *= scale;\n"
191 "}\n");
192
193 //
194 vtkDataSet* dataSet = vtkImageData::SafeDownCast(this->PostPro->GetInput())
195 ? vtkDataSet::SafeDownCast(image)
196 : vtkDataSet::SafeDownCast(surface);
197
198 std::string usedArray = this->Options->Scalars;
199 this->PointDataForColoring = vtkDataSetAttributes::SafeDownCast(dataSet->GetPointData());
200 this->CellDataForColoring = vtkDataSetAttributes::SafeDownCast(dataSet->GetCellData());
201 vtkDataSetAttributes* dataForColoring =
202 this->Options->Cells ? this->CellDataForColoring : this->PointDataForColoring;
203
204 // Recover an array for coloring if we ever need it
205 this->ArrayIndexForColoring = -1;
206 if (usedArray.empty())
207 {
208 vtkDataArray* array = dataForColoring->GetScalars();
209 if (array)
210 {
211 const char* arrayName = array->GetName();
212 if (arrayName)
213 {
214 usedArray = arrayName;
215 }
216 if (print)
217 {
218 F3DLog::Print(F3DLog::Severity::Info, "Using default scalar array: ", usedArray);
219 }
220 }
221 else
222 {
223 for (int i = 0; i < dataForColoring->GetNumberOfArrays(); i++)
224 {
225 array = dataForColoring->GetArray(i);
226 if (array)
227 {
228 this->ArrayIndexForColoring = i;
229 const char* arrayName = array->GetName();
230 if (arrayName)
231 {
232 usedArray = arrayName;
233 }
234 if (print)
235 {
236 F3DLog::Print(F3DLog::Severity::Info, "Using first found array: ", usedArray);
237 }
238 break;
239 }
240 }
241 }
242 }
243 if (this->ArrayIndexForColoring == -1)
244 {
245 dataForColoring->GetArray(usedArray.c_str(), this->ArrayIndexForColoring);
246 }
247 if (this->ArrayIndexForColoring == -1 && !usedArray.empty() &&
248 usedArray != f3d::F3DReservedString)
249 {
250 F3DLog::Print(F3DLog::Severity::Warning, "Unknown scalar array: ", usedArray);
251 }
252 if (this->ArrayIndexForColoring == -1 && print)
253 {
254 F3DLog::Print(
255 F3DLog::Severity::Info, "No array found for scalar coloring and volume rendering");
256 }
257
258 // configure props
259 this->VolumeProp->SetMapper(this->VolumeMapper);
260
261 this->GeometryActor->SetMapper(this->PolyDataMapper);
262 this->GeometryActor->GetProperty()->SetInterpolationToPBR();
263
264 double col[3];
265 std::copy(this->Options->SolidColor.begin(), this->Options->SolidColor.end(), col);
266
267 this->GeometryActor->GetProperty()->SetColor(col);
268 this->GeometryActor->GetProperty()->SetOpacity(this->Options->Opacity);
269 this->GeometryActor->GetProperty()->SetRoughness(this->Options->Roughness);
270 this->GeometryActor->GetProperty()->SetMetallic(this->Options->Metallic);
271 this->GeometryActor->GetProperty()->SetPointSize(this->Options->PointSize);
272 this->GeometryActor->GetProperty()->SetLineWidth(this->Options->LineWidth);
273
274 this->PointSpritesActor->SetMapper(this->PointGaussianMapper);
275 this->PointSpritesActor->GetProperty()->SetColor(col);
276 this->PointSpritesActor->GetProperty()->SetOpacity(this->Options->Opacity);
277
278 // Textures
279 this->GeometryActor->GetProperty()->SetBaseColorTexture(
280 this->GetTexture(this->Options->BaseColorTex, true));
281 this->GeometryActor->GetProperty()->SetORMTexture(this->GetTexture(this->Options->ORMTex));
282 this->GeometryActor->GetProperty()->SetEmissiveTexture(
283 this->GetTexture(this->Options->EmissiveTex, true));
284 this->GeometryActor->GetProperty()->SetEmissiveFactor(this->Options->EmissiveFactor.data());
285 this->GeometryActor->GetProperty()->SetNormalTexture(this->GetTexture(this->Options->NormalTex));
286 this->GeometryActor->GetProperty()->SetNormalScale(this->Options->NormalScale);
287
288 // add props
289 ren->AddActor2D(this->ScalarBarActor);
290 ren->AddActor(this->GeometryActor);
291 ren->AddActor(this->PointSpritesActor);
292 ren->AddVolume(this->VolumeProp);
293 }
294
295 //----------------------------------------------------------------------------
296 // TODO : add this function in a utils file for rendering in VTK directly
GetTexture(const std::string & fileName,bool isSRGB)297 vtkSmartPointer<vtkTexture> vtkF3DGenericImporter::GetTexture(
298 const std::string& fileName, bool isSRGB)
299 {
300 vtkSmartPointer<vtkTexture> texture;
301 if (!fileName.empty())
302 {
303 std::string fullPath = vtksys::SystemTools::CollapseFullPath(fileName);
304
305 auto reader = vtkSmartPointer<vtkImageReader2>::Take(
306 vtkImageReader2Factory::CreateImageReader2(fullPath.c_str()));
307 if (reader)
308 {
309 reader->SetFileName(fullPath.c_str());
310 reader->Update();
311 texture = vtkSmartPointer<vtkTexture>::New();
312 texture->SetInputConnection(reader->GetOutputPort());
313 if (isSRGB)
314 {
315 texture->UseSRGBColorSpaceOn();
316 }
317 texture->InterpolateOn();
318 return texture;
319 }
320 else
321 {
322 F3DLog::Print(F3DLog::Severity::Warning, "Cannot open texture file ", fullPath);
323 }
324 }
325
326 return texture;
327 }
328
329 //----------------------------------------------------------------------------
ImportLights(vtkRenderer * ren)330 void vtkF3DGenericImporter::ImportLights(vtkRenderer* ren)
331 {
332 ren->RemoveAllLights();
333 ren->AutomaticLightCreationOff();
334
335 if (!ren->GetUseImageBasedLighting())
336 {
337 vtkNew<vtkLightKit> lightKit;
338 lightKit->AddLightsToRenderer(ren);
339 }
340 }
341
342 //----------------------------------------------------------------------------
ImportProperties(vtkRenderer * vtkNotUsed (ren))343 void vtkF3DGenericImporter::ImportProperties(vtkRenderer* vtkNotUsed(ren)) {}
344
345 //----------------------------------------------------------------------------
PrintSelf(std::ostream & os,vtkIndent indent)346 void vtkF3DGenericImporter::PrintSelf(std::ostream& os, vtkIndent indent)
347 {
348 vtkImporter::PrintSelf(os, indent);
349 }
350
351 //----------------------------------------------------------------------------
SetFileName(const char * arg)352 void vtkF3DGenericImporter::SetFileName(const char* arg)
353 {
354 this->TemporalInformationUpdated = false;
355 this->Reader->SetFileName(std::string(arg));
356 }
357
358 //----------------------------------------------------------------------------
SetOptions(const F3DOptions & options)359 void vtkF3DGenericImporter::SetOptions(const F3DOptions& options)
360 {
361 this->Options = &options;
362 }
363
364 //----------------------------------------------------------------------------
CanReadFile()365 bool vtkF3DGenericImporter::CanReadFile()
366 {
367 return this->Reader->IsReaderValid();
368 }
369
370 //----------------------------------------------------------------------------
GetOutputsDescription()371 std::string vtkF3DGenericImporter::GetOutputsDescription()
372 {
373 return this->OutputDescription;
374 }
375
376 //----------------------------------------------------------------------------
GetMultiBlockDescription(vtkMultiBlockDataSet * mb,vtkIndent indent)377 std::string vtkF3DGenericImporter::GetMultiBlockDescription(
378 vtkMultiBlockDataSet* mb, vtkIndent indent)
379 {
380 std::stringstream ss;
381 for (vtkIdType i = 0; i < mb->GetNumberOfBlocks(); i++)
382 {
383 const char* blockName = mb->GetMetaData(i)->Get(vtkCompositeDataSet::NAME());
384 ss << indent << "Block: " << (blockName ? std::string(blockName) : std::to_string(i)) << "\n";
385 vtkDataObject* object = mb->GetBlock(i);
386 vtkMultiBlockDataSet* mbChild = vtkMultiBlockDataSet::SafeDownCast(object);
387 vtkDataSet* ds = vtkDataSet::SafeDownCast(object);
388 if (mbChild)
389 {
390 ss << vtkF3DGenericImporter::GetMultiBlockDescription(mbChild, indent.GetNextIndent());
391 }
392 else if (ds)
393 {
394 ss << vtkImporter::GetDataSetDescription(ds, indent.GetNextIndent());
395 }
396 }
397 return ss.str();
398 }
399
400 //----------------------------------------------------------------------------
GetDataObjectDescription(vtkDataObject * object)401 std::string vtkF3DGenericImporter::GetDataObjectDescription(vtkDataObject* object)
402 {
403 vtkMultiBlockDataSet* mb = vtkMultiBlockDataSet::SafeDownCast(object);
404 vtkDataSet* ds = vtkDataSet::SafeDownCast(object);
405 if (mb)
406 {
407 return vtkF3DGenericImporter::GetMultiBlockDescription(mb, vtkIndent(0));
408 }
409 else if (ds)
410 {
411 return vtkImporter::GetDataSetDescription(ds, vtkIndent(0));
412 }
413 return "";
414 }
415
416 //----------------------------------------------------------------------------
UpdateTimeStep(double timestep)417 void vtkF3DGenericImporter::UpdateTimeStep(double timestep)
418 {
419 this->PostPro->UpdateTimeStep(timestep);
420 }
421