Skip to content

WebGPU PointCloudMapper

Repository source: WebGPU_PointCloudMapper

Description

This example demonstrates how to use the vtkWebGPUPointCloudMapper of the WebGPU module with colors mapped on points through scalars.

This mapper derives from [vtkPolyDataMapper](https://www.vtk.org/doc/nightly/html/classvtkPolyDataMapper.html) and is thus used analogously. The mapper will only render points (and not 1-vertex cells) of the polydata it is given as input.

The colors can be set on points through the use of scalars.

Note that to use this example, you will need your VTK to be built with WebGPU. Building instructions can be found here.

It is expected that the illustration image of this example is flipped compared to what is rendered on screen when running the example locally.

Question

If you have a question about this example, please use the VTK Discourse Forum

Code

WebGPU_PointCloudMapper.cxx

#include "vtkCamera.h"
#include "vtkNew.h"
#include "vtkPointData.h"
#include "vtkPolyDataMapper.h"
#include "vtkRenderWindow.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkRenderer.h"
#include "vtkWebGPUComputePointCloudMapper.h"

namespace {
vtkSmartPointer<vtkPolyData> CreatePointCloud()
{
  vtkNew<vtkUnsignedCharArray> colors;
  colors->SetNumberOfComponents(4);

  vtkNew<vtkPoints> points;
  // How many points in X, Y, Z direction
  constexpr int sizeX = 1200;
  constexpr int sizeY = 12;
  constexpr int sizeZ = 1200;

  // 'divider' controls the space between the points. Higher values means points
  // closer together
  constexpr float divider = 16.0f;
  // Controls the 'width' of the cosine wave
  constexpr float divider_cos = divider * 8;
  // Height of the cosine wave
  constexpr float cos_height_multiplier = 8;
  // Variables that indicates what the maximum extent of the point is expected
  // to be
  constexpr float maxX = sizeX / divider;
  constexpr float maxY = sizeY / divider;
  constexpr float maxZ = sizeZ / divider;
  for (int i = 0; i < sizeX; i++)
  {
    for (int j = 0; j < sizeY; j++)
    {
      for (int k = 0; k < sizeZ; k++)
      {
        int pointIndex = k + j * sizeZ + i * sizeY * sizeZ;

        // Using rand() here to jitter the points a little bit to reduce visible
        // aliasing
        double pointX = i / divider + rand() / (float)RAND_MAX;
        double pointZ = k / divider + rand() / (float)RAND_MAX;

        double cosX = std::cos(i / divider_cos);
        double sinZ = std::sin(k / divider_cos);
        double pointY = cosX * cos_height_multiplier * sinZ + j / 10.0f;

        points->InsertNextPoint(pointX, pointY, pointZ);

        // Inserting the R, G, B components to create color gradients
        colors->InsertComponent(
            pointIndex, 0,
            static_cast<unsigned char>(i / divider / maxX * 255.0f));
        colors->InsertComponent(
            pointIndex, 1,
            static_cast<unsigned char>(j / divider / maxY * 255.0f));
        colors->InsertComponent(
            pointIndex, 2,
            static_cast<unsigned char>(k / divider / maxZ * 127.0f + 127.0f));
        colors->InsertComponent(pointIndex, 3, 255);
      }
    }
  }

  vtkSmartPointer<vtkPolyData> polydata;
  polydata = vtkSmartPointer<vtkPolyData>::New();
  polydata->SetPoints(points);
  polydata->GetPointData()->SetScalars(colors);

  return polydata;
}
} // namespace

//------------------------------------------------------------------------------
int main(int argc, char* argv[])
{
  vtkNew<vtkRenderWindow> renWin;
  renWin->SetWindowName(__func__);
  renWin->SetMultiSamples(0);
  renWin->SetSize(1280, 720);

  vtkSmartPointer<vtkRenderer> renderer = vtkSmartPointer<vtkRenderer>::New();
  renderer->SetBackground(0.2, 0.3, 0.4);
  // Setting the camera to a nice position for looking at the point cloud
  renderer->GetActiveCamera()->SetPosition(150.594, 37.6722, 40.0177);
  renderer->GetActiveCamera()->SetFocalPoint(38.6725, -1.44734, 37.6991);
  renWin->AddRenderer(renderer);

  vtkSmartPointer<vtkPolyData> polydata = CreatePointCloud();

  // Center the camera on the point cloud
  renderer->ResetCamera(polydata->GetBounds());

  // Create the mapper and set its input as any other poly data mapper
  vtkNew<vtkWebGPUComputePointCloudMapper> pointCloudMapper;
  pointCloudMapper->SetInputData(polydata);

  vtkNew<vtkActor> actor;
  actor->SetMapper(pointCloudMapper);

  renderer->AddActor(actor);

  // Start an interactor to interact with the point cloud
  vtkNew<vtkRenderWindowInteractor> iren;
  iren->SetRenderWindow(renWin);
  iren->Start();

  return 0;
}

CMakeLists.txt

cmake_minimum_required(VERSION 3.12 FATAL_ERROR)

project(WebGPU_PointCloudMapper)

find_package(VTK COMPONENTS 
  CommonCore
  CommonDataModel
  InteractionStyle
  RenderingContextOpenGL2
  RenderingCore
  RenderingFreeType
  RenderingGL2PSOpenGL2
  RenderingOpenGL2
)

if (NOT VTK_FOUND)
  message(FATAL_ERROR "WebGPU_PointCloudMapper: Unable to find the VTK build folder.")
endif()

# Prevent a "command line is too long" failure in Windows.
set(CMAKE_NINJA_FORCE_RESPONSE_FILE "ON" CACHE BOOL "Force Ninja to use response files.")
add_executable(WebGPU_PointCloudMapper MACOSX_BUNDLE WebGPU_PointCloudMapper.cxx )
  target_link_libraries(WebGPU_PointCloudMapper PRIVATE ${VTK_LIBRARIES}
)
# vtk_module_autoinit is needed
vtk_module_autoinit(
  TARGETS WebGPU_PointCloudMapper
  MODULES ${VTK_LIBRARIES}
)

Download and Build WebGPU_PointCloudMapper

Click here to download WebGPU_PointCloudMapper and its CMakeLists.txt file. Once the tarball WebGPU_PointCloudMapper.tar has been downloaded and extracted,

cd WebGPU_PointCloudMapper/build

If VTK is installed:

cmake ..

If VTK is not installed but compiled on your system, you will need to specify the path to your VTK build:

cmake -DVTK_DIR:PATH=/home/me/vtk_build ..

Build the project:

make

and run it:

./WebGPU_PointCloudMapper

WINDOWS USERS

Be sure to add the VTK bin directory to your path. This will resolve the VTK dll's at run time.