|
34 | 34 | #include <vtk_glew.h> |
35 | 35 | #endif |
36 | 36 |
|
| 37 | +#include <algorithm> |
37 | 38 | #include <sstream> |
| 39 | +#include <vector> |
38 | 40 |
|
39 | 41 | //---------------------------------------------------------------------------- |
40 | 42 | class vtkF3DSplatMapperHelper : public vtkOpenGLPointGaussianMapperHelper |
@@ -76,17 +78,22 @@ class vtkF3DSplatMapperHelper : public vtkOpenGLPointGaussianMapperHelper |
76 | 78 |
|
77 | 79 | private: |
78 | 80 | #if !defined(__ANDROID__) && !defined(__EMSCRIPTEN__) |
79 | | - void SortSplats(vtkRenderer* ren); |
80 | | - |
81 | 81 | vtkNew<vtkShader> DepthComputeShader; |
82 | 82 | vtkNew<vtkShaderProgram> DepthProgram; |
83 | 83 | vtkNew<vtkOpenGLBufferObject> DepthBuffer; |
84 | 84 |
|
85 | 85 | vtkNew<vtkF3DBitonicSort> Sorter; |
| 86 | +#endif |
| 87 | + |
| 88 | + std::vector<unsigned int> CPUSortedIndices; |
| 89 | + std::vector<float> CPUDepths; |
86 | 90 |
|
87 | | - double DirectionThreshold = 0.999; |
| 91 | + static constexpr double DirectionThreshold = 0.999; |
88 | 92 | double LastDirection[3] = { 0.0, 0.0, 0.0 }; |
89 | | -#endif |
| 93 | + |
| 94 | + bool SortNeeded(vtkRenderer* ren); |
| 95 | + void SortSplats(vtkRenderer* ren); |
| 96 | + void SortSplatsCPU(vtkRenderer* ren); |
90 | 97 |
|
91 | 98 | bool OwnerUseInstancing(); |
92 | 99 |
|
@@ -311,71 +318,129 @@ void vtkF3DSplatMapperHelper::SetCameraShaderParameters( |
311 | 318 | this->Superclass::SetCameraShaderParameters(cellBO, ren, actor); |
312 | 319 | } |
313 | 320 |
|
314 | | -#if !defined(__ANDROID__) && !defined(__EMSCRIPTEN__) |
| 321 | +//------------------------------------------------------------------------------ |
| 322 | +bool vtkF3DSplatMapperHelper::SortNeeded(vtkRenderer* ren) |
| 323 | +{ |
| 324 | + const double* focalPoint = ren->GetActiveCamera()->GetFocalPoint(); |
| 325 | + const double* origin = ren->GetActiveCamera()->GetPosition(); |
| 326 | + double direction[3]; |
| 327 | + |
| 328 | + for (int i = 0; i < 3; ++i) |
| 329 | + { |
| 330 | + // the orientation is reverted to sort splats back to front |
| 331 | + direction[i] = origin[i] - focalPoint[i]; |
| 332 | + } |
| 333 | + |
| 334 | + vtkMath::Normalize(direction); |
| 335 | + |
| 336 | + if (vtkMath::Dot(this->LastDirection, direction) >= vtkF3DSplatMapperHelper::DirectionThreshold) |
| 337 | + { |
| 338 | + return false; |
| 339 | + } |
| 340 | + |
| 341 | + this->LastDirection[0] = direction[0]; |
| 342 | + this->LastDirection[1] = direction[1]; |
| 343 | + this->LastDirection[2] = direction[2]; |
| 344 | + |
| 345 | + return true; |
| 346 | +} |
| 347 | + |
315 | 348 | //---------------------------------------------------------------------------- |
316 | 349 | void vtkF3DSplatMapperHelper::SortSplats(vtkRenderer* ren) |
317 | 350 | { |
318 | | - int numVerts = this->VBOs->GetNumberOfTuples("vertexMC"); |
| 351 | +#if !defined(__ANDROID__) && !defined(__EMSCRIPTEN__) |
319 | 352 |
|
320 | | - if (numVerts) |
| 353 | + if (!this->SortNeeded(ren)) |
321 | 354 | { |
322 | | - const double* focalPoint = ren->GetActiveCamera()->GetFocalPoint(); |
323 | | - const double* origin = ren->GetActiveCamera()->GetPosition(); |
324 | | - double direction[3]; |
| 355 | + return; |
| 356 | + } |
325 | 357 |
|
326 | | - for (int i = 0; i < 3; ++i) |
327 | | - { |
328 | | - // the orientation is reverted to sort splats back to front |
329 | | - direction[i] = origin[i] - focalPoint[i]; |
330 | | - } |
| 358 | + int numVerts = this->VBOs->GetNumberOfTuples("vertexMC"); |
331 | 359 |
|
332 | | - vtkMath::Normalize(direction); |
| 360 | + vtkOpenGLShaderCache* shaderCache = |
| 361 | + vtkOpenGLRenderWindow::SafeDownCast(ren->GetRenderWindow())->GetShaderCache(); |
333 | 362 |
|
334 | | - // sort the splats only if the camera direction has changed |
335 | | - if (vtkMath::Dot(this->LastDirection, direction) < this->DirectionThreshold) |
336 | | - { |
337 | | - vtkOpenGLShaderCache* shaderCache = |
338 | | - vtkOpenGLRenderWindow::SafeDownCast(ren->GetRenderWindow())->GetShaderCache(); |
| 363 | + // compute next power of two |
| 364 | + unsigned int numVertsExt = vtkMath::NearestPowerOfTwo(numVerts); |
339 | 365 |
|
340 | | - // compute next power of two |
341 | | - unsigned int numVertsExt = vtkMath::NearestPowerOfTwo(numVerts); |
| 366 | + // depth computation |
| 367 | + shaderCache->ReadyShaderProgram(this->DepthProgram); |
342 | 368 |
|
343 | | - // depth computation |
344 | | - shaderCache->ReadyShaderProgram(this->DepthProgram); |
| 369 | + this->DepthProgram->SetUniform3f("viewDirection", this->LastDirection); |
| 370 | + this->DepthProgram->SetUniformi("count", numVerts); |
| 371 | + this->VBOs->GetVBO("vertexMC")->BindShaderStorage(0); |
| 372 | + this->Primitives[PrimitivePoints].IBO->BindShaderStorage(1); |
| 373 | + this->DepthBuffer->BindShaderStorage(2); |
345 | 374 |
|
346 | | - this->LastDirection[0] = direction[0]; |
347 | | - this->LastDirection[1] = direction[1]; |
348 | | - this->LastDirection[2] = direction[2]; |
| 375 | + glDispatchCompute(numVertsExt / 32, 1, 1); |
| 376 | + glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT); |
349 | 377 |
|
350 | | - this->DepthProgram->SetUniform3f("viewDirection", direction); |
351 | | - this->DepthProgram->SetUniformi("count", numVerts); |
352 | | - this->VBOs->GetVBO("vertexMC")->BindShaderStorage(0); |
353 | | - this->Primitives[PrimitivePoints].IBO->BindShaderStorage(1); |
354 | | - this->DepthBuffer->BindShaderStorage(2); |
| 378 | + // sort |
| 379 | + this->Sorter->Run(vtkOpenGLRenderWindow::SafeDownCast(ren->GetRenderWindow()), numVerts, |
| 380 | + this->DepthBuffer, this->Primitives[PrimitivePoints].IBO); |
| 381 | +#endif |
| 382 | +} |
355 | 383 |
|
356 | | - glDispatchCompute(numVertsExt / 32, 1, 1); |
357 | | - glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT); |
| 384 | +//---------------------------------------------------------------------------- |
| 385 | +void vtkF3DSplatMapperHelper::SortSplatsCPU(vtkRenderer* ren) |
| 386 | +{ |
| 387 | + if (!this->SortNeeded(ren)) |
| 388 | + { |
| 389 | + return; |
| 390 | + } |
358 | 391 |
|
359 | | - // sort |
360 | | - this->Sorter->Run(vtkOpenGLRenderWindow::SafeDownCast(ren->GetRenderWindow()), numVerts, |
361 | | - this->DepthBuffer, this->Primitives[PrimitivePoints].IBO); |
362 | | - } |
| 392 | + int numVerts = this->VBOs->GetNumberOfTuples("vertexMC"); |
| 393 | + |
| 394 | + this->CPUSortedIndices.resize(static_cast<size_t>(numVerts)); |
| 395 | + |
| 396 | + this->Primitives[PrimitivePoints].IBO->Download( |
| 397 | + this->CPUSortedIndices.data(), static_cast<size_t>(numVerts)); |
| 398 | + |
| 399 | + this->CPUDepths.resize(static_cast<size_t>(numVerts)); |
| 400 | + // compute depth for each splat |
| 401 | + vtkPolyData* poly = this->CurrentInput; |
| 402 | + |
| 403 | + vtkPoints* points = poly->GetPoints(); |
| 404 | + |
| 405 | + for (int i = 0; i < numVerts; ++i) |
| 406 | + { |
| 407 | + const double* pos = points->GetPoint(i); |
| 408 | + this->CPUDepths[i] = pos[0] * this->LastDirection[0] + pos[1] * this->LastDirection[1] + |
| 409 | + pos[2] * this->LastDirection[2]; |
363 | 410 | } |
| 411 | + |
| 412 | + // Match bitonic sort ordering: sort ascending by depth (back-to-front given reversed direction) |
| 413 | + std::sort(this->CPUSortedIndices.begin(), this->CPUSortedIndices.end(), |
| 414 | + [&](const GLuint& a, const GLuint& b) { return this->CPUDepths[a] < this->CPUDepths[b]; }); |
| 415 | + |
| 416 | + this->Primitives[PrimitivePoints].IBO->Upload(this->CPUSortedIndices.data(), |
| 417 | + static_cast<size_t>(numVerts), vtkOpenGLBufferObject::ObjectType::ElementArrayBuffer); |
364 | 418 | } |
365 | | -#endif |
366 | 419 |
|
367 | 420 | //---------------------------------------------------------------------------- |
368 | 421 | void vtkF3DSplatMapperHelper::RenderPieceDraw(vtkRenderer* ren, vtkActor* actor) |
369 | 422 | { |
370 | | -#if !defined(__ANDROID__) && !defined(__EMSCRIPTEN__) |
371 | 423 | const vtkF3DRenderer* renderer = vtkF3DRenderer::SafeDownCast(ren); |
372 | 424 |
|
373 | | - if (renderer->GetBlendingMode() == vtkF3DRenderer::BlendingMode::SORT && |
374 | | - vtkShader::IsComputeShaderSupported() && actor->HasTranslucentPolygonalGeometry()) |
| 425 | + if (actor->HasTranslucentPolygonalGeometry()) |
375 | 426 | { |
376 | | - this->SortSplats(ren); |
| 427 | + if (renderer->GetBlendingMode() == vtkF3DRenderer::BlendingMode::SORT) |
| 428 | + { |
| 429 | + if (vtkShader::IsComputeShaderSupported()) |
| 430 | + { |
| 431 | + this->SortSplats(ren); |
| 432 | + } |
| 433 | + else |
| 434 | + { |
| 435 | + vtkWarningMacro("Compute shaders not supported, falling back to CPU sorting"); |
| 436 | + this->SortSplatsCPU(ren); |
| 437 | + } |
| 438 | + } |
| 439 | + else if (renderer->GetBlendingMode() == vtkF3DRenderer::BlendingMode::SORT_CPU) |
| 440 | + { |
| 441 | + this->SortSplatsCPU(ren); |
| 442 | + } |
377 | 443 | } |
378 | | -#endif |
379 | 444 |
|
380 | 445 | if (this->OwnerUseInstancing()) |
381 | 446 | { |
|
0 commit comments