diff --git a/Interaction/Widgets/vtk.module b/Interaction/Widgets/vtk.module
index 59b771d3624f3af292ae1024f152d3ca9f3520ab..4bfd44d354e39ac39a720ea4f28277d4e43dd6f1 100644
--- a/Interaction/Widgets/vtk.module
+++ b/Interaction/Widgets/vtk.module
@@ -42,7 +42,6 @@ PRIVATE_DEPENDS
   VTK::RenderingAnnotation
   VTK::RenderingFreeType
   VTK::RenderingVolume
-  VTK::RenderingOpenGL2
 
 TEST_DEPENDS
   VTK::CommonComputationalGeometry
diff --git a/Interaction/Widgets/vtk3DCursorRepresentation.cxx b/Interaction/Widgets/vtk3DCursorRepresentation.cxx
index bc432583525889a9539a30e1a9b0a1478291e607..acdc10f520c34e3ab3ee327ffd63ac5d8dac9375 100644
--- a/Interaction/Widgets/vtk3DCursorRepresentation.cxx
+++ b/Interaction/Widgets/vtk3DCursorRepresentation.cxx
@@ -7,7 +7,6 @@
 #include "vtkHardwarePicker.h"
 #include "vtkMath.h"
 #include "vtkObjectFactory.h"
-#include "vtkOpenGLPolyDataMapper.h"
 #include "vtkPolyDataMapper.h"
 #include "vtkProperty.h"
 #include "vtkRenderer.h"
@@ -178,7 +177,7 @@ void vtk3DCursorRepresentation::WidgetInteraction(double newEventPos[2])
         cpdm->SetCellIdArrayName(nullptr);
       }
     }
-    else if (auto glMapper = vtkOpenGLPolyDataMapper::SafeDownCast(actor->GetMapper()))
+    else if (auto glMapper = vtkPolyDataMapper::SafeDownCast(actor->GetMapper()))
     {
       if (glMapper->GetPointIdArrayName())
       {
@@ -202,7 +201,7 @@ void vtk3DCursorRepresentation::WidgetInteraction(double newEventPos[2])
     {
       cpdm->SetPointIdArrayName(item->second.c_str());
     }
-    else if (auto glMapper = vtkOpenGLPolyDataMapper::SafeDownCast(item->first))
+    else if (auto glMapper = vtkPolyDataMapper::SafeDownCast(item->first))
     {
       glMapper->SetPointIdArrayName(item->second.c_str());
     }
@@ -213,7 +212,7 @@ void vtk3DCursorRepresentation::WidgetInteraction(double newEventPos[2])
     {
       cpdm->SetCellIdArrayName(item->second.c_str());
     }
-    else if (auto glMapper = vtkOpenGLPolyDataMapper::SafeDownCast(item->first))
+    else if (auto glMapper = vtkPolyDataMapper::SafeDownCast(item->first))
     {
       glMapper->SetCellIdArrayName(item->second.c_str());
     }
diff --git a/Rendering/Core/vtkCompositePolyDataMapper.cxx b/Rendering/Core/vtkCompositePolyDataMapper.cxx
index 92d005293d08633c3ef40aef197089fbe66b9204..bd5ba2855769f7851634646117a6dda83b49a2b3 100644
--- a/Rendering/Core/vtkCompositePolyDataMapper.cxx
+++ b/Rendering/Core/vtkCompositePolyDataMapper.cxx
@@ -85,13 +85,7 @@ vtkCompositePolyDataMapper::vtkCompositePolyDataMapper()
 }
 
 //------------------------------------------------------------------------------
-vtkCompositePolyDataMapper::~vtkCompositePolyDataMapper()
-{
-  this->SetPointIdArrayName(nullptr);
-  this->SetCellIdArrayName(nullptr);
-  this->SetProcessIdArrayName(nullptr);
-  this->SetCompositeIdArrayName(nullptr);
-}
+vtkCompositePolyDataMapper::~vtkCompositePolyDataMapper() = default;
 
 //------------------------------------------------------------------------------
 // Specify the type of data this mapper can handle. If we are
@@ -175,10 +169,7 @@ void vtkCompositePolyDataMapper::ShallowCopy(vtkAbstractMapper* mapper)
   {
     this->SetCompositeDataDisplayAttributes(cpdm->GetCompositeDataDisplayAttributes());
     this->SetColorMissingArraysWithNanColor(cpdm->GetColorMissingArraysWithNanColor());
-    this->SetCellIdArrayName(cpdm->GetCellIdArrayName());
     this->SetCompositeIdArrayName(cpdm->GetCompositeIdArrayName());
-    this->SetPointIdArrayName(cpdm->GetPointIdArrayName());
-    this->SetProcessIdArrayName(cpdm->GetProcessIdArrayName());
   }
   // Now do superclass
   this->vtkPolyDataMapper::ShallowCopy(mapper);
diff --git a/Rendering/Core/vtkCompositePolyDataMapper.h b/Rendering/Core/vtkCompositePolyDataMapper.h
index 2252b2dbd139d5fa346ae673b471ba52febb32a0..8c3ad39a05e4f3112eebe1d00c144e59373a1362 100644
--- a/Rendering/Core/vtkCompositePolyDataMapper.h
+++ b/Rendering/Core/vtkCompositePolyDataMapper.h
@@ -236,45 +236,6 @@ public:
    */
   vtkMTimeType GetMTime() override;
 
-  ///@{
-  /**
-   * By default, this class uses the dataset's point and cell ids during
-   * rendering. However, one can override those by specifying cell and point
-   * data arrays to use instead. Currently, only vtkIdType array is supported.
-   * Set to NULL string (default) to use the point ids instead.
-   */
-  vtkSetStringMacro(PointIdArrayName);
-  vtkGetStringMacro(PointIdArrayName);
-  vtkSetStringMacro(CellIdArrayName);
-  vtkGetStringMacro(CellIdArrayName);
-  ///@}
-
-  ///@{
-  /**
-   * If this class should override the process id using a data-array,
-   * set this variable to the name of the array to use. It must be a
-   * point-array.
-   * The array's DataType *MUST* be VTK_UNSIGNED_INT.
-   */
-  vtkSetStringMacro(ProcessIdArrayName);
-  vtkGetStringMacro(ProcessIdArrayName);
-  ///@}
-
-  ///@{
-  /**
-   * Generally, this class can render the composite id when iterating
-   * over composite datasets. However in some cases (as in AMR), the rendered
-   * structure may not correspond to the input data, in which case we need
-   * to provide a cell array that can be used to render in the composite id in
-   * selection passes. Set to NULL (default) to not override the composite id
-   * color set by vtkCompositePainter if any.
-   * The array *MUST* be a cell array.
-   * The array's DataType *MUST* be VTK_UNSIGNED_INT.
-   */
-  vtkSetStringMacro(CompositeIdArrayName);
-  vtkGetStringMacro(CompositeIdArrayName);
-  ///@}
-
 protected:
   vtkCompositePolyDataMapper();
   ~vtkCompositePolyDataMapper() override;
@@ -364,12 +325,6 @@ protected:
    */
   vtkTimeStamp BoundsMTime;
 
-  // additional picking indirection
-  char* PointIdArrayName = nullptr;
-  char* CellIdArrayName = nullptr;
-  char* ProcessIdArrayName = nullptr;
-  char* CompositeIdArrayName = nullptr;
-
   vtkStateStorage TranslucentState;
   bool HasTranslucentGeometry = false;
   vtkStateStorage RenderValuesState;
diff --git a/Rendering/Core/vtkPolyDataMapper.cxx b/Rendering/Core/vtkPolyDataMapper.cxx
index 4aa767c0c8180035993493cf29165b217e99a875..9a93c2c1c8e463d4baf7153beb695118a460c307 100644
--- a/Rendering/Core/vtkPolyDataMapper.cxx
+++ b/Rendering/Core/vtkPolyDataMapper.cxx
@@ -25,6 +25,19 @@ vtkPolyDataMapper::vtkPolyDataMapper()
   this->SeamlessV = false;
   this->PauseShiftScale = false;
   this->ShiftScaleMethod = ShiftScaleMethodType::AUTO_SHIFT_SCALE;
+  this->SetPointIdArrayName(nullptr);
+  this->SetCellIdArrayName(nullptr);
+  this->SetCompositeIdArrayName(nullptr);
+  this->SetProcessIdArrayName(nullptr);
+}
+
+//------------------------------------------------------------------------------
+vtkPolyDataMapper::~vtkPolyDataMapper()
+{
+  this->SetPointIdArrayName(nullptr);
+  this->SetCellIdArrayName(nullptr);
+  this->SetCompositeIdArrayName(nullptr);
+  this->SetProcessIdArrayName(nullptr);
 }
 
 //------------------------------------------------------------------------------
@@ -156,6 +169,9 @@ void vtkPolyDataMapper::ShallowCopy(vtkAbstractMapper* mapper)
     this->SetSeamlessV(m->GetSeamlessV());
     this->SetVBOShiftScaleMethod(m->GetVBOShiftScaleMethod());
     this->SetPauseShiftScale(m->GetPauseShiftScale());
+    this->SetCellIdArrayName(m->GetCellIdArrayName());
+    this->SetPointIdArrayName(m->GetPointIdArrayName());
+    this->SetProcessIdArrayName(m->GetProcessIdArrayName());
   }
 
   // Now do superclass
diff --git a/Rendering/Core/vtkPolyDataMapper.h b/Rendering/Core/vtkPolyDataMapper.h
index 0e31f9f3f066198136a7c6ccbb4e8edaa2406984..06b0869f2d5b8707a4db51afaee9385e84ad3451 100644
--- a/Rendering/Core/vtkPolyDataMapper.h
+++ b/Rendering/Core/vtkPolyDataMapper.h
@@ -107,6 +107,45 @@ public:
   vtkBooleanMacro(SeamlessV, bool);
   ///@}
 
+  ///@{
+  /**
+   * By default, this class uses the dataset's point and cell ids during
+   * rendering. However, one can override those by specifying cell and point
+   * data arrays to use instead. Currently, only vtkIdType array is supported.
+   * Set to NULL string (default) to use the point ids instead.
+   */
+  vtkSetStringMacro(PointIdArrayName);
+  vtkGetStringMacro(PointIdArrayName);
+  vtkSetStringMacro(CellIdArrayName);
+  vtkGetStringMacro(CellIdArrayName);
+  ///@}
+
+  ///@{
+  /**
+   * Generally, this class can render the composite id when iterating
+   * over composite datasets. However in some cases (as in AMR), the rendered
+   * structure may not correspond to the input data, in which case we need
+   * to provide a cell array that can be used to render in the composite id in
+   * selection passes. Set to NULL (default) to not override the composite id
+   * color set by vtkCompositePainter if any.
+   * The array *MUST* be a cell array.
+   * The array's DataType *MUST* be VTK_UNSIGNED_INT.
+   */
+  vtkSetStringMacro(CompositeIdArrayName);
+  vtkGetStringMacro(CompositeIdArrayName);
+  ///@}
+
+  ///@{
+  /**
+   * If this class should override the process id using a data-array,
+   * set this variable to the name of the array to use. It must be a
+   * point-array.
+   * The array's DataType *MUST* be VTK_UNSIGNED_INT.
+   */
+  vtkSetStringMacro(ProcessIdArrayName);
+  vtkGetStringMacro(ProcessIdArrayName);
+  ///@}
+
   /**
    * Return bounding box (array of six doubles) of data expressed as
    * (xmin,xmax, ymin,ymax, zmin,zmax).
@@ -213,7 +252,7 @@ public:
 
 protected:
   vtkPolyDataMapper();
-  ~vtkPolyDataMapper() override = default;
+  ~vtkPolyDataMapper() override;
 
   /**
    * Called in GetBounds(). When this method is called, the consider the input
@@ -230,6 +269,12 @@ protected:
   int ShiftScaleMethod; // for points
   bool PauseShiftScale;
 
+  // additional picking indirection
+  char* PointIdArrayName = nullptr;
+  char* CellIdArrayName = nullptr;
+  char* CompositeIdArrayName = nullptr;
+  char* ProcessIdArrayName = nullptr;
+
   int FillInputPortInformation(int, vtkInformation*) override;
 
 private:
diff --git a/Rendering/OpenGL2/vtkOpenGLLowMemoryBatchedPolyDataMapper.cxx b/Rendering/OpenGL2/vtkOpenGLLowMemoryBatchedPolyDataMapper.cxx
index 86895396aee72cdcfd5cf98693b13aeba5333a79..aa86cf40e7ffdecb81be5e919fb696b0a99e83a7 100644
--- a/Rendering/OpenGL2/vtkOpenGLLowMemoryBatchedPolyDataMapper.cxx
+++ b/Rendering/OpenGL2/vtkOpenGLLowMemoryBatchedPolyDataMapper.cxx
@@ -451,9 +451,7 @@ void vtkOpenGLLowMemoryBatchedPolyDataMapper::ProcessCompositePixelBuffers(vtkHa
 
     if (sel->GetUseProcessIdFromData())
     {
-      processArray = !this->ProcessIdArrayName.empty()
-        ? pd->GetArray(this->ProcessIdArrayName.c_str())
-        : nullptr;
+      processArray = this->ProcessIdArrayName ? pd->GetArray(this->ProcessIdArrayName) : nullptr;
     }
 
     if (processdata && (processArray && processArray->GetDataType() == VTK_UNSIGNED_INT) &&
@@ -474,8 +472,8 @@ void vtkOpenGLLowMemoryBatchedPolyDataMapper::ProcessCompositePixelBuffers(vtkHa
   // do we need to do anything to the point id data?
   if (currPass == vtkHardwareSelector::POINT_ID_LOW24)
   {
-    vtkIdTypeArray* pointArrayId = !this->PointIdArrayName.empty()
-      ? vtkArrayDownCast<vtkIdTypeArray>(pd->GetArray(this->PointIdArrayName.c_str()))
+    vtkIdTypeArray* pointArrayId = this->PointIdArrayName
+      ? vtkArrayDownCast<vtkIdTypeArray>(pd->GetArray(this->PointIdArrayName))
       : nullptr;
 
     // do we need to do anything to the point id data?
@@ -517,8 +515,8 @@ void vtkOpenGLLowMemoryBatchedPolyDataMapper::ProcessCompositePixelBuffers(vtkHa
 
   if (currPass == vtkHardwareSelector::POINT_ID_HIGH24)
   {
-    vtkIdTypeArray* pointArrayId = !this->PointIdArrayName.empty()
-      ? vtkArrayDownCast<vtkIdTypeArray>(pd->GetArray(this->PointIdArrayName.c_str()))
+    vtkIdTypeArray* pointArrayId = this->PointIdArrayName
+      ? vtkArrayDownCast<vtkIdTypeArray>(pd->GetArray(this->PointIdArrayName))
       : nullptr;
 
     // do we need to do anything to the point id data?
@@ -557,9 +555,8 @@ void vtkOpenGLLowMemoryBatchedPolyDataMapper::ProcessCompositePixelBuffers(vtkHa
   {
     unsigned char* compositedata = sel->GetPixelBuffer(vtkHardwareSelector::COMPOSITE_INDEX_PASS);
 
-    vtkDataArray* compositeArray = !this->CompositeIdArrayName.empty()
-      ? cd->GetArray(this->CompositeIdArrayName.c_str())
-      : nullptr;
+    vtkDataArray* compositeArray =
+      this->CompositeIdArrayName ? cd->GetArray(this->CompositeIdArrayName) : nullptr;
 
     if (compositedata && (compositeArray && compositeArray->GetDataType() == VTK_UNSIGNED_INT) &&
       rawclowdata)
@@ -578,8 +575,8 @@ void vtkOpenGLLowMemoryBatchedPolyDataMapper::ProcessCompositePixelBuffers(vtkHa
 
   if (currPass == vtkHardwareSelector::CELL_ID_LOW24)
   {
-    vtkIdTypeArray* cellArrayId = !this->CellIdArrayName.empty()
-      ? vtkArrayDownCast<vtkIdTypeArray>(cd->GetArray(this->CellIdArrayName.c_str()))
+    vtkIdTypeArray* cellArrayId = this->CellIdArrayName
+      ? vtkArrayDownCast<vtkIdTypeArray>(cd->GetArray(this->CellIdArrayName))
       : nullptr;
     unsigned char* clowdata = sel->GetPixelBuffer(vtkHardwareSelector::CELL_ID_LOW24);
     bool hasHighCellIds = sel->HasHighCellIds();
@@ -620,8 +617,8 @@ void vtkOpenGLLowMemoryBatchedPolyDataMapper::ProcessCompositePixelBuffers(vtkHa
 
   if (currPass == vtkHardwareSelector::CELL_ID_HIGH24)
   {
-    vtkIdTypeArray* cellArrayId = !this->CellIdArrayName.empty()
-      ? vtkArrayDownCast<vtkIdTypeArray>(cd->GetArray(this->CellIdArrayName.c_str()))
+    vtkIdTypeArray* cellArrayId = this->CellIdArrayName
+      ? vtkArrayDownCast<vtkIdTypeArray>(cd->GetArray(this->CellIdArrayName))
       : nullptr;
     unsigned char* chighdata = sel->GetPixelBuffer(vtkHardwareSelector::CELL_ID_HIGH24);
 
diff --git a/Rendering/OpenGL2/vtkOpenGLLowMemoryPolyDataMapper.cxx b/Rendering/OpenGL2/vtkOpenGLLowMemoryPolyDataMapper.cxx
index 75d4619048af1c54a0c9d99e895c1fd3932e8181..dfacbef2601ac7f72926b71d3a49e0cc985adb94 100644
--- a/Rendering/OpenGL2/vtkOpenGLLowMemoryPolyDataMapper.cxx
+++ b/Rendering/OpenGL2/vtkOpenGLLowMemoryPolyDataMapper.cxx
@@ -2764,9 +2764,7 @@ void vtkOpenGLLowMemoryPolyDataMapper::ProcessSelectorPixelBuffers(
 
     if (sel->GetUseProcessIdFromData())
     {
-      processArray = !this->ProcessIdArrayName.empty()
-        ? pd->GetArray(this->ProcessIdArrayName.c_str())
-        : nullptr;
+      processArray = this->ProcessIdArrayName ? pd->GetArray(this->ProcessIdArrayName) : nullptr;
     }
 
     // do we need to do anything to the process pass data?
@@ -2788,8 +2786,8 @@ void vtkOpenGLLowMemoryPolyDataMapper::ProcessSelectorPixelBuffers(
 
   if (currPass == vtkHardwareSelector::POINT_ID_LOW24)
   {
-    vtkIdTypeArray* pointArrayId = !this->PointIdArrayName.empty()
-      ? vtkArrayDownCast<vtkIdTypeArray>(pd->GetArray(this->PointIdArrayName.c_str()))
+    vtkIdTypeArray* pointArrayId = this->PointIdArrayName
+      ? vtkArrayDownCast<vtkIdTypeArray>(pd->GetArray(this->PointIdArrayName))
       : nullptr;
 
     // do we need to do anything to the point id data?
@@ -2820,8 +2818,8 @@ void vtkOpenGLLowMemoryPolyDataMapper::ProcessSelectorPixelBuffers(
 
   if (currPass == vtkHardwareSelector::POINT_ID_HIGH24)
   {
-    vtkIdTypeArray* pointArrayId = !this->PointIdArrayName.empty()
-      ? vtkArrayDownCast<vtkIdTypeArray>(pd->GetArray(this->PointIdArrayName.c_str()))
+    vtkIdTypeArray* pointArrayId = this->PointIdArrayName
+      ? vtkArrayDownCast<vtkIdTypeArray>(pd->GetArray(this->PointIdArrayName))
       : nullptr;
 
     // do we need to do anything to the point id data?
@@ -2855,9 +2853,8 @@ void vtkOpenGLLowMemoryPolyDataMapper::ProcessSelectorPixelBuffers(
   {
     unsigned char* compositedata = sel->GetPixelBuffer(vtkHardwareSelector::COMPOSITE_INDEX_PASS);
 
-    vtkDataArray* compositeArray = !this->CompositeIdArrayName.empty()
-      ? cd->GetArray(this->CompositeIdArrayName.c_str())
-      : nullptr;
+    vtkDataArray* compositeArray =
+      this->CompositeIdArrayName ? cd->GetArray(this->CompositeIdArrayName) : nullptr;
 
     if (compositedata && (compositeArray && compositeArray->GetDataType() == VTK_UNSIGNED_INT) &&
       rawclowdata)
@@ -2877,8 +2874,8 @@ void vtkOpenGLLowMemoryPolyDataMapper::ProcessSelectorPixelBuffers(
   // process the cellid array?
   if (currPass == vtkHardwareSelector::CELL_ID_LOW24)
   {
-    vtkIdTypeArray* cellArrayId = !this->CellIdArrayName.empty()
-      ? vtkArrayDownCast<vtkIdTypeArray>(cd->GetArray(this->CellIdArrayName.c_str()))
+    vtkIdTypeArray* cellArrayId = this->CellIdArrayName
+      ? vtkArrayDownCast<vtkIdTypeArray>(cd->GetArray(this->CellIdArrayName))
       : nullptr;
     unsigned char* clowdata = sel->GetPixelBuffer(vtkHardwareSelector::CELL_ID_LOW24);
 
@@ -2911,8 +2908,8 @@ void vtkOpenGLLowMemoryPolyDataMapper::ProcessSelectorPixelBuffers(
 
   if (currPass == vtkHardwareSelector::CELL_ID_HIGH24)
   {
-    vtkIdTypeArray* cellArrayId = !this->CellIdArrayName.empty()
-      ? vtkArrayDownCast<vtkIdTypeArray>(cd->GetArray(this->CellIdArrayName.c_str()))
+    vtkIdTypeArray* cellArrayId = this->CellIdArrayName
+      ? vtkArrayDownCast<vtkIdTypeArray>(cd->GetArray(this->CellIdArrayName))
       : nullptr;
     unsigned char* chighdata = sel->GetPixelBuffer(vtkHardwareSelector::CELL_ID_HIGH24);
 
@@ -2955,9 +2952,8 @@ void vtkOpenGLLowMemoryPolyDataMapper::UpdateMaximumPointCellIds(vtkRenderer* re
   vtkIdType maxPointId = mesh->GetPoints()->GetNumberOfPoints() - 1;
   if (mesh && mesh->GetPointData())
   {
-    vtkIdTypeArray* pointArrayId = !this->PointIdArrayName.empty()
-      ? vtkArrayDownCast<vtkIdTypeArray>(
-          mesh->GetPointData()->GetArray(this->PointIdArrayName.c_str()))
+    vtkIdTypeArray* pointArrayId = this->PointIdArrayName
+      ? vtkArrayDownCast<vtkIdTypeArray>(mesh->GetPointData()->GetArray(this->PointIdArrayName))
       : nullptr;
     if (pointArrayId)
     {
@@ -2973,9 +2969,8 @@ void vtkOpenGLLowMemoryPolyDataMapper::UpdateMaximumPointCellIds(vtkRenderer* re
   vtkIdType maxCellId = mesh->GetNumberOfCells() - 1;
   if (mesh && mesh->GetCellData())
   {
-    vtkIdTypeArray* cellArrayId = !this->CellIdArrayName.empty()
-      ? vtkArrayDownCast<vtkIdTypeArray>(
-          mesh->GetCellData()->GetArray(this->CellIdArrayName.c_str()))
+    vtkIdTypeArray* cellArrayId = this->CellIdArrayName
+      ? vtkArrayDownCast<vtkIdTypeArray>(mesh->GetCellData()->GetArray(this->CellIdArrayName))
       : nullptr;
     if (cellArrayId)
     {
diff --git a/Rendering/OpenGL2/vtkOpenGLLowMemoryPolyDataMapper.h b/Rendering/OpenGL2/vtkOpenGLLowMemoryPolyDataMapper.h
index 9525e742e1a22e7cdd7565a742cfa1e17be8a301..32d5b29a90898437d17ecd0ad066fa03d8805c05 100644
--- a/Rendering/OpenGL2/vtkOpenGLLowMemoryPolyDataMapper.h
+++ b/Rendering/OpenGL2/vtkOpenGLLowMemoryPolyDataMapper.h
@@ -78,45 +78,6 @@ public:
    */
   bool GetSupportsSelection() override { return true; }
 
-  ///@{
-  /**
-   * By default, this class uses the dataset's point and cell ids during
-   * rendering. However, one can override those by specifying cell and point
-   * data arrays to use instead. Currently, only vtkIdType array is supported.
-   * Set to NULL string (default) to use the point ids instead.
-   */
-  vtkSetStdStringFromCharMacro(PointIdArrayName);
-  vtkGetCharFromStdStringMacro(PointIdArrayName);
-  vtkSetStdStringFromCharMacro(CellIdArrayName);
-  vtkGetCharFromStdStringMacro(CellIdArrayName);
-  ///@}
-
-  ///@{
-  /**
-   * If this class should override the process id using a data-array,
-   * set this variable to the name of the array to use. It must be a
-   * point-array.
-   * The array's DataType *MUST* be VTK_UNSIGNED_INT.
-   */
-  vtkSetStdStringFromCharMacro(ProcessIdArrayName);
-  vtkGetCharFromStdStringMacro(ProcessIdArrayName);
-  ///@}
-
-  ///@{
-  /**
-   * Generally, this class can render the composite id when iterating
-   * over composite datasets. However in some cases (as in AMR), the rendered
-   * structure may not correspond to the input data, in which case we need
-   * to provide a cell array that can be used to render in the composite id in
-   * selection passes. Set to NULL (default) to not override the composite id
-   * color set by vtkCompositePainter if any.
-   * The array *MUST* be a cell array.
-   * The array's DataType *MUST* be VTK_UNSIGNED_INT.
-   */
-  vtkSetStdStringFromCharMacro(CompositeIdArrayName);
-  vtkGetCharFromStdStringMacro(CompositeIdArrayName);
-  ///@}
-
   /// If you removed all mods, call this to go back to default setting.
   virtual void ResetModsToDefault();
   void AddMod(const std::string& className);
@@ -342,11 +303,6 @@ protected:
   /// @name Selection data
   bool PopulateSelectionSettings = true;
   bool PointPicking = false;
-  // additional picking indirection
-  std::string PointIdArrayName;
-  std::string CellIdArrayName;
-  std::string ProcessIdArrayName;
-  std::string CompositeIdArrayName;
 
   /// @name Cached PBR information
   bool HasAnisotropy = false;
diff --git a/Rendering/OpenGL2/vtkOpenGLPolyDataMapper.cxx b/Rendering/OpenGL2/vtkOpenGLPolyDataMapper.cxx
index 8f31a36c14f7e24d65866768443730dbf289d362..cc0c5de95e0902d9a61e22c1c7f3aed5bc718985 100644
--- a/Rendering/OpenGL2/vtkOpenGLPolyDataMapper.cxx
+++ b/Rendering/OpenGL2/vtkOpenGLPolyDataMapper.cxx
@@ -177,10 +177,6 @@ vtkOpenGLPolyDataMapper::~vtkOpenGLPolyDataMapper()
     this->CellNormalBuffer = nullptr;
   }
 
-  this->SetPointIdArrayName(nullptr);
-  this->SetCellIdArrayName(nullptr);
-  this->SetProcessIdArrayName(nullptr);
-  this->SetCompositeIdArrayName(nullptr);
   this->VBOs->Delete();
   this->VBOs = nullptr;
 
diff --git a/Rendering/OpenGL2/vtkOpenGLPolyDataMapper.h b/Rendering/OpenGL2/vtkOpenGLPolyDataMapper.h
index ef3c5280e60ba4654bd1f51e1321f82218c35b6e..711e3c9a60f9ab76a63cc7e270484510ba08f6c8 100644
--- a/Rendering/OpenGL2/vtkOpenGLPolyDataMapper.h
+++ b/Rendering/OpenGL2/vtkOpenGLPolyDataMapper.h
@@ -93,45 +93,6 @@ public:
   // other polydata (not the input)
   vtkPolyData* CurrentInput;
 
-  ///@{
-  /**
-   * By default, this class uses the dataset's point and cell ids during
-   * rendering. However, one can override those by specifying cell and point
-   * data arrays to use instead. Currently, only vtkIdType array is supported.
-   * Set to NULL string (default) to use the point ids instead.
-   */
-  vtkSetStringMacro(PointIdArrayName);
-  vtkGetStringMacro(PointIdArrayName);
-  vtkSetStringMacro(CellIdArrayName);
-  vtkGetStringMacro(CellIdArrayName);
-  ///@}
-
-  ///@{
-  /**
-   * If this class should override the process id using a data-array,
-   * set this variable to the name of the array to use. It must be a
-   * point-array.
-   * The array's DataType *MUST* be VTK_UNSIGNED_INT.
-   */
-  vtkSetStringMacro(ProcessIdArrayName);
-  vtkGetStringMacro(ProcessIdArrayName);
-  ///@}
-
-  ///@{
-  /**
-   * Generally, this class can render the composite id when iterating
-   * over composite datasets. However in some cases (as in AMR), the rendered
-   * structure may not correspond to the input data, in which case we need
-   * to provide a cell array that can be used to render in the composite id in
-   * selection passes. Set to NULL (default) to not override the composite id
-   * color set by vtkCompositePainter if any.
-   * The array *MUST* be a cell array.
-   * The array's DataType *MUST* be VTK_UNSIGNED_INT.
-   */
-  vtkSetStringMacro(CompositeIdArrayName);
-  vtkGetStringMacro(CompositeIdArrayName);
-  ///@}
-
   /**
    * Make a shallow copy of this mapper.
    */
@@ -460,12 +421,6 @@ protected:
   std::vector<unsigned char> EdgeValues;
   virtual bool DrawingEdges(vtkRenderer*, vtkActor*);
 
-  // additional picking indirection
-  char* PointIdArrayName;
-  char* CellIdArrayName;
-  char* ProcessIdArrayName;
-  char* CompositeIdArrayName;
-
   class ExtraAttributeValue
   {
   public:
diff --git a/Rendering/WebGPU/Private/vtkWebGPURenderPassDescriptorInternals.cxx b/Rendering/WebGPU/Private/vtkWebGPURenderPassDescriptorInternals.cxx
index 789ea8bfe7a60d2ce80795d0a263d4f9f6f4af5d..aa6d8d738bae8e6d20651681a5e56256e7f990c2 100644
--- a/Rendering/WebGPU/Private/vtkWebGPURenderPassDescriptorInternals.cxx
+++ b/Rendering/WebGPU/Private/vtkWebGPURenderPassDescriptorInternals.cxx
@@ -9,21 +9,24 @@ vtkWebGPURenderPassDescriptorInternals::~vtkWebGPURenderPassDescriptorInternals(
 //------------------------------------------------------------------------------
 vtkWebGPURenderPassDescriptorInternals::vtkWebGPURenderPassDescriptorInternals(
   const std::vector<wgpu::TextureView>& colorAttachmentInfo,
-  wgpu::TextureView depthStencil /*= wgpu::TextureView()*/, bool doClear /*= true*/)
+  wgpu::TextureView depthStencil /*= wgpu::TextureView()*/, bool clearColor /*= true*/,
+  bool clearDepth /*= true*/, bool clearStencil /*= true*/)
 {
-  wgpu::LoadOp loadOp = doClear ? wgpu::LoadOp::Clear : wgpu::LoadOp::Load;
+  const wgpu::LoadOp colorLoadOp = clearColor ? wgpu::LoadOp::Clear : wgpu::LoadOp::Load;
   for (uint32_t i = 0; i < kMaxColorAttachments; ++i)
   {
-    this->ColorAttachments[i].loadOp = loadOp;
+    this->ColorAttachments[i].loadOp = colorLoadOp;
     this->ColorAttachments[i].storeOp = wgpu::StoreOp::Store;
     this->ColorAttachments[i].clearValue = { 0.0f, 0.0f, 0.0f, 0.0f };
   }
 
+  const wgpu::LoadOp depthLoadOp = clearDepth ? wgpu::LoadOp::Clear : wgpu::LoadOp::Load;
+  const wgpu::LoadOp stencilLoadOp = clearStencil ? wgpu::LoadOp::Clear : wgpu::LoadOp::Load;
   this->DepthStencilAttachmentInfo.depthClearValue = 1.0f;
   this->DepthStencilAttachmentInfo.stencilClearValue = 0;
-  this->DepthStencilAttachmentInfo.depthLoadOp = loadOp;
+  this->DepthStencilAttachmentInfo.depthLoadOp = depthLoadOp;
   this->DepthStencilAttachmentInfo.depthStoreOp = wgpu::StoreOp::Store;
-  this->DepthStencilAttachmentInfo.stencilLoadOp = loadOp;
+  this->DepthStencilAttachmentInfo.stencilLoadOp = stencilLoadOp;
   this->DepthStencilAttachmentInfo.stencilStoreOp = wgpu::StoreOp::Store;
 
   colorAttachmentCount = static_cast<uint32_t>(colorAttachmentInfo.size());
diff --git a/Rendering/WebGPU/Private/vtkWebGPURenderPassDescriptorInternals.h b/Rendering/WebGPU/Private/vtkWebGPURenderPassDescriptorInternals.h
index 428ed8d0b9d8168a29c88eb992d5c3e251edf074..6915ffdb6f4a9268b25c9be6c93ad107bc796a00 100644
--- a/Rendering/WebGPU/Private/vtkWebGPURenderPassDescriptorInternals.h
+++ b/Rendering/WebGPU/Private/vtkWebGPURenderPassDescriptorInternals.h
@@ -16,7 +16,8 @@ class VTKRENDERINGWEBGPU_NO_EXPORT vtkWebGPURenderPassDescriptorInternals
 public:
   static constexpr int kMaxColorAttachments = 8u;
   vtkWebGPURenderPassDescriptorInternals(const std::vector<wgpu::TextureView>& colorAttachmentInfo,
-    wgpu::TextureView depthStencil = wgpu::TextureView(), bool doClear = true);
+    wgpu::TextureView depthStencil = wgpu::TextureView(), bool clearColor = true,
+    bool clearDepth = true, bool clearStencil = true);
   ~vtkWebGPURenderPassDescriptorInternals();
 
   vtkWebGPURenderPassDescriptorInternals(
diff --git a/Rendering/WebGPU/Testing/Cxx/CMakeLists.txt b/Rendering/WebGPU/Testing/Cxx/CMakeLists.txt
index 8c4eccbbb5bf03a278c5c57b75b911173aa86086..378ba559e96913e8a0a23e106182f5ac3088016a 100644
--- a/Rendering/WebGPU/Testing/Cxx/CMakeLists.txt
+++ b/Rendering/WebGPU/Testing/Cxx/CMakeLists.txt
@@ -14,6 +14,7 @@ endif ()
 # (vtk/vtk#19322): Add baselines for these unit tests
 vtk_add_test_cxx(vtkRenderingWebGPUCxxTests tests
   TestActorFaceCullingProperty.cxx,NO_DATA
+  TestAxesActor.cxx,NO_DATA
   TestCellScalarMappedColors.cxx,NO_DATA
   TestCompositePolyDataMapper.cxx,NO_DATA
   TestComputeDoublePipelineRenderBuffer.cxx,NO_DATA
@@ -34,7 +35,12 @@ vtk_add_test_cxx(vtkRenderingWebGPUCxxTests tests
   TestComputeTexture.cxx,NO_DATA,NO_VALID
   TestLineRendering.cxx,NO_DATA
   TestLowPowerRenderWindow.cxx,NO_DATA
-  TestManyActorsOneMapper.cxx,NO_DATA,NO_VALID
+  TestNActorsNMappersOneInput.cxx,NO_DATA
+  TestNActorsOneMapper.cxx,NO_DATA
+  TestNViewportsNActorsNMappersNInputs.cxx,NO_DATA
+  TestNViewportsNActorsNMappersOneInput.cxx,NO_DATA
+  TestNViewportsNActorsOneMapper.cxx,NO_DATA
+  TestNViewportsOneActor.cxx,NO_DATA
   TestPointScalarMappedColors.cxx,NO_DATA
   TestReadPixels.cxx,NO_DATA,NO_VALID
   TestRenderPointsAsSpheres.cxx,NO_DATA
diff --git a/Rendering/WebGPU/Testing/Cxx/TestAxesActor.cxx b/Rendering/WebGPU/Testing/Cxx/TestAxesActor.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..8467ec41c30bda48e1c945b96f09747e7a23427b
--- /dev/null
+++ b/Rendering/WebGPU/Testing/Cxx/TestAxesActor.cxx
@@ -0,0 +1,65 @@
+// SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
+// SPDX-License-Identifier: BSD-3-Clause
+
+#include "vtkActor.h"
+#include "vtkAxesActor.h"
+#include "vtkCamera.h"
+#include "vtkConeSource.h"
+#include "vtkNew.h"
+#include "vtkOrientationMarkerWidget.h"
+#include "vtkPolyDataMapper.h"
+#include "vtkProperty.h"
+#include "vtkRegressionTestImage.h"
+#include "vtkRenderWindow.h"
+#include "vtkRenderWindowInteractor.h"
+#include "vtkRenderer.h"
+
+//------------------------------------------------------------------------------
+int TestAxesActor(int argc, char* argv[])
+{
+  vtkNew<vtkRenderer> renderer;
+  renderer->SetBackground(0.1, 0.1, 0.1);
+
+  vtkNew<vtkRenderWindow> renderWindow;
+  renderWindow->SetSize(800, 800);
+  renderWindow->AddRenderer(renderer);
+
+  vtkNew<vtkRenderWindowInteractor> iren;
+  iren->SetRenderWindow(renderWindow);
+
+  vtkNew<vtkConeSource> cone;
+  // map elevation output to graphics primitives.
+  vtkNew<vtkPolyDataMapper> mapper;
+  // mapper->SetLookupTable(lut);
+  mapper->SetInputConnection(cone->GetOutputPort());
+  vtkNew<vtkActor> actor;
+  actor->SetMapper(mapper);
+  renderer->AddActor(actor);
+
+  vtkNew<vtkAxesActor> axes;
+  axes->SetShaftTypeToCylinder();
+  axes->SetNormalizedTipLength(0.4, 0.4, 0.4);
+  // FIXME: the vtkCaptionActor2D does not render text with webgpu. An override for
+  // vtkPolyDataMapper2D must be implemented in webgpu.
+  // https://gitlab.kitware.com/vtk/vtk/-/issues/19551
+  axes->SetAxisLabels(false);
+  vtkNew<vtkOrientationMarkerWidget> om;
+  om->SetOrientationMarker(axes);
+  om->SetInteractor(iren);
+  om->EnabledOn();
+  om->InteractiveOn();
+
+  renderer->ResetCamera();
+  renderer->GetActiveCamera()->Azimuth(45);
+  renderer->GetActiveCamera()->Elevation(45);
+  renderer->GetActiveCamera()->OrthogonalizeViewUp();
+  renderWindow->Render();
+
+  int retVal = vtkRegressionTestImageThreshold(renderWindow, 0.05);
+  if (retVal == vtkRegressionTester::DO_INTERACTOR)
+  {
+    iren->Start();
+  }
+
+  return !retVal;
+}
diff --git a/Rendering/WebGPU/Testing/Cxx/TestNActorsNMappersOneInput.cxx b/Rendering/WebGPU/Testing/Cxx/TestNActorsNMappersOneInput.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..bc570306cfaf2ee25e6b4c06c3bc91ced9dd39e7
--- /dev/null
+++ b/Rendering/WebGPU/Testing/Cxx/TestNActorsNMappersOneInput.cxx
@@ -0,0 +1,75 @@
+// SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
+// SPDX-License-Identifier: BSD-3-Clause
+#include "vtkActor.h"
+#include "vtkCamera.h"
+#include "vtkConeSource.h"
+#include "vtkInteractorStyleTrackballCamera.h"
+#include "vtkNew.h"
+#include "vtkPolyDataMapper.h"
+#include "vtkProperty.h"
+#include "vtkRegressionTestImage.h"
+#include "vtkRenderWindow.h"
+#include "vtkRenderWindowInteractor.h"
+#include "vtkRenderer.h"
+
+// In this unit test, there are 4 actors, each connected to a mapper. All mappers share a common
+// source.
+int TestNActorsNMappersOneInput(int argc, char* argv[])
+{
+  vtkNew<vtkRenderWindow> renWin;
+  renWin->SetWindowName(__func__);
+  renWin->SetSize(800, 800);
+  renWin->SetMultiSamples(0);
+
+  vtkNew<vtkRenderer> renderer;
+  renderer->SetBackground(1.0, 1.0, 1.0);
+  renWin->AddRenderer(renderer);
+
+  vtkNew<vtkConeSource> cone;
+
+  double x = 0.0, y = 0.0, z = 0.0;
+  double spacingX = 2.0, spacingY = 2.0, spacingZ = 2.0;
+  for (int k = 0; k < 8; ++k)
+  {
+    for (int j = 0; j < 8; ++j)
+    {
+      for (int i = 0; i < 8; ++i)
+      {
+        x += spacingX;
+        vtkNew<vtkPolyDataMapper> mapper;
+        mapper->SetInputConnection(cone->GetOutputPort());
+        vtkNew<vtkActor> actor;
+        actor->SetMapper(mapper);
+        mapper->Update();
+        mapper->SetStatic(1);
+        actor->GetProperty()->SetEdgeVisibility(true);
+        actor->GetProperty()->SetLineWidth(2);
+        actor->GetProperty()->SetEdgeColor((8.0 - j) / 8.0, k / 16.0, i / 8.0);
+        actor->GetProperty()->SetDiffuseColor(i / 8.0, (8.0 - j) / 8.0, k / 16.0);
+        actor->SetPosition(x, y, z);
+        renderer->AddActor(actor);
+      }
+      x = 0.0;
+      y += spacingY;
+    }
+    y = 0.0;
+    z += spacingZ;
+  }
+
+  renderer->ResetCamera();
+  renWin->Render();
+
+  vtkNew<vtkRenderWindowInteractor> iren;
+  iren->SetRenderWindow(renWin);
+  vtkNew<vtkInteractorStyleTrackballCamera> style;
+  iren->SetInteractorStyle(style);
+  style->SetDefaultRenderer(renderer);
+  renWin->Render();
+
+  const int retVal = vtkRegressionTestImage(renWin);
+  if (retVal == vtkRegressionTester::DO_INTERACTOR)
+  {
+    iren->Start();
+  }
+  return !retVal;
+}
diff --git a/Rendering/WebGPU/Testing/Cxx/TestManyActorsOneMapper.cxx b/Rendering/WebGPU/Testing/Cxx/TestNActorsOneMapper.cxx
similarity index 83%
rename from Rendering/WebGPU/Testing/Cxx/TestManyActorsOneMapper.cxx
rename to Rendering/WebGPU/Testing/Cxx/TestNActorsOneMapper.cxx
index 3a34225c7b663893c71897d3d93a48a8b6137e72..cafa9d68125048d350c8e6aa0ddaea3f4ed86fa4 100644
--- a/Rendering/WebGPU/Testing/Cxx/TestManyActorsOneMapper.cxx
+++ b/Rendering/WebGPU/Testing/Cxx/TestNActorsOneMapper.cxx
@@ -12,13 +12,16 @@
 #include "vtkRenderWindowInteractor.h"
 #include "vtkRenderer.h"
 
-int TestManyActorsOneMapper(int argc, char* argv[])
+// In this unit test, there are 4 actors. All share a common mapper.
+int TestNActorsOneMapper(int argc, char* argv[])
 {
   vtkNew<vtkRenderWindow> renWin;
   renWin->SetWindowName(__func__);
+  renWin->SetSize(800, 800);
   renWin->SetMultiSamples(0);
 
   vtkNew<vtkRenderer> renderer;
+  renderer->SetBackground(1.0, 1.0, 1.0);
   renWin->AddRenderer(renderer);
 
   vtkNew<vtkConeSource> cone;
@@ -40,7 +43,8 @@ int TestManyActorsOneMapper(int argc, char* argv[])
         mapper->SetStatic(1);
         actor->GetProperty()->SetEdgeVisibility(true);
         actor->GetProperty()->SetLineWidth(2);
-        actor->GetProperty()->SetEdgeColor(1.0, 0.0, 0.0);
+        actor->GetProperty()->SetEdgeColor((8.0 - j) / 8.0, k / 16.0, i / 8.0);
+        actor->GetProperty()->SetDiffuseColor(i / 8.0, (8.0 - j) / 8.0, k / 16.0);
         actor->SetPosition(x, y, z);
         renderer->AddActor(actor);
       }
@@ -52,7 +56,6 @@ int TestManyActorsOneMapper(int argc, char* argv[])
   }
 
   renderer->ResetCamera();
-  renderer->SetBackground(0.1, 0.1, 0.1);
   renWin->Render();
 
   vtkNew<vtkRenderWindowInteractor> iren;
diff --git a/Rendering/WebGPU/Testing/Cxx/TestNViewportsNActorsNMappersNInputs.cxx b/Rendering/WebGPU/Testing/Cxx/TestNViewportsNActorsNMappersNInputs.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..51a237b0e59811a00645f6a354415cc07481f90f
--- /dev/null
+++ b/Rendering/WebGPU/Testing/Cxx/TestNViewportsNActorsNMappersNInputs.cxx
@@ -0,0 +1,54 @@
+// SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
+// SPDX-License-Identifier: BSD-3-Clause
+
+#include "vtkActor.h"
+#include "vtkCompositePolyDataMapper.h"
+#include "vtkPartitionedDataSetCollectionSource.h"
+#include "vtkProperty.h"
+#include "vtkRegressionTestImage.h"
+#include "vtkRenderWindow.h"
+#include "vtkRenderWindowInteractor.h"
+#include "vtkRenderer.h"
+#include "vtkTesting.h"
+
+#include <cstdlib>
+
+// In this unit test, there are 4 viewports. Each viewport displays an actor
+// that is connected to a mapper which is then connected to a partitioned dataset collection source
+// which has as many shapes as the index of the mapper.
+int TestNViewportsNActorsNMappersNInputs(int argc, char* argv[])
+{
+  vtkNew<vtkRenderWindow> renderWindow;
+  vtkNew<vtkRenderWindowInteractor> interactor;
+  vtkNew<vtkRenderer> renderers[4];
+
+  double xmins[4] = { 0.0, 0.4, 0.0, 0.0 };
+  double ymins[4] = { 0.0, 0.0, 0.25, 0.5 };
+  double xmaxs[4] = { 0.4, 1.0, 1.0, 1.0 };
+  double ymaxs[4] = { 0.25, 0.25, 0.5, 1.0 };
+  for (int i = 0; i < 4; ++i)
+  {
+    auto ren = renderers[i].Get();
+    vtkNew<vtkPartitionedDataSetCollectionSource> source;
+    source->SetNumberOfShapes(i + 1); // generates i + 1 shapes.
+    vtkNew<vtkCompositePolyDataMapper> mapper;
+    mapper->SetInputConnection(source->GetOutputPort());
+    vtkNew<vtkActor> actor;
+    actor->SetMapper(mapper);
+    actor->GetProperty()->SetDiffuseColor(0.5, i / 4.0, (4.0 - i) / 4);
+    ren->AddActor(actor);
+    ren->SetBackground(i / 4.0, (4.0 - i) / 4, 1);
+    ren->SetViewport(xmins[i], ymins[i], xmaxs[i], ymaxs[i]);
+    renderWindow->AddRenderer(ren);
+  }
+  renderWindow->SetSize(800, 800);
+  renderWindow->SetInteractor(interactor);
+  interactor->Initialize();
+
+  const int retVal = vtkRegressionTestImage(renderWindow);
+  if (retVal == vtkRegressionTester::DO_INTERACTOR)
+  {
+    interactor->Start();
+  }
+  return !retVal;
+}
diff --git a/Rendering/WebGPU/Testing/Cxx/TestNViewportsNActorsNMappersOneInput.cxx b/Rendering/WebGPU/Testing/Cxx/TestNViewportsNActorsNMappersOneInput.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..80f714224e5bff2772838d988d09eb85ca068242
--- /dev/null
+++ b/Rendering/WebGPU/Testing/Cxx/TestNViewportsNActorsNMappersOneInput.cxx
@@ -0,0 +1,52 @@
+// SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
+// SPDX-License-Identifier: BSD-3-Clause
+
+#include "vtkActor.h"
+#include "vtkConeSource.h"
+#include "vtkPolyDataMapper.h"
+#include "vtkProperty.h"
+#include "vtkRegressionTestImage.h"
+#include "vtkRenderWindow.h"
+#include "vtkRenderWindowInteractor.h"
+#include "vtkRenderer.h"
+#include "vtkTesting.h"
+
+#include <cstdlib>
+
+// In this unit test, there are 4 viewports. Each viewport displays an actor
+// that is connected to a mapper. All mappers share a common cone source.
+int TestNViewportsNActorsNMappersOneInput(int argc, char* argv[])
+{
+  vtkNew<vtkRenderWindow> renderWindow;
+  vtkNew<vtkRenderWindowInteractor> interactor;
+  vtkNew<vtkRenderer> renderers[4];
+  vtkNew<vtkConeSource> cone;
+
+  double xmins[4] = { 0.0, 0.4, 0.0, 0.0 };
+  double ymins[4] = { 0.0, 0.0, 0.25, 0.5 };
+  double xmaxs[4] = { 0.4, 1.0, 1.0, 1.0 };
+  double ymaxs[4] = { 0.25, 0.25, 0.5, 1.0 };
+  for (int i = 0; i < 4; ++i)
+  {
+    auto ren = renderers[i].Get();
+    vtkNew<vtkPolyDataMapper> mapper;
+    mapper->SetInputConnection(cone->GetOutputPort());
+    vtkNew<vtkActor> actor;
+    actor->SetMapper(mapper);
+    actor->GetProperty()->SetDiffuseColor(0.5, i / 4.0, (4.0 - i) / 4);
+    ren->AddActor(actor);
+    ren->SetBackground(i / 4.0, (4.0 - i) / 4, 1);
+    ren->SetViewport(xmins[i], ymins[i], xmaxs[i], ymaxs[i]);
+    renderWindow->AddRenderer(ren);
+  }
+  renderWindow->SetSize(800, 800);
+  renderWindow->SetInteractor(interactor);
+  interactor->Initialize();
+
+  const int retVal = vtkRegressionTestImage(renderWindow);
+  if (retVal == vtkRegressionTester::DO_INTERACTOR)
+  {
+    interactor->Start();
+  }
+  return !retVal;
+}
diff --git a/Rendering/WebGPU/Testing/Cxx/TestNViewportsNActorsOneMapper.cxx b/Rendering/WebGPU/Testing/Cxx/TestNViewportsNActorsOneMapper.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..ab6047fedc847f7bb6ad0c132a6e6583e29c16cd
--- /dev/null
+++ b/Rendering/WebGPU/Testing/Cxx/TestNViewportsNActorsOneMapper.cxx
@@ -0,0 +1,52 @@
+// SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
+// SPDX-License-Identifier: BSD-3-Clause
+
+#include "vtkActor.h"
+#include "vtkConeSource.h"
+#include "vtkPolyDataMapper.h"
+#include "vtkProperty.h"
+#include "vtkRegressionTestImage.h"
+#include "vtkRenderWindow.h"
+#include "vtkRenderWindowInteractor.h"
+#include "vtkRenderer.h"
+#include "vtkTesting.h"
+
+#include <cstdlib>
+
+// In this unit test, there are 4 viewports. Each viewport displays an actor.
+// All actors share a common mapper.
+int TestNViewportsNActorsOneMapper(int argc, char* argv[])
+{
+  vtkNew<vtkRenderWindow> renderWindow;
+  vtkNew<vtkRenderWindowInteractor> interactor;
+  vtkNew<vtkRenderer> renderers[4];
+  vtkNew<vtkConeSource> cone;
+  vtkNew<vtkPolyDataMapper> mapper;
+
+  mapper->SetInputConnection(cone->GetOutputPort());
+  double xmins[4] = { 0.0, 0.4, 0.0, 0.0 };
+  double ymins[4] = { 0.0, 0.0, 0.25, 0.5 };
+  double xmaxs[4] = { 0.4, 1.0, 1.0, 1.0 };
+  double ymaxs[4] = { 0.25, 0.25, 0.5, 1.0 };
+  for (int i = 0; i < 4; ++i)
+  {
+    auto ren = renderers[i].Get();
+    vtkNew<vtkActor> actor;
+    actor->SetMapper(mapper);
+    actor->GetProperty()->SetDiffuseColor(0.5, i / 4.0, (4.0 - i) / 4);
+    ren->AddActor(actor);
+    ren->SetBackground(i / 4.0, (4.0 - i) / 4, 1);
+    ren->SetViewport(xmins[i], ymins[i], xmaxs[i], ymaxs[i]);
+    renderWindow->AddRenderer(ren);
+  }
+  renderWindow->SetSize(800, 800);
+  renderWindow->SetInteractor(interactor);
+  interactor->Initialize();
+
+  const int retVal = vtkRegressionTestImage(renderWindow);
+  if (retVal == vtkRegressionTester::DO_INTERACTOR)
+  {
+    interactor->Start();
+  }
+  return !retVal;
+}
diff --git a/Rendering/WebGPU/Testing/Cxx/TestNViewportsOneActor.cxx b/Rendering/WebGPU/Testing/Cxx/TestNViewportsOneActor.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..cfbcd581b273bbd9091d55d483ad9ff3611828c3
--- /dev/null
+++ b/Rendering/WebGPU/Testing/Cxx/TestNViewportsOneActor.cxx
@@ -0,0 +1,50 @@
+// SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
+// SPDX-License-Identifier: BSD-3-Clause
+
+#include "vtkActor.h"
+#include "vtkConeSource.h"
+#include "vtkPolyDataMapper.h"
+#include "vtkRegressionTestImage.h"
+#include "vtkRenderWindow.h"
+#include "vtkRenderWindowInteractor.h"
+#include "vtkRenderer.h"
+#include "vtkTesting.h"
+
+#include <cstdlib>
+
+// In this unit test, there are 4 viewports.
+// All viewports display the same actor.
+int TestNViewportsOneActor(int argc, char* argv[])
+{
+  vtkNew<vtkRenderWindow> renderWindow;
+  vtkNew<vtkRenderWindowInteractor> interactor;
+  vtkNew<vtkRenderer> renderers[4];
+  vtkNew<vtkConeSource> cone;
+  vtkNew<vtkPolyDataMapper> mapper;
+  vtkNew<vtkActor> actor;
+  actor->SetMapper(mapper);
+
+  mapper->SetInputConnection(cone->GetOutputPort());
+  double xmins[4] = { 0.0, 0.4, 0.0, 0.0 };
+  double ymins[4] = { 0.0, 0.0, 0.25, 0.5 };
+  double xmaxs[4] = { 0.4, 1.0, 1.0, 1.0 };
+  double ymaxs[4] = { 0.25, 0.25, 0.5, 1.0 };
+  for (int i = 0; i < 4; ++i)
+  {
+    auto ren = renderers[i].Get();
+    ren->AddActor(actor);
+    ren->SetBackground(i / 4.0, (4.0 - i) / 4, 1);
+    ren->SetViewport(xmins[i], ymins[i], xmaxs[i], ymaxs[i]);
+    renderWindow->AddRenderer(ren);
+  }
+  renderWindow->SetSize(800, 800);
+  renderWindow->SetInteractor(interactor);
+  interactor->Initialize();
+
+  const int retVal = vtkRegressionTestImage(renderWindow);
+  if (retVal == vtkRegressionTester::DO_INTERACTOR)
+  {
+    interactor->Start();
+  }
+  return !retVal;
+}
diff --git a/Rendering/WebGPU/Testing/Cxx/TestReadPixels.cxx b/Rendering/WebGPU/Testing/Cxx/TestReadPixels.cxx
index c3f8858460224e00eeef5aeb702556f5fd72e034..bf1e409a8e1c69bd98425da49ab2cb83084fbb76 100644
--- a/Rendering/WebGPU/Testing/Cxx/TestReadPixels.cxx
+++ b/Rendering/WebGPU/Testing/Cxx/TestReadPixels.cxx
@@ -53,13 +53,13 @@ int TestReadPixels(int, char*[])
   VTK_TEST_READ_PIXELS(ucharTuple[0] == 100);
   VTK_TEST_READ_PIXELS(ucharTuple[1] == 110);
   VTK_TEST_READ_PIXELS(ucharTuple[2] == 120);
-  VTK_TEST_READ_PIXELS(ucharTuple[3] == 255);
+  VTK_TEST_READ_PIXELS(ucharTuple[3] == 0);
 
   ucharRGBA->GetTypedTuple(299 * 299, ucharTuple);
   VTK_TEST_READ_PIXELS(ucharTuple[0] == 100);
   VTK_TEST_READ_PIXELS(ucharTuple[1] == 110);
   VTK_TEST_READ_PIXELS(ucharTuple[2] == 120);
-  VTK_TEST_READ_PIXELS(ucharTuple[3] == 255);
+  VTK_TEST_READ_PIXELS(ucharTuple[3] == 0);
 
   // Verify background color as normalized float32 RGBA values
   vtkNew<vtkFloatArray> f32RGBA;
@@ -68,12 +68,12 @@ int TestReadPixels(int, char*[])
   VTK_TEST_READ_PIXELS(static_cast<int>(f32RGBA->GetTuple(0)[0] * 255) == 100);
   VTK_TEST_READ_PIXELS(static_cast<int>(f32RGBA->GetTuple(0)[1] * 255) == 110);
   VTK_TEST_READ_PIXELS(static_cast<int>(f32RGBA->GetTuple(0)[2] * 255) == 120);
-  VTK_TEST_READ_PIXELS(static_cast<int>(f32RGBA->GetTuple(0)[3] * 255) == 255);
+  VTK_TEST_READ_PIXELS(static_cast<int>(f32RGBA->GetTuple(0)[3] * 255) == 0);
 
   VTK_TEST_READ_PIXELS(static_cast<int>(f32RGBA->GetTuple(299)[0] * 255) == 100);
   VTK_TEST_READ_PIXELS(static_cast<int>(f32RGBA->GetTuple(299)[1] * 255) == 110);
   VTK_TEST_READ_PIXELS(static_cast<int>(f32RGBA->GetTuple(299)[2] * 255) == 120);
-  VTK_TEST_READ_PIXELS(static_cast<int>(f32RGBA->GetTuple(299)[3] * 255) == 255);
+  VTK_TEST_READ_PIXELS(static_cast<int>(f32RGBA->GetTuple(299)[3] * 255) == 0);
 
   // Verify background color as unsigned char RGB values
   vtkNew<vtkUnsignedCharArray> ucharRGB;
diff --git a/Rendering/WebGPU/Testing/Data/Baseline/TestActorFaceCullingProperty.png.sha512 b/Rendering/WebGPU/Testing/Data/Baseline/TestActorFaceCullingProperty.png.sha512
index 6658b637354231aa81e73cd26988b0645e238805..b413346ccaa9c3726f79d0fcfe360345d89568a0 100644
--- a/Rendering/WebGPU/Testing/Data/Baseline/TestActorFaceCullingProperty.png.sha512
+++ b/Rendering/WebGPU/Testing/Data/Baseline/TestActorFaceCullingProperty.png.sha512
@@ -1 +1 @@
-c1e634e12d7cc3272cfab7ea4072441803d1a0893cad1c5768abc33e0f12dbc44c365f64fedab5d72e92895705e3b1ead17816662cd955a10090032cc7ebce80
+0881aed8e7ce2111245509ce0b1ed4d9400f7ad6a74d3b72f93fb144df3ec42db7a0f774540b138cc52adfc4873b757dd7a5a49c0fe49422d589cd26faf0b27a
diff --git a/Rendering/WebGPU/Testing/Data/Baseline/TestAxesActor.png.sha512 b/Rendering/WebGPU/Testing/Data/Baseline/TestAxesActor.png.sha512
new file mode 100644
index 0000000000000000000000000000000000000000..27b819d0c3790109b7fef214dd305c1f8c4eb9a9
--- /dev/null
+++ b/Rendering/WebGPU/Testing/Data/Baseline/TestAxesActor.png.sha512
@@ -0,0 +1 @@
+886465c51a5139ff595b17bbde3a13fd90fe355aaeeae771ac075a97e6ffc424787870464929ead886dc9beac5a9361a5f49644112c5b10bafd076a0e82a4432
diff --git a/Rendering/WebGPU/Testing/Data/Baseline/TestCellScalarMappedColors.png.sha512 b/Rendering/WebGPU/Testing/Data/Baseline/TestCellScalarMappedColors.png.sha512
index 44aad9b8c698c44283e2c56188ccec31bc21ebc2..71b9fd7af39b0f3d4372f918bd784ee5a4e8bb5d 100644
--- a/Rendering/WebGPU/Testing/Data/Baseline/TestCellScalarMappedColors.png.sha512
+++ b/Rendering/WebGPU/Testing/Data/Baseline/TestCellScalarMappedColors.png.sha512
@@ -1 +1 @@
-5c61da1a5e627f69e222ac01c30ef7ade58462eb99838a268f5970d8485de10e17d558e90378aa492bf2371b72d3098f5dc4d446da48c52cff3100f730a350eb
+1cb666a1e9287f450d66fabba6212fd88f1b494ae54f5e92c06d639c5c40d6b89aa6c72a10b2d0e0ff7cd29f23b75714f48b874838c7ee9e91633f7953bd3567
diff --git a/Rendering/WebGPU/Testing/Data/Baseline/TestComputeDoublePipelineRenderBuffer.png.sha512 b/Rendering/WebGPU/Testing/Data/Baseline/TestComputeDoublePipelineRenderBuffer.png.sha512
index a6153df495357572175fa750891e96f31a9dff1f..c17909de3e81420cbbfadf4b3679f26ecc623cf8 100644
--- a/Rendering/WebGPU/Testing/Data/Baseline/TestComputeDoublePipelineRenderBuffer.png.sha512
+++ b/Rendering/WebGPU/Testing/Data/Baseline/TestComputeDoublePipelineRenderBuffer.png.sha512
@@ -1 +1 @@
-38e8af3e7c0de9fce3baeb82f242bc277721930a1f4b2f927788a6dd19786d5311cefc46d6c0328cebf5269d0fc81e77235d3fdd460add6c4b7f52619c667344
+9a2618f6fb336a10be5a4557db4c6b03bad73431201798ed47e94c8c9c09a98c22204382062ddc72005c454f3a730a74fef0e7493f9f3d78816f3a2eb4297018
diff --git a/Rendering/WebGPU/Testing/Data/Baseline/TestComputeModifyCellColors.png.sha512 b/Rendering/WebGPU/Testing/Data/Baseline/TestComputeModifyCellColors.png.sha512
index c56a25fb43ee8be48e0c36dc9a27d56adf584159..14e1e503fc9c464baa432339a71e265efe3bc8e5 100644
--- a/Rendering/WebGPU/Testing/Data/Baseline/TestComputeModifyCellColors.png.sha512
+++ b/Rendering/WebGPU/Testing/Data/Baseline/TestComputeModifyCellColors.png.sha512
@@ -1 +1 @@
-2d12adc4a72f82289906c7397a9a7e7dc0a0a9b24fd623e847ce2640d308b145d2b26e72796f8b92a9bc5c357081e915435de059ec63b772144b8ea034cdf87c
+8ca4501aed167f882e5742d2f5c89e4a58c9a02498c5766c0cc2a192ad26534f37b1b900c5b3d642f069c745ae12e2897b80269b2f19191aeb39babb01009f5c
diff --git a/Rendering/WebGPU/Testing/Data/Baseline/TestComputeModifyPointColors.png.sha512 b/Rendering/WebGPU/Testing/Data/Baseline/TestComputeModifyPointColors.png.sha512
index 6a3d36c2d25b54f67cd6c8f75e87a7193f3cb0d3..979b8fec1e2094c50293f7bfd914a50637fc8fad 100644
--- a/Rendering/WebGPU/Testing/Data/Baseline/TestComputeModifyPointColors.png.sha512
+++ b/Rendering/WebGPU/Testing/Data/Baseline/TestComputeModifyPointColors.png.sha512
@@ -1 +1 @@
-02d4b7e76ac468c9f57c3d3fd57e91be28108279311a2e64e5d76cdb76990549d5d0ff2a85b04130c7d0f58e4efe60ebc5369c7f82aeb77de84cf3f0a659d339
+15f41b07ddb55503627fecc1a1c400da3a24f2577834f800257b5d7b8870b2e43a485c6009b6c5bf46034a330db402391d8968fa9828f0b8770ed4e36483b09b
diff --git a/Rendering/WebGPU/Testing/Data/Baseline/TestComputePointCloudMapperColors.png.sha512 b/Rendering/WebGPU/Testing/Data/Baseline/TestComputePointCloudMapperColors.png.sha512
index 5a1268059c1832c90c4c3d656ea0e8bac20d6461..c2227cf2e339d9f70f3ca6a49bd43572c2891103 100644
--- a/Rendering/WebGPU/Testing/Data/Baseline/TestComputePointCloudMapperColors.png.sha512
+++ b/Rendering/WebGPU/Testing/Data/Baseline/TestComputePointCloudMapperColors.png.sha512
@@ -1 +1 @@
-deb0401974b7dcd09b3f7a1f4f1db3ec002e3c41d987fc8fcd2a5a280955e4a72528cc8c981ed7964011511d46c5c64e8fa705fc6ac19ff878acca457addabb2
+61fa867e1067095520724ba2f4f3185dbecac2ebe4b1b587054797c55cb1934bcec68e748ca600d663598affda84bb9961254fb4aae5edebae91c62d81b4792a
diff --git a/Rendering/WebGPU/Testing/Data/Baseline/TestComputePointCloudMapperDepth.png.sha512 b/Rendering/WebGPU/Testing/Data/Baseline/TestComputePointCloudMapperDepth.png.sha512
index cee7e21627fd64d05f78c2144aa628cf7451e37a..4843614a2971eff0a61f47b49c938d849bf161df 100644
--- a/Rendering/WebGPU/Testing/Data/Baseline/TestComputePointCloudMapperDepth.png.sha512
+++ b/Rendering/WebGPU/Testing/Data/Baseline/TestComputePointCloudMapperDepth.png.sha512
@@ -1 +1 @@
-704bd115593340117ba08f93ba65b1da53d5c2e3eaa6aaefab29eceb99cf9335d1749711963b4975af5f1b4425ddd6efdde2701d792ec20866c63e3c66468aa3
+6a60a66a20b4d48e8c124a28360f4cf8030da70a5416ca75f7e3e94f6afc531c5ae899a5923cf4352225400a844b79827d2db37431ec04000b561dd53fa2befa
diff --git a/Rendering/WebGPU/Testing/Data/Baseline/TestComputePointCloudMapperGeometry.png.sha512 b/Rendering/WebGPU/Testing/Data/Baseline/TestComputePointCloudMapperGeometry.png.sha512
index b7fd061be53992023cd8a31fc090a7f171475201..e3b9cd02cf94488c7cb8302955476386158ecef0 100644
--- a/Rendering/WebGPU/Testing/Data/Baseline/TestComputePointCloudMapperGeometry.png.sha512
+++ b/Rendering/WebGPU/Testing/Data/Baseline/TestComputePointCloudMapperGeometry.png.sha512
@@ -1 +1 @@
-5814217c48a8044b617c3197c642380aa038347a17d17d1e1802f44700507f39f28ef517c6de8681d9c66663820477125a91003a59b77826049ef1be1292c310
+7cb81a40d3d1cf88b305b6d35e21079494664374e188eaa67f937bc903bcd52c3591021f2afdde44663b121d28aed133a52c2c2204cf5ffd75c14662d56e745b
diff --git a/Rendering/WebGPU/Testing/Data/Baseline/TestLineRendering.png.sha512 b/Rendering/WebGPU/Testing/Data/Baseline/TestLineRendering.png.sha512
index 9c6721265c895841c35b36eb64a9df2afc147c0f..2de791bf1685283fdf93d6a3ef29d5e7398bc2e9 100644
--- a/Rendering/WebGPU/Testing/Data/Baseline/TestLineRendering.png.sha512
+++ b/Rendering/WebGPU/Testing/Data/Baseline/TestLineRendering.png.sha512
@@ -1 +1 @@
-472dca61286c099be50129b5c5c2d8767e96fdf4f8cbd11867064524f82258320458719f9bedd949c6c4c91d49e8e6eae97cb3070658944b2d5b4e2ad7e977dc
+2beffd3799e6c0b9b4d56b7508efd86d91124d6282b8ed993b68c36369f8d2d25b40d66945517b0698f3d015523131d949d4d2a2af888a422a5c1b8cb078c5e7
diff --git a/Rendering/WebGPU/Testing/Data/Baseline/TestLineRenderingTranslucent.png.sha512 b/Rendering/WebGPU/Testing/Data/Baseline/TestLineRenderingTranslucent.png.sha512
index a00e8ae2dae91c85bb91136fa04083fb1b7b2e54..8ac494e15313bbc65cce61bbeeca11274f7ec7e1 100644
--- a/Rendering/WebGPU/Testing/Data/Baseline/TestLineRenderingTranslucent.png.sha512
+++ b/Rendering/WebGPU/Testing/Data/Baseline/TestLineRenderingTranslucent.png.sha512
@@ -1 +1 @@
-a96b4282a009fe27a75b2ac2af60a87446d089b10cdda4d84daca579bfbb9664b79eed7c9c91e94932f77085ce9cf12273602c21e77af1a10c26cdd3bc4b92f2
+5f510959aa0a84d2aaf009b78feb250ba07745146228eb37f1b945fc65f6f3cee9512db620d8af258ab67409adcd2d3d0edfeb7016f5fcbc0ef454ccac545993
diff --git a/Rendering/WebGPU/Testing/Data/Baseline/TestLowPowerRenderWindow.png.sha512 b/Rendering/WebGPU/Testing/Data/Baseline/TestLowPowerRenderWindow.png.sha512
index d7ef5664f4b8944ea7774dd957b98b8f56536397..dfc1b341469cf2450cbf615bad90b9d538c2e067 100644
--- a/Rendering/WebGPU/Testing/Data/Baseline/TestLowPowerRenderWindow.png.sha512
+++ b/Rendering/WebGPU/Testing/Data/Baseline/TestLowPowerRenderWindow.png.sha512
@@ -1 +1 @@
-f111f7ae82d341adecdc19189537997c4243679e88f86fbcb48bc34bb6b95844812e2b3ba85b45664b987818cc47ac0620684d1bb12741b8189d5db24b7be9d9
+583a6e60c700b15874f9642274b3f2526cb2500c40622c7d73e52ddf4a9ef7a783d8f4ee1ba542de511764fd0408a9fc5a72677b85bf930c2524024046110853
diff --git a/Rendering/WebGPU/Testing/Data/Baseline/TestMixedGeometry_1.png.sha512 b/Rendering/WebGPU/Testing/Data/Baseline/TestMixedGeometry_1.png.sha512
index 244725e9c28c2119a2c42a44588795c14c178bd3..c3cdb32a0ecb89d4e70fa08e1f84b868b84adf43 100644
--- a/Rendering/WebGPU/Testing/Data/Baseline/TestMixedGeometry_1.png.sha512
+++ b/Rendering/WebGPU/Testing/Data/Baseline/TestMixedGeometry_1.png.sha512
@@ -1 +1 @@
-3cc8d874194d98165bdf1b5c95661cdf91b288bd943bbc43e5562555b4a5ef488b356d42038ca21ee50ebe5205ce4a5a0075e18f832dd4b7c6f45bcc903c490d
+d2b5aa1a422339f7f1855238c7115424810f0cb5aef51f269d5caf529586166f0add237798ce065093f5dc40cfa4f4a14a9680f615bb8a4c476d99f1c8491446
diff --git a/Rendering/WebGPU/Testing/Data/Baseline/TestMixedGeometry_2.png.sha512 b/Rendering/WebGPU/Testing/Data/Baseline/TestMixedGeometry_2.png.sha512
index 1171c0fa5af9e22f2bc70848d985689e71854f88..c3cdb32a0ecb89d4e70fa08e1f84b868b84adf43 100644
--- a/Rendering/WebGPU/Testing/Data/Baseline/TestMixedGeometry_2.png.sha512
+++ b/Rendering/WebGPU/Testing/Data/Baseline/TestMixedGeometry_2.png.sha512
@@ -1 +1 @@
-804ca7f760436abe04e1cfbe7aa3958153a15f543d571e4f20b22c0e441e85a4a7ddc19ca7bed180837a63273d2baa10f5418f56a1d7d3b30210f981409c5930
+d2b5aa1a422339f7f1855238c7115424810f0cb5aef51f269d5caf529586166f0add237798ce065093f5dc40cfa4f4a14a9680f615bb8a4c476d99f1c8491446
diff --git a/Rendering/WebGPU/Testing/Data/Baseline/TestMixedGeometry_3.png.sha512 b/Rendering/WebGPU/Testing/Data/Baseline/TestMixedGeometry_3.png.sha512
index dd87dac8a11a895e3f5a2ec3b7b6ab0a9a9b2ce2..03c0383943fbb5b5de29dd0a3f2fb786bed34c96 100644
--- a/Rendering/WebGPU/Testing/Data/Baseline/TestMixedGeometry_3.png.sha512
+++ b/Rendering/WebGPU/Testing/Data/Baseline/TestMixedGeometry_3.png.sha512
@@ -1 +1 @@
-dbfc20dc04a072f4edb5d4188869fd1cf07d1fba799c03ebc7d7311a1adce3f935c966c3e5b21c60844e2e1658ca8cc791c8bd983d9b7a6edcc01711fc85a761
+5702f2b1225a8a6ec83586038d170b01f7f7a5c3c770993ff1198c87e36fc496c0c8cd2c3feb80e49f59e8cda74010e12aa395b277d3ba9fef6ca20c81506ce5
diff --git a/Rendering/WebGPU/Testing/Data/Baseline/TestNActorsNMappersOneInput.png.sha512 b/Rendering/WebGPU/Testing/Data/Baseline/TestNActorsNMappersOneInput.png.sha512
new file mode 100644
index 0000000000000000000000000000000000000000..34037e305cd03e54805e59621ab8a2c57c7ea60b
--- /dev/null
+++ b/Rendering/WebGPU/Testing/Data/Baseline/TestNActorsNMappersOneInput.png.sha512
@@ -0,0 +1 @@
+9d9e8df1b7313212f66dcadb977c67a7c2d5a56cefa9bd320a3cbf785ebb4caeac6415450cb1ded117a1151d9574764c405a894beb10a30e9bd67b542f858dd3
diff --git a/Rendering/WebGPU/Testing/Data/Baseline/TestNActorsOneMapper.png.sha512 b/Rendering/WebGPU/Testing/Data/Baseline/TestNActorsOneMapper.png.sha512
new file mode 100644
index 0000000000000000000000000000000000000000..34037e305cd03e54805e59621ab8a2c57c7ea60b
--- /dev/null
+++ b/Rendering/WebGPU/Testing/Data/Baseline/TestNActorsOneMapper.png.sha512
@@ -0,0 +1 @@
+9d9e8df1b7313212f66dcadb977c67a7c2d5a56cefa9bd320a3cbf785ebb4caeac6415450cb1ded117a1151d9574764c405a894beb10a30e9bd67b542f858dd3
diff --git a/Rendering/WebGPU/Testing/Data/Baseline/TestNViewportsNActorsNMappersNInputs.png.sha512 b/Rendering/WebGPU/Testing/Data/Baseline/TestNViewportsNActorsNMappersNInputs.png.sha512
new file mode 100644
index 0000000000000000000000000000000000000000..e143f48c34ee3896e9407b173a358fece9712d54
--- /dev/null
+++ b/Rendering/WebGPU/Testing/Data/Baseline/TestNViewportsNActorsNMappersNInputs.png.sha512
@@ -0,0 +1 @@
+f813c389a7baf1591355b0b0b0ffe73d88b782222e886fcd813cbcdb175da4842b9e84925e5a78e979257e301e3374c9c9f586097e0d0065b29c55acee15df45
diff --git a/Rendering/WebGPU/Testing/Data/Baseline/TestNViewportsNActorsNMappersOneInput.png.sha512 b/Rendering/WebGPU/Testing/Data/Baseline/TestNViewportsNActorsNMappersOneInput.png.sha512
new file mode 100644
index 0000000000000000000000000000000000000000..57dd5c7975db2961d6de14fe188c89582ee5793d
--- /dev/null
+++ b/Rendering/WebGPU/Testing/Data/Baseline/TestNViewportsNActorsNMappersOneInput.png.sha512
@@ -0,0 +1 @@
+dd3762a9d6d73f5e23142ca839637f914bf6b1a17aa0047bff731e4f254f84b6106c847f07c64bc57ff1404611caa038f3fc44269b9a7e6583ce3e1854176aa9
diff --git a/Rendering/WebGPU/Testing/Data/Baseline/TestNViewportsNActorsOneMapper.png.sha512 b/Rendering/WebGPU/Testing/Data/Baseline/TestNViewportsNActorsOneMapper.png.sha512
new file mode 100644
index 0000000000000000000000000000000000000000..57dd5c7975db2961d6de14fe188c89582ee5793d
--- /dev/null
+++ b/Rendering/WebGPU/Testing/Data/Baseline/TestNViewportsNActorsOneMapper.png.sha512
@@ -0,0 +1 @@
+dd3762a9d6d73f5e23142ca839637f914bf6b1a17aa0047bff731e4f254f84b6106c847f07c64bc57ff1404611caa038f3fc44269b9a7e6583ce3e1854176aa9
diff --git a/Rendering/WebGPU/Testing/Data/Baseline/TestNViewportsOneActor.png.sha512 b/Rendering/WebGPU/Testing/Data/Baseline/TestNViewportsOneActor.png.sha512
new file mode 100644
index 0000000000000000000000000000000000000000..90dd4ff29c3888466be8e89700645c8df32265b2
--- /dev/null
+++ b/Rendering/WebGPU/Testing/Data/Baseline/TestNViewportsOneActor.png.sha512
@@ -0,0 +1 @@
+850e585b4caa0e554619a1224fd8ea77824e911240885698a383982d1fa64bb140ab80b6b7421643c345c4fb95ee4275ba2c4dcee54facd1af78c83c6b27f2f0
diff --git a/Rendering/WebGPU/Testing/Data/Baseline/TestPointRenderingRound_1.png.sha512 b/Rendering/WebGPU/Testing/Data/Baseline/TestPointRenderingRound_1.png.sha512
index 0ef75aeb60dec2e62cfed44a8894b8191abb3fb1..ff5df878095d3ecad3bf54c9d6d0eb1a5f524a80 100644
--- a/Rendering/WebGPU/Testing/Data/Baseline/TestPointRenderingRound_1.png.sha512
+++ b/Rendering/WebGPU/Testing/Data/Baseline/TestPointRenderingRound_1.png.sha512
@@ -1 +1 @@
-30d078d518abe289c701c9482405b7ad9b3abe98bcbbeee9e7676d37b207233e3e0f1618c9a95958637bf34df62a092da32b803f5fe4fe5bf031c54727afdb77
+ee52547b00b29bab4e7b07ac9cdecc423ff1999e105e69d8f21a77ceec060388ff86eca2e3f11d3892bcccf576fb508a175e4e35faf7f0ebfe26d74cfde584e7
diff --git a/Rendering/WebGPU/Testing/Data/Baseline/TestPointRenderingRound_2.png.sha512 b/Rendering/WebGPU/Testing/Data/Baseline/TestPointRenderingRound_2.png.sha512
index 0ef75aeb60dec2e62cfed44a8894b8191abb3fb1..ff5df878095d3ecad3bf54c9d6d0eb1a5f524a80 100644
--- a/Rendering/WebGPU/Testing/Data/Baseline/TestPointRenderingRound_2.png.sha512
+++ b/Rendering/WebGPU/Testing/Data/Baseline/TestPointRenderingRound_2.png.sha512
@@ -1 +1 @@
-30d078d518abe289c701c9482405b7ad9b3abe98bcbbeee9e7676d37b207233e3e0f1618c9a95958637bf34df62a092da32b803f5fe4fe5bf031c54727afdb77
+ee52547b00b29bab4e7b07ac9cdecc423ff1999e105e69d8f21a77ceec060388ff86eca2e3f11d3892bcccf576fb508a175e4e35faf7f0ebfe26d74cfde584e7
diff --git a/Rendering/WebGPU/Testing/Data/Baseline/TestPointRenderingRound_3.png.sha512 b/Rendering/WebGPU/Testing/Data/Baseline/TestPointRenderingRound_3.png.sha512
index 0ad165767946db85306e416e20ee3e21d50cdfe0..0465dcf0616e5556954d04ec6c56e9eadb08d2ad 100644
--- a/Rendering/WebGPU/Testing/Data/Baseline/TestPointRenderingRound_3.png.sha512
+++ b/Rendering/WebGPU/Testing/Data/Baseline/TestPointRenderingRound_3.png.sha512
@@ -1 +1 @@
-6b85ed6f9134cbfaddc81e8623006a958c4a0c25d20a39be8872b3675bb916c906ac9e5dca24c560206af10709f5656c9dc0267f8c3afaf54e39edd36d8bd35c
+721edb7808f8b9362bd2b5e2fa800da8747c0c158de06c6415ffddb9207cdb94539a9ac89f38d987fedd97656d2bdd6e551ec4e675609070d37dcd83d5dff9e6
diff --git a/Rendering/WebGPU/Testing/Data/Baseline/TestPointRenderingRound_4.png.sha512 b/Rendering/WebGPU/Testing/Data/Baseline/TestPointRenderingRound_4.png.sha512
index 6af059dc8abc7d0760a72aaa049b5ff467234324..c71f22864b2b1fd5e5d18298656ea19e28f83825 100644
--- a/Rendering/WebGPU/Testing/Data/Baseline/TestPointRenderingRound_4.png.sha512
+++ b/Rendering/WebGPU/Testing/Data/Baseline/TestPointRenderingRound_4.png.sha512
@@ -1 +1 @@
-ea726b0f44e548870be57ea8f1710fdae6d242342354e9702f0469af21c9b86c92c46d8e128d82b5eb985c6c4a663b81930ccb50ae6d5819bdb857aacea46378
+d4aa29fcad92161f7f17eaa302c73fc036f51465cf54950c76899b6eeba5d4dcf7cb34372450ee7d53f1ce1c7aca0a873b885a7152c2d3d39e28ec743fc51a61
diff --git a/Rendering/WebGPU/Testing/Data/Baseline/TestPointRendering_1.png.sha512 b/Rendering/WebGPU/Testing/Data/Baseline/TestPointRendering_1.png.sha512
index 42cbd6dae0d8f5f957676a9ced7e5d0dd57116a6..06380ab15a0303d3e26e166a16719a0b8ad8e953 100644
--- a/Rendering/WebGPU/Testing/Data/Baseline/TestPointRendering_1.png.sha512
+++ b/Rendering/WebGPU/Testing/Data/Baseline/TestPointRendering_1.png.sha512
@@ -1 +1 @@
-4e167bd563795d1085f01b91931c037839271194f3fe1ff47c104561e30019eae41df5bafb99bb275055127ce92f6d9872a9d3b9aa6996a9fb1ab29a80018713
+28b157c8a0a7f3a5c78b5554123aeac67b21e6506f1b14f7017d5709bae9e413402cb871ec0b9a715e8a8ff2153462e94f92965624121a07333b46eaddceaeec
diff --git a/Rendering/WebGPU/Testing/Data/Baseline/TestPointRendering_2.png.sha512 b/Rendering/WebGPU/Testing/Data/Baseline/TestPointRendering_2.png.sha512
index 42cbd6dae0d8f5f957676a9ced7e5d0dd57116a6..06380ab15a0303d3e26e166a16719a0b8ad8e953 100644
--- a/Rendering/WebGPU/Testing/Data/Baseline/TestPointRendering_2.png.sha512
+++ b/Rendering/WebGPU/Testing/Data/Baseline/TestPointRendering_2.png.sha512
@@ -1 +1 @@
-4e167bd563795d1085f01b91931c037839271194f3fe1ff47c104561e30019eae41df5bafb99bb275055127ce92f6d9872a9d3b9aa6996a9fb1ab29a80018713
+28b157c8a0a7f3a5c78b5554123aeac67b21e6506f1b14f7017d5709bae9e413402cb871ec0b9a715e8a8ff2153462e94f92965624121a07333b46eaddceaeec
diff --git a/Rendering/WebGPU/Testing/Data/Baseline/TestPointRendering_3.png.sha512 b/Rendering/WebGPU/Testing/Data/Baseline/TestPointRendering_3.png.sha512
index 977a3e3c14321cc65945e7fcbc0498975c447c25..bee975fb8c1107dd7bea2f96584d3e13d1f15199 100644
--- a/Rendering/WebGPU/Testing/Data/Baseline/TestPointRendering_3.png.sha512
+++ b/Rendering/WebGPU/Testing/Data/Baseline/TestPointRendering_3.png.sha512
@@ -1 +1 @@
-93e01d5ca995cd0ed47dc56c1888f02068ea3c81d2a04c807cbaf179a4d10e3f2b51bcfb8e648175fa8f560d3ff377f835f73bde688415105082180cf09dfa6d
+a0667349c665a084530a0b1c49a0e51814886b2a1938f7137ffb6275075ea2e202d3a92e6b77f2f7cd168f4bf6b01a7ce3b3f1fb6323019efa3c7274b26c693e
diff --git a/Rendering/WebGPU/Testing/Data/Baseline/TestPointRendering_4.png.sha512 b/Rendering/WebGPU/Testing/Data/Baseline/TestPointRendering_4.png.sha512
index 78ceb0fb9f0d6ffe1382607269af1e43b9dd37ae..c1fdde10061922053a5b254bbf298a7f2dadfffc 100644
--- a/Rendering/WebGPU/Testing/Data/Baseline/TestPointRendering_4.png.sha512
+++ b/Rendering/WebGPU/Testing/Data/Baseline/TestPointRendering_4.png.sha512
@@ -1 +1 @@
-1b61f02cfbade29d6b4ff6c55d12e6a786b9b047bc0ab2408b0682af576e77b9ed5cacc1daea400b5befca7f4ecfa1243ef09b202cf7619f7a64255f04d630e2
+6ac5225469b91cc54054478553f3af3197bba9d73c7cfb4a2bceeef6667114821818f2b3dc621d8665e29b4d6639eca880dde59e0ee55c5c30fd689746f8d8ec
diff --git a/Rendering/WebGPU/Testing/Data/Baseline/TestPointScalarMappedColors.png.sha512 b/Rendering/WebGPU/Testing/Data/Baseline/TestPointScalarMappedColors.png.sha512
index 5154983f4acc3ba8f7ff1cd259a5c8d3501258fd..93c50090ce762df936df55111316841671c108be 100644
--- a/Rendering/WebGPU/Testing/Data/Baseline/TestPointScalarMappedColors.png.sha512
+++ b/Rendering/WebGPU/Testing/Data/Baseline/TestPointScalarMappedColors.png.sha512
@@ -1 +1 @@
-7d781c9819babbda35b638eddd120ad9b6164f0a6aa45b5f4bd95b6f22e4d405abcb0d7aecccac091aad28b198c28565d8b993a5f93557a16f4334c6f9b3133e
+cde0cd07919ed186c63d188df1cb6bc21c28b924e25e88dfd0acbb592ad7261730e7c853a0b1e89a53ef08b6eddc0da7bf7029482d8c32bc48c75199edcaa2a4
diff --git a/Rendering/WebGPU/Testing/Data/Baseline/TestQuad.png.sha512 b/Rendering/WebGPU/Testing/Data/Baseline/TestQuad.png.sha512
index 7761c3855dd4175628fac6b057022c491007e00c..f814656ad47ac04303e0426332103e23709fe069 100644
--- a/Rendering/WebGPU/Testing/Data/Baseline/TestQuad.png.sha512
+++ b/Rendering/WebGPU/Testing/Data/Baseline/TestQuad.png.sha512
@@ -1 +1 @@
-b267115b993da75808f971524fbf97f7d5019a9aa2eac52cce3ba5502641cca369f924e2ffa58bee19f17d6a93e8b8b6289e6b93638697cada99f273f4414c6e
+0e4502df4f4e1e99e729f8649e1ff27e090dc708204adfb8abe3635562b51861b715970201fad5db58c19eab6dae8162b8e78e3c2a566747a368cce87ad147f1
diff --git a/Rendering/WebGPU/Testing/Data/Baseline/TestQuadPointRep.png.sha512 b/Rendering/WebGPU/Testing/Data/Baseline/TestQuadPointRep.png.sha512
index 4da6d3d8c445972f9468d6b8ce3237ed2dda293f..a83a300f50628eeae545d6d019ace25c2a8cf99f 100644
--- a/Rendering/WebGPU/Testing/Data/Baseline/TestQuadPointRep.png.sha512
+++ b/Rendering/WebGPU/Testing/Data/Baseline/TestQuadPointRep.png.sha512
@@ -1 +1 @@
-91f685ee35dbbebfff125876440a7275e04dcb0bae2c5a62e4bc05cdf30edcabcb8a0cdf65c9291291a0c0cf4bb6faa6e001edb87b37ae37b077c029e07fe3b5
+54065c6a9eed2ed5ae39f721f8bd0e1d1f3e6acb1559d843c4347d5e5f44505ab75ecec6b34db63d815182865a42626b8491478103c304c2af229f7df0b586bb
diff --git a/Rendering/WebGPU/Testing/Data/Baseline/TestRenderLinesAsTubes.png.sha512 b/Rendering/WebGPU/Testing/Data/Baseline/TestRenderLinesAsTubes.png.sha512
index 75e88241db1d17656673b9aafdc4133e795d9747..95312a9ae5602a55e612a7d91cb2d270dccb2268 100644
--- a/Rendering/WebGPU/Testing/Data/Baseline/TestRenderLinesAsTubes.png.sha512
+++ b/Rendering/WebGPU/Testing/Data/Baseline/TestRenderLinesAsTubes.png.sha512
@@ -1 +1 @@
-064a4dbc2a1582a48644537c53fb6b896540d7d5748e87f41c3230962c1cbfbca02f8c2201f1cd6a1e09bb0161251a645b7edc4a0b0efd2d0beb6d2ebdcf2c05
+e37091f7ca37c78b696e2df6da78d7c09a2e3311c2c305535997c86ad61c4abe505843c0e467c63b40cb735a1f588ea225458ab2d26a7d4bbe7f7f75dac2c93f
diff --git a/Rendering/WebGPU/Testing/Data/Baseline/TestRenderLinesAsTubesOrthoCamera.png.sha512 b/Rendering/WebGPU/Testing/Data/Baseline/TestRenderLinesAsTubesOrthoCamera.png.sha512
index ffe2989f8418e5cf47d9e430e08e0ccd68507367..0a1af52022afc1064faf2853e5d13db438d32daf 100644
--- a/Rendering/WebGPU/Testing/Data/Baseline/TestRenderLinesAsTubesOrthoCamera.png.sha512
+++ b/Rendering/WebGPU/Testing/Data/Baseline/TestRenderLinesAsTubesOrthoCamera.png.sha512
@@ -1 +1 @@
-54e8a8dc61bef44333e10b66fb26f684052cea20f84679951436a2164c2337d383364389027fdc43ad458ce68970c10b2627d1a918b38d1e9339e97e8d94075d
+3fe64733a33a65bf78ff350e03fd2be1c48717dd2c08940464a2a363e74d996cbd1bdff813ed6fe3021f9a7c819130beb415698fb8ba9293d7974fe17414e5ff
diff --git a/Rendering/WebGPU/Testing/Data/Baseline/TestRenderPointsAsSpheres.png.sha512 b/Rendering/WebGPU/Testing/Data/Baseline/TestRenderPointsAsSpheres.png.sha512
index 07e05061f89a09ce88aae20954ad79f31c2abe37..8cefe76ec3877cc216f8383e22feb80428cccf8e 100644
--- a/Rendering/WebGPU/Testing/Data/Baseline/TestRenderPointsAsSpheres.png.sha512
+++ b/Rendering/WebGPU/Testing/Data/Baseline/TestRenderPointsAsSpheres.png.sha512
@@ -1 +1 @@
-5b005358c5e110bfa576153c2c371db80f00fd6a07c8ea0e98ce04d71805153a5aa8133c56a8915b63e98d16c7bef0d6162dc4296fc67c6ce3c1c20b82fab4d5
+4cafe2027593b9596d9e5bfc51ae784ec1c34573a9dbc9ec39ff67ac9b8dd7b252cd2b609d0e2e4d36c2860528f394bb57a7bbad72d38de3879a7d6952411083
diff --git a/Rendering/WebGPU/Testing/Data/Baseline/TestRenderPointsAsSpheresOrthoCamera.png.sha512 b/Rendering/WebGPU/Testing/Data/Baseline/TestRenderPointsAsSpheresOrthoCamera.png.sha512
index 4b7237d22837571c302fbe9873d52c16a2416cf2..4d5d0d8d2337b5e33dd746bda097a6cf56a43be8 100644
--- a/Rendering/WebGPU/Testing/Data/Baseline/TestRenderPointsAsSpheresOrthoCamera.png.sha512
+++ b/Rendering/WebGPU/Testing/Data/Baseline/TestRenderPointsAsSpheresOrthoCamera.png.sha512
@@ -1 +1 @@
-d19ae6919a75f7e656a47d7ddb4dcf5a646ef4ce240b64a52593ce2a94533f244a723dc16e003cd3ca7ee9c856fe4ddd368de56a8cf2ebbd4b2cacf168c279f2
+fa748691e72885453226191e044d2526a2ab98f40bb7a8f99b197fe25b412ed448a8da8f05202c60ae979fc140a80178ae9b42b34b8629ba3f1ebfd7e21c5de3
diff --git a/Rendering/WebGPU/Testing/Data/Baseline/TestRenderWindowChangeDeviceLater.png.sha512 b/Rendering/WebGPU/Testing/Data/Baseline/TestRenderWindowChangeDeviceLater.png.sha512
index d7ef5664f4b8944ea7774dd957b98b8f56536397..dfc1b341469cf2450cbf615bad90b9d538c2e067 100644
--- a/Rendering/WebGPU/Testing/Data/Baseline/TestRenderWindowChangeDeviceLater.png.sha512
+++ b/Rendering/WebGPU/Testing/Data/Baseline/TestRenderWindowChangeDeviceLater.png.sha512
@@ -1 +1 @@
-f111f7ae82d341adecdc19189537997c4243679e88f86fbcb48bc34bb6b95844812e2b3ba85b45664b987818cc47ac0620684d1bb12741b8189d5db24b7be9d9
+583a6e60c700b15874f9642274b3f2526cb2500c40622c7d73e52ddf4a9ef7a783d8f4ee1ba542de511764fd0408a9fc5a72677b85bf930c2524024046110853
diff --git a/Rendering/WebGPU/Testing/Data/Baseline/TestScalarModeToggle.png.sha512 b/Rendering/WebGPU/Testing/Data/Baseline/TestScalarModeToggle.png.sha512
index ce72704a5746f00ee6a53913586ce72cb1a83e19..bed06da2eb62b99ffc33cc4c61d6c88929aebd86 100644
--- a/Rendering/WebGPU/Testing/Data/Baseline/TestScalarModeToggle.png.sha512
+++ b/Rendering/WebGPU/Testing/Data/Baseline/TestScalarModeToggle.png.sha512
@@ -1 +1 @@
-922b963521eea93e5a33c1fa0a18d396b8087d3e8fbca10f7ff81ee9a7bfa672a2b06d059587fbc3ab66f6eae2971b2c80d0c925d751d9f163d0e927aa6db4e0
+ec605ce3d149e95431d7329d5ec05da9fc5203657ee76073f065ea384038fd3c2bcbcd4102dac4d4b9357cd68db1bb3d7399820f38231a9877456a691a3cc15e
diff --git a/Rendering/WebGPU/Testing/Data/Baseline/TestSurfacePlusEdges.png.sha512 b/Rendering/WebGPU/Testing/Data/Baseline/TestSurfacePlusEdges.png.sha512
index 5303a3cc04e92ae183c2b317d7310d2671918d9a..1377665f933976eff976d5a560c8ad7bfd421a46 100644
--- a/Rendering/WebGPU/Testing/Data/Baseline/TestSurfacePlusEdges.png.sha512
+++ b/Rendering/WebGPU/Testing/Data/Baseline/TestSurfacePlusEdges.png.sha512
@@ -1 +1 @@
-1d2214369f96edc5a4b53ab0ae46e2ab68cdb62f02a7e7a31306bdb01fa829bcd47f0ff1a977cbee8bf86bda19fc48d473a1e1c85a11ac08e373151d3065f2a5
+5e6a31fa7fde75f080349de0a0e232e90b5212d23062483d42deac5de925228bbe12457c9e54cda49c7bfe3f0702f245606692ce9aa87afb1ff305545d4a0cc6
diff --git a/Rendering/WebGPU/Testing/Data/Baseline/TestVertexRendering.png.sha512 b/Rendering/WebGPU/Testing/Data/Baseline/TestVertexRendering.png.sha512
index ab5275de9236d8efa778cd9884c384696297d9f1..ba521867e1c4fdfcb5ec053d36025c76bbaa058b 100644
--- a/Rendering/WebGPU/Testing/Data/Baseline/TestVertexRendering.png.sha512
+++ b/Rendering/WebGPU/Testing/Data/Baseline/TestVertexRendering.png.sha512
@@ -1 +1 @@
-ccdb818a5c7c6053607474f74da970eff8177a339794750ea9eb2812a99c4eb6b68d7f40092ea664f786e264e3cf16827c98871d95f3b077bf222dc30b112cd9
+4560bd0959e7c53ae32821a6762a67c695b6dda7785a4fb7c910f79e014865678d5b19f18df25cc7c31c633cfe634d31d80b746616d1ad8dcd9e9a8210d29e70
diff --git a/Rendering/WebGPU/Testing/Data/Baseline/TestWireframe.png.sha512 b/Rendering/WebGPU/Testing/Data/Baseline/TestWireframe.png.sha512
index 6c58a2ad70761d2707633adf7a0d401d424c4f7b..112e470852e9082b8e76635808e0568b91c0ee4a 100644
--- a/Rendering/WebGPU/Testing/Data/Baseline/TestWireframe.png.sha512
+++ b/Rendering/WebGPU/Testing/Data/Baseline/TestWireframe.png.sha512
@@ -1 +1 @@
-be78db346b8e6546e1be90a8d471f44765fb64267b2c25d7682dbca0b223d21e4e127f854c7c14dd622a6e06fa3d9dca6dcc3a3934df503992ff0fee40f672c8
+927647d3209b1d0c9ada11d62d57c3ecb3eb3a62bf8fddf4e0b31aef4b8f37a0c755100f58d23346d26c56afaf0d2a94339d5224f3313a1914dcb6be56047668
diff --git a/Rendering/WebGPU/Testing/Python/TestReadPixels.py b/Rendering/WebGPU/Testing/Python/TestReadPixels.py
index a3fbbf1d7cc5cdcebd4683528356e717462d45d4..0743921b49d50855910072d9e80a4a05046510e0 100644
--- a/Rendering/WebGPU/Testing/Python/TestReadPixels.py
+++ b/Rendering/WebGPU/Testing/Python/TestReadPixels.py
@@ -27,8 +27,8 @@ renderWindow.Render()
 # Verify background color as unsigned char RGBA values
 ucharRGBA = vtkUnsignedCharArray()
 renderWindow.GetRGBACharPixelData(0, 0, 299, 299, 0, ucharRGBA)
-assert(ucharRGBA.GetTuple(0) == (100.0, 110.0, 120.0, 255.0))
-assert(ucharRGBA.GetTuple(299 * 299) == (100.0, 110.0, 120.0, 255.0))
+assert(ucharRGBA.GetTuple(0) == (100.0, 110.0, 120.0, 0.0))
+assert(ucharRGBA.GetTuple(299 * 299) == (100.0, 110.0, 120.0, 0.0))
 
 # Verify background color as normalized float32 RGBA values
 f32RGBA = vtkFloatArray()
@@ -36,11 +36,11 @@ renderWindow.GetRGBAPixelData(0, 0, 299, 299, 0, f32RGBA)
 assert(int(f32RGBA.GetTuple(0)[0] * 255) == 100)
 assert(int(f32RGBA.GetTuple(0)[1] * 255) == 110)
 assert(int(f32RGBA.GetTuple(0)[2] * 255) == 120)
-assert(int(f32RGBA.GetTuple(0)[3] * 255) == 255)
+assert(int(f32RGBA.GetTuple(0)[3] * 255) == 0)
 assert(int(f32RGBA.GetTuple(299)[0] * 255) == 100)
 assert(int(f32RGBA.GetTuple(299)[1] * 255) == 110)
 assert(int(f32RGBA.GetTuple(299)[2] * 255) == 120)
-assert(int(f32RGBA.GetTuple(299)[3] * 255) == 255)
+assert(int(f32RGBA.GetTuple(299)[3] * 255) == 0)
 
 # Verify background color as unsigned char RGB values
 ucharRGB = vtkUnsignedCharArray()
diff --git a/Rendering/WebGPU/vtk.module b/Rendering/WebGPU/vtk.module
index 0a57a63011665150f1558f3e37c7836e3c340809..412fcc1b583047fcb5b844b5e632484c44670d30 100644
--- a/Rendering/WebGPU/vtk.module
+++ b/Rendering/WebGPU/vtk.module
@@ -20,9 +20,11 @@ PRIVATE_DEPENDS
   VTK::fmt
 TEST_DEPENDS
   VTK::CommonColor
+  VTK::RenderingAnnotation
   VTK::FiltersGeneral
   VTK::FiltersSources
   VTK::RenderingUI
   VTK::InteractionStyle
+  VTK::InteractionWidgets
   VTK::TestingCore
   VTK::TestingRendering
diff --git a/Rendering/WebGPU/vtkWebGPUActor.cxx b/Rendering/WebGPU/vtkWebGPUActor.cxx
index 9df2df4034dfbda7c87957e246b5670b41c30a68..ef3e443c1d535ac0b1e6910c0ee28eb386856add 100644
--- a/Rendering/WebGPU/vtkWebGPUActor.cxx
+++ b/Rendering/WebGPU/vtkWebGPUActor.cxx
@@ -3,6 +3,9 @@
 
 #include "vtkWebGPUActor.h"
 
+#include "Private/vtkWebGPUBindGroupInternals.h"
+#include "Private/vtkWebGPUBindGroupLayoutInternals.h"
+
 #include "vtkMapper.h"
 #include "vtkMatrix3x3.h"
 #include "vtkObjectFactory.h"
@@ -12,6 +15,7 @@
 #include "vtkTexture.h"
 #include "vtkTransform.h"
 #include "vtkWebGPUComputePointCloudMapper.h"
+#include "vtkWebGPURenderWindow.h"
 #include "vtkWebGPURenderer.h"
 #include "vtkWindow.h"
 
@@ -19,6 +23,19 @@
 
 VTK_ABI_NAMESPACE_BEGIN
 
+//------------------------------------------------------------------------------
+void vtkWebGPUActor::MapperBooleanCache::SetValue(bool newValue)
+{
+  this->Value = newValue;
+  this->TimeStamp.Modified();
+}
+
+//------------------------------------------------------------------------------
+bool vtkWebGPUActor::MapperBooleanCache::IsOutdated(vtkMapper* mapper)
+{
+  return mapper->GetMTime() > this->TimeStamp;
+}
+
 //------------------------------------------------------------------------------
 vtkStandardNewMacro(vtkWebGPUActor);
 
@@ -35,7 +52,17 @@ void vtkWebGPUActor::PrintSelf(ostream& os, vtkIndent indent)
   os << indent << "ModelTransformsBuildTimestamp: " << this->ModelTransformsBuildTimestamp << '\n';
   os << indent << "ShadingOptionsBuildTimestamp: " << this->ShadingOptionsBuildTimestamp << '\n';
   os << indent << "RenderOptionsBuildTimestamp: " << this->RenderOptionsBuildTimestamp << '\n';
-  os << indent << "BundleInvalidated: " << this->BundleInvalidated << '\n';
+}
+
+//------------------------------------------------------------------------------
+void vtkWebGPUActor::ReleaseGraphicsResources(vtkWindow* window)
+{
+  this->ActorBindGroupLayout = nullptr;
+  this->ActorBindGroup = nullptr;
+  this->ActorBuffer = nullptr;
+  this->MapperHasOpaqueGeometry = {};
+  this->MapperHasTranslucentPolygonalGeometry = {};
+  this->Superclass::ReleaseGraphicsResources(window);
 }
 
 //------------------------------------------------------------------------------
@@ -43,21 +70,46 @@ void vtkWebGPUActor::Render(vtkRenderer* renderer, vtkMapper* mapper)
 {
   if (auto* wgpuRenderer = vtkWebGPURenderer::SafeDownCast(renderer))
   {
+    auto* wgpuRenderWindow = vtkWebGPURenderWindow::SafeDownCast(wgpuRenderer->GetRenderWindow());
+    auto* wgpuConfiguration = wgpuRenderWindow->GetWGPUConfiguration();
     switch (wgpuRenderer->GetRenderStage())
     {
       case vtkWebGPURenderer::AwaitingPreparation:
         break;
       case vtkWebGPURenderer::UpdatingBuffers:
+      {
+        if (!(this->ActorBindGroup && this->ActorBindGroupLayout && this->ActorBuffer))
+        {
+          this->AllocateResources(wgpuConfiguration);
+        }
         // reset this flag because the `mapper->Render()` call shall invalidate the bundle if it
         // determines that the render bundle needs to be recorded once again.
-        this->BundleInvalidated = false;
         mapper->Render(renderer, this);
-        this->CacheActorRenderOptions();
-        this->CacheActorShadeOptions();
-        this->CacheActorTransforms();
+        bool updateBuffers = this->CacheActorRenderOptions();
+        updateBuffers |= this->CacheActorShadeOptions();
+        updateBuffers |= this->CacheActorTransforms();
+        if (updateBuffers)
+        {
+          wgpuConfiguration->WriteBuffer(this->ActorBuffer, 0, this->GetCachedActorInformation(),
+            this->GetCacheSizeBytes(), "ActorBufferUpdate");
+        }
         break;
+      }
       case vtkWebGPURenderer::RecordingCommands:
-        mapper->Render(renderer, this);
+        if (wgpuRenderer->GetUseRenderBundles() && this->SupportRenderBundles())
+        {
+          if (wgpuRenderer->GetRebuildRenderBundle())
+          {
+            wgpuRenderer->GetRenderBundleEncoder().SetBindGroup(1, this->ActorBindGroup);
+            mapper->Render(renderer, this);
+          }
+          // else, no need to record draw commands.
+        }
+        else
+        {
+          wgpuRenderer->GetRenderPassEncoder().SetBindGroup(1, this->ActorBindGroup);
+          mapper->Render(renderer, this);
+        }
         break;
       case vtkWebGPURenderer::Finished:
       default:
@@ -85,6 +137,66 @@ bool vtkWebGPUActor::SupportRenderBundles()
   return true;
 }
 
+//------------------------------------------------------------------------------
+vtkTypeBool vtkWebGPUActor::HasOpaqueGeometry()
+{
+  bool isOpaque = false;
+  if (this->Mapper)
+  {
+    if (this->MapperHasOpaqueGeometry.IsOutdated(this->Mapper))
+    {
+      isOpaque = this->Superclass::HasOpaqueGeometry();
+      this->MapperHasOpaqueGeometry.SetValue(isOpaque);
+    }
+    else
+    {
+      // nullify mapper so that superclass doesn't run the expensive
+      // code path in vtkMapper::HasOpaqueGeometry.
+      vtkMapper* tmpMapper = this->Mapper;
+      this->Mapper = nullptr;
+      isOpaque = this->Superclass::HasOpaqueGeometry();
+      // restore
+      this->Mapper = tmpMapper;
+      isOpaque &= this->MapperHasOpaqueGeometry.GetValue();
+    }
+  }
+  else
+  {
+    isOpaque = this->Superclass::HasOpaqueGeometry();
+  }
+  return isOpaque;
+}
+
+//------------------------------------------------------------------------------
+vtkTypeBool vtkWebGPUActor::HasTranslucentPolygonalGeometry()
+{
+  bool isTranslucent = false;
+  if (this->Mapper)
+  {
+    if (this->MapperHasTranslucentPolygonalGeometry.IsOutdated(this->Mapper))
+    {
+      isTranslucent = this->Superclass::HasTranslucentPolygonalGeometry();
+      this->MapperHasTranslucentPolygonalGeometry.SetValue(isTranslucent);
+    }
+    else
+    {
+      // nullify mapper so that superclass doesn't run the expensive
+      // code path in vtkMapper::HasTranslucentPolygonalGeometry.
+      vtkMapper* tmpMapper = this->Mapper;
+      this->Mapper = nullptr;
+      isTranslucent = this->Superclass::HasTranslucentPolygonalGeometry();
+      // restore
+      this->Mapper = tmpMapper;
+      isTranslucent &= this->MapperHasTranslucentPolygonalGeometry.GetValue();
+    }
+  }
+  else
+  {
+    isTranslucent = this->Superclass::HasTranslucentPolygonalGeometry();
+  }
+  return isTranslucent;
+}
+
 //------------------------------------------------------------------------------
 bool vtkWebGPUActor::UpdateKeyMatrices()
 {
@@ -126,7 +238,7 @@ bool vtkWebGPUActor::UpdateKeyMatrices()
 }
 
 //------------------------------------------------------------------------------
-void vtkWebGPUActor::CacheActorTransforms()
+bool vtkWebGPUActor::CacheActorTransforms()
 {
   if (this->UpdateKeyMatrices())
   {
@@ -142,11 +254,13 @@ void vtkWebGPUActor::CacheActorTransforms()
         transform.Normal[i][j] = this->NormalMatrix->GetElement(i, j);
       }
     }
+    return true;
   }
+  return false;
 }
 
 //------------------------------------------------------------------------------
-void vtkWebGPUActor::CacheActorRenderOptions()
+bool vtkWebGPUActor::CacheActorRenderOptions()
 {
   auto* displayProperty = this->GetProperty();
   if (displayProperty->GetMTime() > this->RenderOptionsBuildTimestamp ||
@@ -165,11 +279,13 @@ void vtkWebGPUActor::CacheActorRenderOptions()
       (displayProperty->GetRenderLinesAsTubes() << 6) |
       (static_cast<int>(displayProperty->GetPoint2DShape()) << 7);
     this->RenderOptionsBuildTimestamp.Modified();
+    return true;
   }
+  return false;
 }
 
 //------------------------------------------------------------------------------
-void vtkWebGPUActor::CacheActorShadeOptions()
+bool vtkWebGPUActor::CacheActorShadeOptions()
 {
   auto* displayProperty = this->GetProperty();
   if (displayProperty->GetMTime() > this->ShadingOptionsBuildTimestamp ||
@@ -190,6 +306,42 @@ void vtkWebGPUActor::CacheActorShadeOptions()
       so.VertexColor[i] = displayProperty->GetVertexColor()[i];
     }
     this->ShadingOptionsBuildTimestamp.Modified();
+    return true;
   }
+  return false;
+}
+
+//------------------------------------------------------------------------------
+void vtkWebGPUActor::AllocateResources(vtkWebGPUConfiguration* wgpuConfiguration)
+{
+  const auto& device = wgpuConfiguration->GetDevice();
+
+  const auto actorDescription = this->GetObjectDescription();
+  const auto bufferLabel = "buffer@" + actorDescription;
+  const auto bufferSize = vtkWebGPUConfiguration::Align(vtkWebGPUActor::GetCacheSizeBytes(), 32);
+  this->ActorBuffer = wgpuConfiguration->CreateBuffer(bufferSize,
+    wgpu::BufferUsage::Storage | wgpu::BufferUsage::CopyDst, false, bufferLabel.c_str());
+
+  this->ActorBindGroupLayout = vtkWebGPUBindGroupLayoutInternals::MakeBindGroupLayout(device,
+    {
+      // clang-format off
+      // ActorBlocks
+      { 0, wgpu::ShaderStage::Vertex | wgpu::ShaderStage::Fragment, wgpu::BufferBindingType::ReadOnlyStorage },
+      // clang-format on
+    },
+    "bgl@" + actorDescription);
+  this->ActorBindGroup =
+    vtkWebGPUBindGroupInternals::MakeBindGroup(device, this->ActorBindGroupLayout,
+      {
+        // clang-format off
+        { 0, this->ActorBuffer, 0, bufferSize },
+        // clang-format on
+      },
+      "bg@" + actorDescription);
+  // Reset timestamps because the previous buffer is now gone and contents of the buffer will need
+  // to be re-uploaded.
+  this->ModelTransformsBuildTimestamp = vtkTimeStamp();
+  this->ShadingOptionsBuildTimestamp = vtkTimeStamp();
+  this->RenderOptionsBuildTimestamp = vtkTimeStamp();
 }
 VTK_ABI_NAMESPACE_END
diff --git a/Rendering/WebGPU/vtkWebGPUActor.h b/Rendering/WebGPU/vtkWebGPUActor.h
index 01bc6d3873830d2593dd2712542ad795ad001aa0..002ace5cf247050a59100f95b5332fd2dce32bf2 100644
--- a/Rendering/WebGPU/vtkWebGPUActor.h
+++ b/Rendering/WebGPU/vtkWebGPUActor.h
@@ -10,6 +10,7 @@
 
 VTK_ABI_NAMESPACE_BEGIN
 class vtkMatrix3x3;
+class vtkWebGPUConfiguration;
 class vtkWebGPURenderPipelineCache;
 
 class VTKRENDERINGWEBGPU_EXPORT vtkWebGPUActor : public vtkActor
@@ -19,6 +20,8 @@ public:
   vtkTypeMacro(vtkWebGPUActor, vtkActor);
   void PrintSelf(ostream& os, vtkIndent indent) override;
 
+  void ReleaseGraphicsResources(vtkWindow* window) override;
+
   inline const void* GetCachedActorInformation() { return &(this->CachedActorInfo); }
   static std::size_t GetCacheSizeBytes() { return sizeof(ActorBlock); }
 
@@ -35,28 +38,40 @@ public:
    */
   bool SupportRenderBundles();
 
+  inline void PopulateBindgroupLayouts(std::vector<wgpu::BindGroupLayout>& layouts)
+  {
+    layouts.emplace_back(this->ActorBindGroupLayout);
+  }
+
   virtual bool UpdateKeyMatrices();
 
+  ///@{
   /**
-   * Forces the renderer to re-record draw commands into a render bundle associated with this actor.
+   * Does this prop have opaque/translucent polygonal geometry?
+   * These methods are overriden to skip redundant checks
+   * in different rendering stages.
    *
-   * @note This does not use vtkSetMacro because the actor MTime should not be affected when a
-   * render bundle is invalidated.
-   */
-  inline void SetBundleInvalidated(bool value) { this->BundleInvalidated = value; }
-
-  /**
-   * Get whether the render bundle associated with this actor must be reset by the renderer.
+   * If the mapper has already been checked for opaque geometry and the mapper
+   * has not been modified since the last check, this method uses the last result,
+   * instead of asking the mapper to check for opaque geometry again. The
+   * HasTranslucentPolygonalGeometry() similarly checks and caches the result of
+   * vtkMapper::HasTranslucentPolygonalGeometry()
+   *
+   * @sa vtkWebGPURenderer::GetRenderStage()
    */
-  vtkGetMacro(BundleInvalidated, bool);
+  vtkTypeBool HasOpaqueGeometry() override;
+  vtkTypeBool HasTranslucentPolygonalGeometry() override;
+  ///@}
 
 protected:
   vtkWebGPUActor();
   ~vtkWebGPUActor() override;
 
-  void CacheActorTransforms();
-  void CacheActorRenderOptions();
-  void CacheActorShadeOptions();
+  bool CacheActorTransforms();
+  bool CacheActorRenderOptions();
+  bool CacheActorShadeOptions();
+
+  void AllocateResources(vtkWebGPUConfiguration* renderer);
 
   struct ActorBlock
   {
@@ -116,7 +131,34 @@ protected:
   vtkTimeStamp ShadingOptionsBuildTimestamp;
   vtkTimeStamp RenderOptionsBuildTimestamp;
 
-  bool BundleInvalidated = false;
+  wgpu::BindGroupLayout ActorBindGroupLayout;
+  wgpu::BindGroup ActorBindGroup;
+  wgpu::Buffer ActorBuffer;
+
+  class MapperBooleanCache
+  {
+    bool Value = false;
+    vtkTimeStamp TimeStamp;
+
+  public:
+    /**
+     * Update the cached value with the new value. This also increments the TimeStamp.
+     */
+    void SetValue(bool newValue);
+
+    /**
+     * Returns the cached `Value`.
+     */
+    inline bool GetValue() { return Value; }
+
+    /**
+     * Returns true if the timestamp of the cached value is older than the mapper's MTime.
+     */
+    bool IsOutdated(vtkMapper* mapper);
+  };
+
+  MapperBooleanCache MapperHasOpaqueGeometry;
+  MapperBooleanCache MapperHasTranslucentPolygonalGeometry;
 
 private:
   vtkWebGPUActor(const vtkWebGPUActor&) = delete;
diff --git a/Rendering/WebGPU/vtkWebGPUBatchedPolyDataMapper.cxx b/Rendering/WebGPU/vtkWebGPUBatchedPolyDataMapper.cxx
index dbaf78d08e74b22c999cafdc91d598d7d5220cf0..f1127874a16297ef81d291bbe7c573889baf710a 100644
--- a/Rendering/WebGPU/vtkWebGPUBatchedPolyDataMapper.cxx
+++ b/Rendering/WebGPU/vtkWebGPUBatchedPolyDataMapper.cxx
@@ -138,14 +138,14 @@ void vtkWebGPUBatchedPolyDataMapper::RenderPiece(vtkRenderer* renderer, vtkActor
   }
 
   auto* wgpuRenderWindow = vtkWebGPURenderWindow::SafeDownCast(renderer->GetRenderWindow());
-  auto* wgpuActor = vtkWebGPUActor::SafeDownCast(actor);
+  auto* wgpuRenderer = vtkWebGPURenderer::SafeDownCast(renderer);
   auto* wgpuConfiguration = wgpuRenderWindow->GetWGPUConfiguration();
   const auto& device = wgpuRenderWindow->GetDevice();
 
   auto& batchElement = *(this->VTKPolyDataToBatchElement.begin()->second);
   if (this->LastBlockVisibility != batchElement.Visibility)
   {
-    wgpuActor->SetBundleInvalidated(true);
+    wgpuRenderer->InvalidateBundle();
   }
   this->LastBlockVisibility = batchElement.Visibility;
 
diff --git a/Rendering/WebGPU/vtkWebGPUCamera.cxx b/Rendering/WebGPU/vtkWebGPUCamera.cxx
index aa36d2e8b920eb02312beefa0506afa9e164ece7..3e52a238a4e40e38edab7f9c125b0f9bbed3573c 100644
--- a/Rendering/WebGPU/vtkWebGPUCamera.cxx
+++ b/Rendering/WebGPU/vtkWebGPUCamera.cxx
@@ -5,6 +5,7 @@
 #include "vtkMatrix3x3.h"
 #include "vtkMatrix4x4.h"
 #include "vtkObjectFactory.h"
+#include "vtkRenderWindow.h"
 #include "vtkRenderer.h"
 #include "vtkWebGPURenderer.h"
 
@@ -60,6 +61,7 @@ void vtkWebGPUCamera::CacheSceneTransforms(vtkRenderer* renderer)
         st.ProjectionMatrix[i][j] = projection->GetElement(j, i);
       }
     }
+    st.ProjectionMatrix[1][1] *= -1;
     // normal matrix
     for (int i = 0; i < 3; ++i)
     {
@@ -119,13 +121,17 @@ void vtkWebGPUCamera::UpdateViewport(vtkRenderer* renderer)
     rpassEncoder.SetScissorRect(static_cast<uint32_t>(this->ScissorRect.GetLeft()),
       static_cast<uint32_t>(this->ScissorRect.GetBottom()),
       static_cast<uint32_t>(this->ScissorRect.GetWidth()),
-      static_cast<uint32_t>(this->ScissorRect.GetWidth()));
+      static_cast<uint32_t>(this->ScissorRect.GetHeight()));
     this->UseScissor = false;
   }
   else
   {
     rpassEncoder.SetScissorRect(
-      0u, 0u, static_cast<uint32_t>(width), static_cast<uint32_t>(height));
+      lowerLeft[0], lowerLeft[1], static_cast<uint32_t>(width), static_cast<uint32_t>(height));
+  }
+  if ((renderer->GetRenderWindow())->GetErase() && renderer->GetErase())
+  {
+    renderer->Clear();
   }
 }
 
diff --git a/Rendering/WebGPU/vtkWebGPUClearDrawPass.cxx b/Rendering/WebGPU/vtkWebGPUClearDrawPass.cxx
index 33c33ac07cc734baaec2d5de9497edfa91be4219..7fac2cce1c94a450273ed30afddc4b5261f35216 100644
--- a/Rendering/WebGPU/vtkWebGPUClearDrawPass.cxx
+++ b/Rendering/WebGPU/vtkWebGPUClearDrawPass.cxx
@@ -7,7 +7,6 @@
 #include "vtkRenderState.h"
 #include "vtkRenderer.h"
 #include "vtkWebGPURenderWindow.h"
-#include <chrono>
 
 VTK_ABI_NAMESPACE_BEGIN
 
@@ -29,7 +28,6 @@ void vtkWebGPUClearDrawPass::PrintSelf(ostream& os, vtkIndent indent)
 //------------------------------------------------------------------------------
 wgpu::RenderPassEncoder vtkWebGPUClearDrawPass::Begin(const vtkRenderState* state)
 {
-  auto renderer = state->GetRenderer();
   auto wgpuRenderWindow =
     vtkWebGPURenderWindow::SafeDownCast(state->GetRenderer()->GetRenderWindow());
 
@@ -39,17 +37,8 @@ wgpu::RenderPassEncoder vtkWebGPUClearDrawPass::Begin(const vtkRenderState* stat
   wgpu::TextureView depthStencilView = wgpuRenderWindow->GetDepthStencilView();
 
   vtkWebGPURenderPassDescriptorInternals renderPassDescriptor(
-    backBufferViews, depthStencilView, this->DoClear);
+    backBufferViews, depthStencilView, this->ClearColor, this->ClearDepth, this->ClearStencil);
   renderPassDescriptor.label = "vtkWebGPUClearDrawPass::Begin";
-
-  double* bgColor = renderer->GetBackground();
-  for (auto& colorAttachment : renderPassDescriptor.ColorAttachments)
-  {
-    colorAttachment.clearValue.r = bgColor[0];
-    colorAttachment.clearValue.g = bgColor[1];
-    colorAttachment.clearValue.b = bgColor[2];
-    colorAttachment.clearValue.a = 1.0f;
-  }
   return wgpuRenderWindow->NewRenderPass(renderPassDescriptor);
 }
 
diff --git a/Rendering/WebGPU/vtkWebGPUClearDrawPass.h b/Rendering/WebGPU/vtkWebGPUClearDrawPass.h
index 0eb945c666dbd9ba5599e5cba26d166238032606..b205bd2919cd978c518811c515da81e4ab4b3b97 100644
--- a/Rendering/WebGPU/vtkWebGPUClearDrawPass.h
+++ b/Rendering/WebGPU/vtkWebGPUClearDrawPass.h
@@ -19,12 +19,31 @@ public:
 
   ///@{
   /**
-   * Get/set the DoClear attribute. If true this clear pass will clear the color and depth buffer
-   * before rendering. Il false, this pass will render on top of the existing color and depth buffer
+   * Get/set the ClearColor attribute. If true this clear pass will clear the color buffer
+   * before rendering. If false, this pass will render on top of the existing color buffer
    */
-  vtkGetMacro(DoClear, bool);
-  vtkSetMacro(DoClear, bool);
+  vtkGetMacro(ClearColor, bool);
+  vtkSetMacro(ClearColor, bool);
   ///@}
+
+  ///@{
+  /**
+   * Get/set the ClearDepth attribute. If true this clear pass will clear the depth buffer
+   * before rendering. If false, this pass will render on top of the existing depth buffer
+   */
+  vtkGetMacro(ClearDepth, bool);
+  vtkSetMacro(ClearDepth, bool);
+  ///@}
+
+  ///@{
+  /**
+   * Get/set the ClearStencil attribute. If true this clear pass will clear the stencil buffer
+   * before rendering. If false, this pass will render on top of the existing stencil buffer
+   */
+  vtkGetMacro(ClearStencil, bool);
+  vtkSetMacro(ClearStencil, bool);
+  ///@}
+
   wgpu::RenderPassEncoder Begin(const vtkRenderState* state) override;
 
 protected:
@@ -32,7 +51,9 @@ protected:
   ~vtkWebGPUClearDrawPass() override;
 
 private:
-  bool DoClear = true;
+  bool ClearColor = true;
+  bool ClearDepth = true;
+  bool ClearStencil = true;
 
   vtkWebGPUClearDrawPass(const vtkWebGPUClearDrawPass&) = delete;
   void operator=(const vtkWebGPUClearDrawPass&) = delete;
diff --git a/Rendering/WebGPU/vtkWebGPUPolyDataMapper.cxx b/Rendering/WebGPU/vtkWebGPUPolyDataMapper.cxx
index ffc9151f01df9f12b662437b86cb6c3849d92960..d47750841b29ad299b710e3b357989da1adfce2b 100644
--- a/Rendering/WebGPU/vtkWebGPUPolyDataMapper.cxx
+++ b/Rendering/WebGPU/vtkWebGPUPolyDataMapper.cxx
@@ -282,7 +282,6 @@ void vtkWebGPUPolyDataMapper::RenderPiece(vtkRenderer* renderer, vtkActor* actor
 
   const auto device = wgpuRenderWindow->GetDevice();
   auto* wgpuConfiguration = wgpuRenderWindow->GetWGPUConfiguration();
-  auto* wgpuActor = reinterpret_cast<vtkWebGPUActor*>(actor);
   auto* wgpuRenderer = vtkWebGPURenderer::SafeDownCast(renderer);
   auto* displayProperty = actor->GetProperty();
 
@@ -304,16 +303,16 @@ void vtkWebGPUPolyDataMapper::RenderPiece(vtkRenderer* renderer, vtkActor* actor
           wgpuConfiguration, mesh, /*representation=*/VTK_POINTS);
       }
       // setup graphics pipeline
-      if (this->GetNeedToRebuildGraphicsPipelines(actor))
+      if (this->GetNeedToRebuildGraphicsPipelines(actor, renderer))
       {
         // render bundle must reference new bind groups and/or pipelines
-        wgpuActor->SetBundleInvalidated(true);
+        wgpuRenderer->InvalidateBundle();
         this->SetupGraphicsPipelines(device, renderer, actor);
       }
       // invalidate render bundle when any of the cached properties of an actor have changed.
-      if (this->CacheActorProperties(actor))
+      if (this->CacheActorRendererProperties(actor, renderer))
       {
-        wgpuActor->SetBundleInvalidated(true);
+        wgpuRenderer->InvalidateBundle();
       }
       break;
     }
@@ -333,16 +332,17 @@ void vtkWebGPUPolyDataMapper::RenderPiece(vtkRenderer* renderer, vtkActor* actor
 }
 
 //------------------------------------------------------------------------------
-bool vtkWebGPUPolyDataMapper::CacheActorProperties(vtkActor* actor)
+bool vtkWebGPUPolyDataMapper::CacheActorRendererProperties(vtkActor* actor, vtkRenderer* renderer)
 {
-  auto it = this->CachedActorProperties.find(actor);
+  const auto key = std::make_pair(actor, renderer);
+  auto it = this->CachedActorRendererProperties.find(key);
   auto* displayProperty = actor->GetProperty();
   bool hasTranslucentPolygonalGeometry = false;
   if (actor)
   {
     hasTranslucentPolygonalGeometry = actor->HasTranslucentPolygonalGeometry();
   }
-  if (it == this->CachedActorProperties.end())
+  if (it == this->CachedActorRendererProperties.end())
   {
     ActorState state = {};
     state.LastActorBackfaceCulling = displayProperty->GetBackfaceCulling();
@@ -350,7 +350,7 @@ bool vtkWebGPUPolyDataMapper::CacheActorProperties(vtkActor* actor)
     state.LastRepresentation = displayProperty->GetRepresentation();
     state.LastVertexVisibility = displayProperty->GetVertexVisibility();
     state.LastHasRenderingTranslucentGeometry = hasTranslucentPolygonalGeometry;
-    this->CachedActorProperties[actor] = state;
+    this->CachedActorRendererProperties[key] = state;
     return true;
   }
   else
@@ -1257,7 +1257,7 @@ void vtkWebGPUPolyDataMapper::UpdateMeshGeometryBuffers(vtkWebGPURenderWindow* w
 
   vtkCellData* cellData = this->CurrentInput->GetCellData();
   vtkDataArray* cellColors = nullptr;
-  vtkNew<vtkUnsignedCharArray> cellColorsFromFieldData;
+  vtkSmartPointer<vtkUnsignedCharArray> cellColorsFromFieldData;
   if (this->HasCellAttributes[CELL_COLORS])
   {
     // are we using a single color value replicated over all cells?
@@ -1265,6 +1265,7 @@ void vtkWebGPUPolyDataMapper::UpdateMeshGeometryBuffers(vtkWebGPURenderWindow* w
     {
       const vtkIdType numCells = this->CurrentInput->GetNumberOfCells();
       const int numComponents = this->Colors->GetNumberOfComponents();
+      cellColorsFromFieldData = vtk::TakeSmartPointer(vtkUnsignedCharArray::New());
       cellColorsFromFieldData->SetNumberOfComponents(numComponents);
       cellColorsFromFieldData->SetNumberOfTuples(numCells);
       for (int i = 0; i < numComponents; ++i)
@@ -1377,19 +1378,23 @@ void vtkWebGPUPolyDataMapper::UpdateMeshGeometryBuffers(vtkWebGPURenderWindow* w
     }
   }
 
-  const std::string meshAttrDescriptorLabel =
-    "MeshAttributeDescriptor-" + this->CurrentInput->GetObjectDescription();
-  if (this->AttributeDescriptorBuffer == nullptr)
-  {
-    this->AttributeDescriptorBuffer = wgpuConfiguration->CreateBuffer(sizeof(meshAttrDescriptor),
-      wgpu::BufferUsage::Storage | wgpu::BufferUsage::CopyDst,
-      /*mappedAtCreation=*/false, meshAttrDescriptorLabel.c_str());
-  }
   // handle partial updates
   if (updatePointDescriptor || updateCellArrayDescriptor)
   {
+    const std::string meshAttrDescriptorLabel =
+      "MeshAttributeDescriptor-" + this->CurrentInput->GetObjectDescription();
+    if (this->AttributeDescriptorBuffer == nullptr)
+    {
+      this->AttributeDescriptorBuffer = wgpuConfiguration->CreateBuffer(sizeof(meshAttrDescriptor),
+        wgpu::BufferUsage::Storage | wgpu::BufferUsage::CopyDst,
+        /*mappedAtCreation=*/false, meshAttrDescriptorLabel.c_str());
+    }
     wgpuConfiguration->WriteBuffer(this->AttributeDescriptorBuffer, 0, &meshAttrDescriptor,
       sizeof(meshAttrDescriptor), meshAttrDescriptorLabel.c_str());
+    // Create bind group for the point/cell attribute buffers.
+    this->MeshAttributeBindGroup =
+      this->CreateMeshAttributeBindGroup(wgpuConfiguration->GetDevice(), "MeshAttributeBindGroup");
+    this->RebuildGraphicsPipelines = true;
   }
 
   vtkDebugMacro(<< ((updatePointDescriptor || updateCellArrayDescriptor) ? "rebuilt" : "")
@@ -1399,13 +1404,6 @@ void vtkWebGPUPolyDataMapper::UpdateMeshGeometryBuffers(vtkWebGPURenderWindow* w
                 << ((updatePointDescriptor || updateCellArrayDescriptor)
                        ? " buffers"
                        : "reuse point and cell buffers"));
-  if (updatePointDescriptor || updateCellArrayDescriptor)
-  {
-    // Create bind group for the point/cell attribute buffers.
-    this->MeshAttributeBindGroup =
-      this->CreateMeshAttributeBindGroup(wgpuConfiguration->GetDevice(), "MeshAttributeBindGroup");
-    this->RebuildGraphicsPipelines = true;
-  }
 }
 
 //------------------------------------------------------------------------------
@@ -1833,6 +1831,7 @@ void vtkWebGPUPolyDataMapper::DispatchCellToPrimitiveComputePipeline(
 void vtkWebGPUPolyDataMapper::SetupGraphicsPipelines(
   const wgpu::Device& device, vtkRenderer* renderer, vtkActor* actor)
 {
+  auto* wgpuActor = vtkWebGPUActor::SafeDownCast(actor);
   auto* wgpuRenderWindow = vtkWebGPURenderWindow::SafeDownCast(renderer->GetRenderWindow());
   auto* wgpuRenderer = vtkWebGPURenderer::SafeDownCast(renderer);
   auto* wgpuPipelineCache = wgpuRenderWindow->GetWGPUPipelineCache();
@@ -1862,6 +1861,7 @@ void vtkWebGPUPolyDataMapper::SetupGraphicsPipelines(
 
   std::vector<wgpu::BindGroupLayout> bgls;
   wgpuRenderer->PopulateBindgroupLayouts(bgls);
+  wgpuActor->PopulateBindgroupLayouts(bgls);
   bgls.emplace_back(
     this->CreateMeshAttributeBindGroupLayout(device, "MeshAttributeBindGroupLayout"));
   bgls.emplace_back(this->CreateTopologyBindGroupLayout(device, "TopologyBindGroupLayout"));
@@ -1885,14 +1885,16 @@ void vtkWebGPUPolyDataMapper::SetupGraphicsPipelines(
 }
 
 //------------------------------------------------------------------------------
-bool vtkWebGPUPolyDataMapper::GetNeedToRebuildGraphicsPipelines(vtkActor* actor)
+bool vtkWebGPUPolyDataMapper::GetNeedToRebuildGraphicsPipelines(
+  vtkActor* actor, vtkRenderer* renderer)
 {
   if (this->RebuildGraphicsPipelines)
   {
     return true;
   }
-  auto it = this->CachedActorProperties.find(actor);
-  if (it == this->CachedActorProperties.end())
+  const auto key = std::make_pair(actor, renderer);
+  auto it = this->CachedActorRendererProperties.find(key);
+  if (it == this->CachedActorRendererProperties.end())
   {
     return true;
   }
@@ -1939,7 +1941,7 @@ void vtkWebGPUPolyDataMapper::ReleaseGraphicsResources(vtkWindow* w)
     this->IndirectDrawBufferUploadTimeStamp[i] = vtkTimeStamp();
   }
   this->RebuildGraphicsPipelines = true;
-  this->CachedActorProperties.clear();
+  this->CachedActorRendererProperties.clear();
 }
 
 //------------------------------------------------------------------------------
diff --git a/Rendering/WebGPU/vtkWebGPUPolyDataMapper.h b/Rendering/WebGPU/vtkWebGPUPolyDataMapper.h
index 30c4aa4375aa0ee9c6964e23a563add20be86244..9c7e5dfb962b2ecd0b3cbc74cc1c31c9c355258e 100644
--- a/Rendering/WebGPU/vtkWebGPUPolyDataMapper.h
+++ b/Rendering/WebGPU/vtkWebGPUPolyDataMapper.h
@@ -7,6 +7,7 @@
 
 #include "vtkProperty.h"              // for VTK_SURFACE constants
 #include "vtkRenderingWebGPUModule.h" // for export macro
+#include "vtkWeakPointer.h"           // for vtkWeakPointer
 #include "vtkWebGPUComputePipeline.h" // for ivar
 #include "vtk_wgpu.h"                 // for webgpu
 
@@ -203,7 +204,7 @@ protected:
    * This method returns true if the cached properties have changed or the properties of the actor
    * are cached for the first time, false otherwise.
    */
-  bool CacheActorProperties(vtkActor* actor);
+  bool CacheActorRendererProperties(vtkActor* actor, vtkRenderer* renderer);
 
   /**
    * Record draw calls in the render pass encoder. It also sets the bind group, graphics pipeline to
@@ -437,7 +438,7 @@ protected:
    * This method checks MTime of the vtkActor's vtkProperty instance against the build timestamp of
    * the graphics pipeline.
    */
-  bool GetNeedToRebuildGraphicsPipelines(vtkActor* actor);
+  bool GetNeedToRebuildGraphicsPipelines(vtkActor* actor, vtkRenderer* renderer);
 
   struct MeshAttributeBuffers
   {
@@ -542,7 +543,8 @@ protected:
     int LastRepresentation = VTK_SURFACE;
     bool LastHasRenderingTranslucentGeometry = false;
   };
-  std::map<vtkWeakPointer<vtkActor>, ActorState> CachedActorProperties;
+  std::map<std::pair<vtkWeakPointer<vtkActor>, vtkWeakPointer<vtkRenderer>>, ActorState>
+    CachedActorRendererProperties;
 
 private:
   friend class vtkWebGPUComputeRenderBuffer;
diff --git a/Rendering/WebGPU/vtkWebGPURenderWindow.cxx b/Rendering/WebGPU/vtkWebGPURenderWindow.cxx
index fdaa98faf9c5f2348f0634e308dcd684492c2e3f..5ded0108e8c9246e2acdcc43c547df99940e3008 100644
--- a/Rendering/WebGPU/vtkWebGPURenderWindow.cxx
+++ b/Rendering/WebGPU/vtkWebGPURenderWindow.cxx
@@ -590,7 +590,6 @@ void vtkWebGPURenderWindow::CreateFSQGraphicsPipeline()
   wgpu::ShaderModule shaderModule = vtkWebGPUShaderModuleInternals::CreateFromWGSL(device, R"(
     struct VertexOutput {
       @builtin(position) position: vec4<f32>,
-      @location(0) uv: vec2<f32>
     }
 
     @vertex
@@ -603,22 +602,20 @@ void vtkWebGPURenderWindow::CreateFSQGraphicsPipeline()
         vec2<f32>( 1,  1)  // top-right
       );
       output.position = vec4<f32>(coords[vertex_id].xy, 1.0, 1.0);
-      output.uv = output.position.xy * 0.5 + 0.5;
-      // fip y for texture coordinate.
-      output.uv.y = 1.0 - output.uv.y;
       return output;
     }
 
     struct FragmentInput {
       @builtin(position) position: vec4<f32>,
-      @location(0) uv: vec2<f32>
     }
 
     @group(0) @binding(0) var fsqTexture: texture_2d<f32>;
 
     @fragment
     fn fragmentMain(fragment: FragmentInput) -> @location(0) vec4<f32> {
-      let color = textureLoad(fsqTexture, vec2<i32>(fragment.position.xy), 0);
+      let dims = textureDimensions(fsqTexture);
+      let texCoord = vec2(u32(fragment.position.x), dims.y - 1u - u32(fragment.position.y));
+      let color = textureLoad(fsqTexture, texCoord, 0);
       return vec4<f32>(color);
     }
   )");
diff --git a/Rendering/WebGPU/vtkWebGPURenderer.cxx b/Rendering/WebGPU/vtkWebGPURenderer.cxx
index 3221de34516b87d46b0a3a12b914045fe58ace5e..75777e2d12672e3337558c508ca6e86ecfa5212f 100644
--- a/Rendering/WebGPU/vtkWebGPURenderer.cxx
+++ b/Rendering/WebGPU/vtkWebGPURenderer.cxx
@@ -3,8 +3,8 @@
 #include "vtkWebGPURenderer.h"
 #include "Private/vtkWebGPUBindGroupInternals.h"
 #include "Private/vtkWebGPUBindGroupLayoutInternals.h"
-#include "Private/vtkWebGPUBufferInternals.h"
 #include "Private/vtkWebGPUComputePassInternals.h"
+#include "Private/vtkWebGPURenderPipelineDescriptorInternals.h"
 #include "vtkAbstractMapper.h"
 #include "vtkFrameBufferObjectBase.h"
 #include "vtkHardwareSelector.h"
@@ -30,6 +30,53 @@
 
 VTK_ABI_NAMESPACE_BEGIN
 
+namespace
+{
+const char* backgroundShaderSource = R"(
+    struct VertexOutput {
+      @builtin(position) position: vec4<f32>,
+    }
+
+    @vertex
+    fn vertexMain(@builtin(vertex_index) vertex_id: u32) -> VertexOutput {
+      var output: VertexOutput;
+      var coords: array<vec2<f32>, 4> = array<vec2<f32>, 4>(
+        vec2<f32>(-1, -1), // bottom-left
+        vec2<f32>(-1,  1), // top-left
+        vec2<f32>( 1, -1), // bottom-right
+        vec2<f32>( 1,  1)  // top-right
+      );
+      output.position = vec4<f32>(coords[vertex_id].xy, 1.0, 1.0);
+      return output;
+    }
+
+    struct FragmentInput {
+      @builtin(position) position: vec4<f32>
+    };
+    struct FragmentOutput {
+      @location(0) color: vec4<f32>
+    };
+
+    @fragment
+    fn fragmentMain() -> FragmentOutput {
+      var output: FragmentOutput;
+      output.color = vec4<f32>(1, 1, 1, 1);
+      return output;
+    }
+  )";
+
+vtkWebGPURenderPass* MakeClearDrawPass()
+{
+  auto* pass = vtkWebGPUClearDrawPass::New();
+  // do not clear color because doing so would erase the contents of the entire
+  // color attachment, including other renderer's viewports!
+  pass->SetClearColor(false);
+  pass->SetClearDepth(false);
+  pass->SetClearStencil(false);
+  return pass;
+}
+}
+
 //------------------------------------------------------------------------------
 vtkStandardNewMacro(vtkWebGPURenderer);
 
@@ -92,32 +139,6 @@ std::size_t vtkWebGPURenderer::WriteLightsBuffer(std::size_t offset /*=0*/)
   return wroteBytes;
 }
 
-//------------------------------------------------------------------------------
-std::size_t vtkWebGPURenderer::WriteActorBlocksBuffer(std::size_t offset /*=0*/)
-{
-  std::size_t wroteBytes = 0;
-  auto* wgpuRenderWindow = vtkWebGPURenderWindow::SafeDownCast(this->GetRenderWindow());
-  auto* wgpuConfiguration = wgpuRenderWindow->GetWGPUConfiguration();
-
-  const auto size = vtkWebGPUConfiguration::Align(vtkWebGPUActor::GetCacheSizeBytes(), 256);
-  std::vector<uint8_t> stage;
-  stage.resize(this->Props->GetNumberOfItems() * size);
-  vtkProp* aProp = nullptr;
-  vtkCollectionSimpleIterator piter;
-  for (this->Props->InitTraversal(piter); (aProp = this->Props->GetNextProp(piter));)
-  {
-    vtkWebGPUActor* wgpuActor = reinterpret_cast<vtkWebGPUActor*>(aProp);
-    assert(wgpuActor != nullptr);
-
-    const auto data = wgpuActor->GetCachedActorInformation();
-    std::memcpy(&stage[wroteBytes], data, size);
-    wroteBytes += size;
-  }
-  wgpuConfiguration->WriteBuffer(
-    this->ActorBlocksBuffer, offset, stage.data(), wroteBytes, "ActorInformation");
-  return wroteBytes;
-}
-
 //------------------------------------------------------------------------------
 void vtkWebGPURenderer::CreateBuffers()
 {
@@ -128,15 +149,9 @@ void vtkWebGPURenderer::CreateBuffers()
     + this->LightIDs.size() * vtkWebGPULight::GetCacheSizeBytes();
   const auto lightSizePadded = vtkWebGPUConfiguration::Align(lightSize, 32);
 
-  // use padded for actor because dynamic offsets are used.
-  const auto actorBlkSize = vtkMath::Max<std::size_t>(this->Props->GetNumberOfItems() *
-      vtkWebGPUConfiguration::Align(vtkWebGPUActor::GetCacheSizeBytes(), 256),
-    256);
-
   auto* wgpuRenderWindow = vtkWebGPURenderWindow::SafeDownCast(this->GetRenderWindow());
   auto* wgpuConfiguration = wgpuRenderWindow->GetWGPUConfiguration();
   bool createSceneBindGroup = false;
-  bool createActorBindGroup = false;
 
   if (this->SceneTransformBuffer == nullptr)
   {
@@ -154,46 +169,65 @@ void vtkWebGPURenderer::CreateBuffers()
     createSceneBindGroup = true;
   }
 
-  if (actorBlkSize != this->LastActorBufferSize)
-  {
-    if (this->ActorBlocksBuffer != nullptr)
-    {
-      this->ActorBlocksBuffer.Destroy();
-      this->ActorBlocksBuffer = nullptr;
-    }
-  }
-  if (this->ActorBlocksBuffer == nullptr)
+  if (createSceneBindGroup)
   {
-    const std::string label = "ActorInformation-" + this->GetObjectDescription();
-    this->ActorBlocksBuffer = wgpuConfiguration->CreateBuffer(
-      actorBlkSize, wgpu::BufferUsage::Uniform | wgpu::BufferUsage::CopyDst, false, label.c_str());
-    this->LastActorBufferSize = actorBlkSize;
-    createActorBindGroup = true;
+    this->SetupSceneBindGroup();
   }
+}
 
-  if (createSceneBindGroup)
+//------------------------------------------------------------------------------
+void vtkWebGPURenderer::Clear()
+{
+  if (!this->DoClearPass)
   {
-    this->SetupSceneBindGroup();
+    return;
   }
 
-  if (createActorBindGroup)
+  // Draw a quad as big as viewport and colored by the background color.
+  auto* wgpuRenderWindow = vtkWebGPURenderWindow::SafeDownCast(this->RenderWindow);
+  auto* wgpuPipelineCache = wgpuRenderWindow->GetWGPUPipelineCache();
+  vtkWebGPURenderPipelineDescriptorInternals bkgPipelineDescriptor;
+  bkgPipelineDescriptor.vertex.entryPoint = "vertexMain";
+  bkgPipelineDescriptor.vertex.bufferCount = 0;
+  bkgPipelineDescriptor.cFragment.entryPoint = "fragmentMain";
+  bkgPipelineDescriptor.cTargets[0].format = wgpuRenderWindow->GetPreferredSurfaceTextureFormat();
+
+  auto depthState =
+    bkgPipelineDescriptor.EnableDepthStencil(wgpuRenderWindow->GetDepthStencilFormat());
+  depthState->depthWriteEnabled = !this->PreserveDepthBuffer;
+  depthState->depthCompare = wgpu::CompareFunction::Always;
+
+  bkgPipelineDescriptor.primitive.frontFace = wgpu::FrontFace::CCW;
+  bkgPipelineDescriptor.primitive.cullMode = wgpu::CullMode::Front;
+  bkgPipelineDescriptor.primitive.topology = wgpu::PrimitiveTopology::TriangleStrip;
+
+  for (int i = 0; i < vtkWebGPURenderPipelineDescriptorInternals::kMaxColorAttachments; ++i)
   {
-    // delete outdated info.
-    this->PropWGPUItems.clear();
-    this->SetupActorBindGroup();
-    // build new cache for bundles and dynamic offsets.
-    vtkProp* aProp = nullptr;
-    vtkCollectionSimpleIterator piter;
-    const auto size = vtkWebGPUConfiguration::Align(vtkWebGPUActor::GetCacheSizeBytes(), 256);
-    int i = 0;
-    for (this->Props->InitTraversal(piter); (aProp = this->Props->GetNextProp(piter)); i++)
+    if (this->Transparent())
+    {
+      bkgPipelineDescriptor.cBlends[i].color.srcFactor = wgpu::BlendFactor::Zero;
+      bkgPipelineDescriptor.cBlends[i].color.dstFactor = wgpu::BlendFactor::One;
+      bkgPipelineDescriptor.cBlends[i].alpha.srcFactor = wgpu::BlendFactor::Zero;
+      bkgPipelineDescriptor.cBlends[i].alpha.dstFactor = wgpu::BlendFactor::One;
+    }
+    else
     {
-      vtkWGPUPropItem item;
-      item.Bundle = nullptr;
-      item.DynamicOffset = i * size;
-      this->PropWGPUItems.emplace(aProp, item);
+      bkgPipelineDescriptor.cBlends[i].color.srcFactor = wgpu::BlendFactor::Constant;
+      bkgPipelineDescriptor.cBlends[i].color.dstFactor = wgpu::BlendFactor::Zero;
+      bkgPipelineDescriptor.cBlends[i].alpha.srcFactor = wgpu::BlendFactor::Constant;
+      bkgPipelineDescriptor.cBlends[i].alpha.dstFactor = wgpu::BlendFactor::Zero;
     }
   }
+  const auto pipelineKey =
+    wgpuPipelineCache->GetPipelineKey(&bkgPipelineDescriptor, backgroundShaderSource);
+  wgpuPipelineCache->CreateRenderPipeline(&bkgPipelineDescriptor, this, backgroundShaderSource);
+  auto pipeline = wgpuPipelineCache->GetRenderPipeline(pipelineKey);
+
+  this->WGPURenderEncoder.SetPipeline(pipeline);
+  wgpu::Color bkgColor = { this->Background[0], this->Background[1], this->Background[2],
+    this->BackgroundAlpha };
+  this->WGPURenderEncoder.SetBlendConstant(&bkgColor);
+  this->WGPURenderEncoder.Draw(4);
 }
 
 //------------------------------------------------------------------------------
@@ -228,12 +262,24 @@ void vtkWebGPURenderer::UpdateBuffers()
   this->UpdateCamera(); // brings the camera's transform matrices up-to-date.
   this->UpdateLightGeometry();
   this->UpdateLights();
+
+  // Render bundle is rebuilt if any mapper needs to re-record render commands.
+  if (this->UseRenderBundles)
+  {
+    if (this->Bundle != nullptr)
+    {
+      this->RebuildRenderBundle = false;
+    }
+    else
+    {
+      this->RebuildRenderBundle = true;
+    }
+  }
   this->UpdateGeometry(); // mappers prepare geometry SSBO and pipeline layout.
 
   this->CreateBuffers();
   this->WriteSceneTransformsBuffer();
   this->WriteLightsBuffer();
-  this->WriteActorBlocksBuffer();
 }
 
 //------------------------------------------------------------------------------
@@ -349,14 +395,7 @@ int vtkWebGPURenderer::UpdateOpaquePolygonalGeometry()
     {
       for (int i = 0; i < this->PropArrayCount; i++)
       {
-        auto wgpuActor = reinterpret_cast<vtkWebGPUActor*>(this->PropArray[i]);
-        wgpuActor->RenderOpaqueGeometry(this);
-        if (wgpuActor->GetBundleInvalidated())
-        {
-          // mapper's buffers and bind points have changed. bundle is outdated.
-          auto& wgpuPropItem = this->PropWGPUItems[this->PropArray[i]];
-          wgpuPropItem.Bundle = nullptr;
-        }
+        this->PropArray[i]->RenderOpaqueGeometry(this);
       }
       result += this->PropArrayCount;
     }
@@ -365,69 +404,12 @@ int vtkWebGPURenderer::UpdateOpaquePolygonalGeometry()
     {
       for (int i = 0; i < this->PropArrayCount; i++)
       {
-        if (auto* wgpuActor = vtkWebGPUActor::SafeDownCast(this->PropArray[i]))
-        {
-          int rendered = 0;
-          auto& wgpuPropItem = this->PropWGPUItems[this->PropArray[i]];
-          if (wgpuActor->SupportRenderBundles() && this->UseRenderBundles)
-          {
-            this->BundleCacheStats.TotalRequests++;
-            if (wgpuPropItem.Bundle == nullptr)
-            {
-              const std::string label = this->GetObjectDescription();
-              auto wgpuRenderWindow = vtkWebGPURenderWindow::SafeDownCast(this->GetRenderWindow());
-              const auto colorFormat = wgpuRenderWindow->GetPreferredSurfaceTextureFormat();
-              const int sampleCount =
-                wgpuRenderWindow->GetMultiSamples() ? wgpuRenderWindow->GetMultiSamples() : 1;
-              wgpu::RenderBundleEncoderDescriptor bundleEncDesc;
-              bundleEncDesc.colorFormatCount = 1;
-              bundleEncDesc.colorFormats = &colorFormat;
-              bundleEncDesc.depthStencilFormat = wgpuRenderWindow->GetDepthStencilFormat();
-              bundleEncDesc.sampleCount = sampleCount;
-              bundleEncDesc.depthReadOnly = false;
-              bundleEncDesc.stencilReadOnly = false;
-              bundleEncDesc.label = label.c_str();
-              bundleEncDesc.nextInChain = nullptr;
-              this->WGPUBundleEncoder = wgpuRenderWindow->NewRenderBundleEncoder(bundleEncDesc);
-              this->WGPUBundleEncoder.SetBindGroup(0, this->SceneBindGroup);
-              this->WGPUBundleEncoder.SetBindGroup(
-                1, this->ActorBindGroup, 1, &wgpuPropItem.DynamicOffset);
-              rendered = wgpuActor->RenderOpaqueGeometry(this);
-              auto bundle = this->WGPUBundleEncoder.Finish();
-              this->WGPUBundleEncoder = nullptr;
-              if (rendered > 0)
-              {
-                wgpuPropItem.Bundle = bundle;
-                this->Bundles.emplace_back(wgpuPropItem.Bundle);
-              }
-              this->BundleCacheStats.Misses++;
-            }
-            else
-            {
-              // bundle gets reused for this prop.
-              rendered = 1;
-              this->Bundles.emplace_back(wgpuPropItem.Bundle);
-              this->BundleCacheStats.Hits++;
-            }
-          }
-          else
-          {
-            this->WGPURenderEncoder.SetBindGroup(
-              1, this->ActorBindGroup, 1, &wgpuPropItem.DynamicOffset);
-            rendered = wgpuActor->RenderOpaqueGeometry(this);
-          }
-          if (rendered > 0)
-          {
-            result += rendered;
-
-            this->NumberOfPropsRendered += rendered;
-            this->PropsRendered.insert(wgpuActor);
-          }
-        }
-        else
+        const int rendered = this->PropArray[i]->RenderOpaqueGeometry(this);
+        if (rendered > 0)
         {
-          vtkWarningMacro(<< "Prop " << this->PropArray[i]->GetObjectDescription()
-                          << " is unrecognized in the vtkWebGPURenderer.");
+          result += rendered;
+          this->NumberOfPropsRendered += rendered;
+          this->PropsRendered.insert(this->PropArray[i]);
         }
       }
     }
@@ -449,14 +431,7 @@ int vtkWebGPURenderer::UpdateTranslucentPolygonalGeometry()
     {
       for (int i = 0; i < this->PropArrayCount; i++)
       {
-        auto wgpuActor = reinterpret_cast<vtkWebGPUActor*>(this->PropArray[i]);
-        wgpuActor->RenderTranslucentPolygonalGeometry(this);
-        if (wgpuActor->GetBundleInvalidated())
-        {
-          // mapper's buffers and bind points have changed. bundle is outdated.
-          auto& wgpuPropItem = this->PropWGPUItems[this->PropArray[i]];
-          wgpuPropItem.Bundle = nullptr;
-        }
+        this->PropArray[i]->RenderTranslucentPolygonalGeometry(this);
       }
       result += this->PropArrayCount;
     }
@@ -465,69 +440,12 @@ int vtkWebGPURenderer::UpdateTranslucentPolygonalGeometry()
     {
       for (int i = 0; i < this->PropArrayCount; i++)
       {
-        if (auto* wgpuActor = vtkWebGPUActor::SafeDownCast(this->PropArray[i]))
+        const int rendered = this->PropArray[i]->RenderTranslucentPolygonalGeometry(this);
+        if (rendered > 0)
         {
-          int rendered = 0;
-          auto& wgpuPropItem = this->PropWGPUItems[this->PropArray[i]];
-          if (wgpuActor->SupportRenderBundles() && this->UseRenderBundles)
-          {
-            this->BundleCacheStats.TotalRequests++;
-            if (wgpuPropItem.Bundle == nullptr)
-            {
-              const std::string label = this->GetObjectDescription();
-              auto wgpuRenderWindow = vtkWebGPURenderWindow::SafeDownCast(this->GetRenderWindow());
-              const auto colorFormat = wgpuRenderWindow->GetPreferredSurfaceTextureFormat();
-              const int sampleCount =
-                wgpuRenderWindow->GetMultiSamples() ? wgpuRenderWindow->GetMultiSamples() : 1;
-              wgpu::RenderBundleEncoderDescriptor bundleEncDesc;
-              bundleEncDesc.colorFormatCount = 1;
-              bundleEncDesc.colorFormats = &colorFormat;
-              bundleEncDesc.depthStencilFormat = wgpuRenderWindow->GetDepthStencilFormat();
-              bundleEncDesc.sampleCount = sampleCount;
-              bundleEncDesc.depthReadOnly = false;
-              bundleEncDesc.stencilReadOnly = false;
-              bundleEncDesc.label = label.c_str();
-              bundleEncDesc.nextInChain = nullptr;
-              this->WGPUBundleEncoder = wgpuRenderWindow->NewRenderBundleEncoder(bundleEncDesc);
-              this->WGPUBundleEncoder.SetBindGroup(0, this->SceneBindGroup);
-              this->WGPUBundleEncoder.SetBindGroup(
-                1, this->ActorBindGroup, 1, &wgpuPropItem.DynamicOffset);
-              rendered = wgpuActor->RenderTranslucentPolygonalGeometry(this);
-              auto bundle = this->WGPUBundleEncoder.Finish();
-              this->WGPUBundleEncoder = nullptr;
-              if (rendered > 0)
-              {
-                wgpuPropItem.Bundle = bundle;
-                this->Bundles.emplace_back(wgpuPropItem.Bundle);
-              }
-              this->BundleCacheStats.Misses++;
-            }
-            else
-            {
-              // bundle gets reused for this prop.
-              rendered = 1;
-              this->Bundles.emplace_back(wgpuPropItem.Bundle);
-              this->BundleCacheStats.Hits++;
-            }
-          }
-          else
-          {
-            this->WGPURenderEncoder.SetBindGroup(
-              1, this->ActorBindGroup, 1, &wgpuPropItem.DynamicOffset);
-            rendered = wgpuActor->RenderTranslucentPolygonalGeometry(this);
-          }
-          if (rendered > 0)
-          {
-            result += rendered;
-
-            this->NumberOfPropsRendered += rendered;
-            this->PropsRendered.insert(wgpuActor);
-          }
-        }
-        else
-        {
-          vtkWarningMacro(<< "Prop " << this->PropArray[i]->GetObjectDescription()
-                          << " is unrecognized in the vtkWebGPURenderer.");
+          result += rendered;
+          this->NumberOfPropsRendered += rendered;
+          this->PropsRendered.insert(this->PropArray[i]);
         }
       }
     }
@@ -803,17 +721,14 @@ void vtkWebGPURenderer::SetEnvironmentTexture(vtkTexture*, bool vtkNotUsed(isSRG
 void vtkWebGPURenderer::ReleaseGraphicsResources(vtkWindow* w)
 {
   this->Superclass::ReleaseGraphicsResources(w);
-  this->Bundles.clear();
-  this->PropWGPUItems.clear();
+  this->Bundle = nullptr;
+  this->WGPUBundleEncoder = nullptr;
   this->WGPURenderEncoder = nullptr;
   this->SceneTransformBuffer = nullptr;
   this->SceneLightsBuffer = nullptr;
-  this->ActorBlocksBuffer = nullptr;
   this->LastActorBufferSize = 0;
   this->SceneBindGroup = nullptr;
   this->SceneBindGroupLayout = nullptr;
-  this->ActorBindGroup = nullptr;
-  this->ActorBindGroupLayout = nullptr;
 }
 
 //------------------------------------------------------------------------------
@@ -856,6 +771,7 @@ wgpu::CommandBuffer vtkWebGPURenderer::EncodePropListRenderCommand(
   this->PropArrayCount = listLength;
 
   this->BeginRecording();
+  this->ActiveCamera->UpdateViewport(this);
   this->UpdateGeometry();
   this->EndRecording();
 
@@ -884,20 +800,39 @@ void vtkWebGPURenderer::BeginRecording()
   vtkRenderState state(this);
   state.SetPropArrayAndCount(this->PropArray, this->PropArrayCount);
   state.SetFrameBuffer(nullptr);
-  this->Pass = vtkWebGPUClearDrawPass::New();
-
-  vtkWebGPUClearDrawPass::SafeDownCast(this->Pass)->SetDoClear(this->DoClearPass);
+  this->Pass = ::MakeClearDrawPass();
 
   this->WGPURenderEncoder = vtkWebGPURenderPass::SafeDownCast(this->Pass)->Begin(&state);
 #ifndef NDEBUG
   this->WGPURenderEncoder.PushDebugGroup("Renderer start encoding");
 #endif
   this->WGPURenderEncoder.SetBindGroup(0, this->SceneBindGroup);
-
-  this->Bundles.clear();
-  this->BundleCacheStats.TotalRequests = 0;
-  this->BundleCacheStats.Hits = 0;
-  this->BundleCacheStats.Misses = 0;
+  if (this->RebuildRenderBundle)
+  {
+    // destroy previous bundle.
+    this->Bundle = nullptr;
+    // create a new bundle encoder.
+    const std::string label = this->GetObjectDescription();
+    auto wgpuRenderWindow = vtkWebGPURenderWindow::SafeDownCast(this->GetRenderWindow());
+    const auto colorFormat = wgpuRenderWindow->GetPreferredSurfaceTextureFormat();
+    const int sampleCount =
+      wgpuRenderWindow->GetMultiSamples() ? wgpuRenderWindow->GetMultiSamples() : 1;
+    wgpu::RenderBundleEncoderDescriptor bundleEncDesc;
+    bundleEncDesc.colorFormatCount = 1;
+    bundleEncDesc.colorFormats = &colorFormat;
+    bundleEncDesc.depthStencilFormat = wgpuRenderWindow->GetDepthStencilFormat();
+    bundleEncDesc.sampleCount = sampleCount;
+    bundleEncDesc.depthReadOnly = false;
+    bundleEncDesc.stencilReadOnly = false;
+    bundleEncDesc.label = label.c_str();
+    bundleEncDesc.nextInChain = nullptr;
+    this->WGPUBundleEncoder = wgpuRenderWindow->NewRenderBundleEncoder(bundleEncDesc);
+    this->WGPUBundleEncoder.SetBindGroup(0, this->SceneBindGroup);
+  }
+  else
+  {
+    this->WGPUBundleEncoder = nullptr;
+  }
 }
 
 //------------------------------------------------------------------------------
@@ -919,19 +854,6 @@ void vtkWebGPURenderer::SetupBindGroupLayouts()
 
     this->SceneBindGroupLayout.SetLabel("SceneBindGroupLayout");
   }
-
-  if (this->ActorBindGroupLayout.Get() == nullptr)
-  {
-    this->ActorBindGroupLayout = vtkWebGPUBindGroupLayoutInternals::MakeBindGroupLayout(device,
-      {
-        // clang-format off
-      // ActorBlocks
-      { 0, wgpu::ShaderStage::Vertex | wgpu::ShaderStage::Fragment, wgpu::BufferBindingType::Uniform, /*hasDynamicOffsets=*/true },
-        // clang-format on
-      });
-
-    this->ActorBindGroupLayout.SetLabel("ActorBindGroupLayout");
-  }
 }
 
 //------------------------------------------------------------------------------
@@ -951,21 +873,6 @@ void vtkWebGPURenderer::SetupSceneBindGroup()
   this->SceneBindGroup.SetLabel("SceneBindGroup");
 }
 
-//------------------------------------------------------------------------------
-void vtkWebGPURenderer::SetupActorBindGroup()
-{
-  auto wgpuRenderWindow = vtkWebGPURenderWindow::SafeDownCast(this->GetRenderWindow());
-  wgpu::Device device = wgpuRenderWindow->GetDevice();
-  this->ActorBindGroup =
-    vtkWebGPUBindGroupInternals::MakeBindGroup(device, this->ActorBindGroupLayout,
-      {
-        // clang-format off
-        { 0, this->ActorBlocksBuffer, 0, vtkWebGPUConfiguration::Align(vtkWebGPUActor::GetCacheSizeBytes(), 256) },
-        // clang-format on
-      });
-  this->ActorBindGroup.SetLabel("ActorBindGroup");
-}
-
 //------------------------------------------------------------------------------
 void vtkWebGPURenderer::EndRecording()
 {
@@ -973,19 +880,13 @@ void vtkWebGPURenderer::EndRecording()
   this->RenderStage = RenderStageEnum::Finished;
   if (this->UseRenderBundles)
   {
-    if (!this->Bundles.empty() && this->BundleCacheStats.TotalRequests > 0)
+    if (this->WGPUBundleEncoder)
+    {
+      this->Bundle = this->WGPUBundleEncoder.Finish();
+    }
+    if (this->Bundle != nullptr)
     {
-      vtkDebugMacro(<< "Bundle cache summary:\n"
-                    << "Total requests: " << this->BundleCacheStats.TotalRequests << "\n"
-                    << "Hit ratio: "
-                    << (this->BundleCacheStats.Hits / this->BundleCacheStats.TotalRequests) * 100
-                    << "%\n"
-                    << "Miss ratio: "
-                    << (this->BundleCacheStats.Misses / this->BundleCacheStats.TotalRequests) * 100
-                    << "%\n"
-                    << "Hit: " << this->BundleCacheStats.Hits << "\n"
-                    << "Miss: " << this->BundleCacheStats.Misses << "\n");
-      this->WGPURenderEncoder.ExecuteBundles(this->Bundles.size(), this->Bundles.data());
+      this->WGPURenderEncoder.ExecuteBundles(1, &this->Bundle);
     }
   }
 #ifndef NDEBUG
diff --git a/Rendering/WebGPU/vtkWebGPURenderer.h b/Rendering/WebGPU/vtkWebGPURenderer.h
index 69b3b90bb33b09195bdd8fc42c86be59e66422f6..8c4eae9c612b27a17438084d6a60ab67d61b37bb 100644
--- a/Rendering/WebGPU/vtkWebGPURenderer.h
+++ b/Rendering/WebGPU/vtkWebGPURenderer.h
@@ -10,8 +10,6 @@
 #include "vtkWebGPUComputePipeline.h" // for the compute pipelines used by this renderer
 #include "vtk_wgpu.h"                 // for webgpu
 
-#include <string>        // for ivar
-#include <unordered_map> // for ivar
 #include <unordered_set> // for the set of actors rendered last frame
 
 class vtkAbstractMapper;
@@ -58,6 +56,11 @@ public:
     RenderPostRasterization
   };
 
+  /**
+   * Clear the image to the background color.
+   */
+  void Clear() override;
+
   /**
    * Create an image.
    */
@@ -110,13 +113,11 @@ public:
 
   inline wgpu::RenderPassEncoder GetRenderPassEncoder() { return this->WGPURenderEncoder; }
   inline wgpu::RenderBundleEncoder GetRenderBundleEncoder() { return this->WGPUBundleEncoder; }
-  inline wgpu::BindGroup GetActorBindGroup() { return this->ActorBindGroup; }
   inline wgpu::BindGroup GetSceneBindGroup() { return this->SceneBindGroup; }
 
   inline void PopulateBindgroupLayouts(std::vector<wgpu::BindGroupLayout>& layouts)
   {
     layouts.emplace_back(this->SceneBindGroupLayout);
-    layouts.emplace_back(this->ActorBindGroupLayout);
   }
 
   /// @{
@@ -165,6 +166,19 @@ public:
    */
   vtkGetEnumMacro(RenderStage, RenderStageEnum);
 
+  /**
+   * Forces the renderer to re-record draw commands into a render bundle.
+   *
+   * @note This does not use vtkSetMacro because the actor MTime should not be affected when a
+   * render bundle is invalidated.
+   */
+  inline void InvalidateBundle() { this->RebuildRenderBundle = true; }
+
+  /**
+   * Get whether the render bundle associated with this actor must be reset by the renderer.
+   */
+  vtkGetMacro(RebuildRenderBundle, bool);
+
 protected:
   vtkWebGPURenderer();
   ~vtkWebGPURenderer() override;
@@ -184,8 +198,6 @@ protected:
   void CreateBuffers();
   // Create scene bind group.
   void SetupSceneBindGroup();
-  // Create actor bind group.
-  void SetupActorBindGroup();
 
   // Start, finish recording commands with render pass encoder
   void BeginRecording();
@@ -193,35 +205,23 @@ protected:
 
   std::size_t WriteLightsBuffer(std::size_t offset = 0);
   std::size_t WriteSceneTransformsBuffer(std::size_t offset = 0);
-  std::size_t WriteActorBlocksBuffer(std::size_t offset = 0);
 
   wgpu::RenderPassEncoder WGPURenderEncoder;
   wgpu::RenderBundleEncoder WGPUBundleEncoder;
   wgpu::Buffer SceneTransformBuffer;
   wgpu::Buffer SceneLightsBuffer;
-  wgpu::Buffer ActorBlocksBuffer;
   std::size_t LastActorBufferSize = 0;
   wgpu::BindGroup SceneBindGroup;
   wgpu::BindGroupLayout SceneBindGroupLayout;
 
-  wgpu::BindGroup ActorBindGroup;
-  wgpu::BindGroupLayout ActorBindGroupLayout;
-
 #ifdef __EMSCRIPTEN__
   bool UseRenderBundles = true;
 #else
   bool UseRenderBundles = false;
 #endif
-  // one bundle per actor. bundle gets reused every frame.
-  // these bundles can be built in parallel with vtkSMPTools. holding off because not
-  // sure how to get emscripten to thread.
-  std::vector<wgpu::RenderBundle> Bundles;
-  struct vtkWGPUPropItem
-  {
-    wgpu::RenderBundle Bundle = nullptr;
-    vtkTypeUInt32 DynamicOffset = 0;
-  };
-  std::unordered_map<vtkProp*, vtkWGPUPropItem> PropWGPUItems;
+  bool RebuildRenderBundle = false;
+  // the commands in bundle get reused every frame.
+  wgpu::RenderBundle Bundle;
 
   int LightingComplexity = 0;
   std::size_t NumberOfLightsUsed = 0;
@@ -230,13 +230,6 @@ protected:
   vtkMTimeType LightingUpdateTime;
   vtkTimeStamp LightingUploadTimestamp;
 
-  struct
-  {
-    uint32_t Hits = 0;
-    uint32_t Misses = 0;
-    uint32_t TotalRequests = 0;
-  } BundleCacheStats;
-
   /**
    * Optional user transform for lights
    */
diff --git a/Rendering/WebGPU/wgsl/LineMiterJoinVertexShader.wgsl b/Rendering/WebGPU/wgsl/LineMiterJoinVertexShader.wgsl
index e25057be6186d522328ec8dad66e1e44cf9f06b3..f29e73cbe1a271bad78142c7c393300d51f21cd5 100644
--- a/Rendering/WebGPU/wgsl/LineMiterJoinVertexShader.wgsl
+++ b/Rendering/WebGPU/wgsl/LineMiterJoinVertexShader.wgsl
@@ -85,7 +85,7 @@ struct Topology {
 ///-------------------------------------------------------------------
 // Everything shader needs from the vtkActor and it's vtkProperty
 ///-------------------------------------------------------------------
-@group(1) @binding(0) var<uniform> actor: ActorBlock;
+@group(1) @binding(0) var<storage, read> actor: ActorBlock;
 
 ///-----------------------------------------------------------------///
 // Mesh attributes.
diff --git a/Rendering/WebGPU/wgsl/LineRoundJoinVertexShader.wgsl b/Rendering/WebGPU/wgsl/LineRoundJoinVertexShader.wgsl
index 9e81b90a26d5e0d0b2ea0f6e3f5aeb9672d7b67c..a0773d1693f1354fa46b944c389224b9aa829d06 100644
--- a/Rendering/WebGPU/wgsl/LineRoundJoinVertexShader.wgsl
+++ b/Rendering/WebGPU/wgsl/LineRoundJoinVertexShader.wgsl
@@ -138,7 +138,7 @@ struct Topology {
 ///-------------------------------------------------------------------
 // Everything shader needs from the vtkActor and it's vtkProperty
 ///-------------------------------------------------------------------
-@group(1) @binding(0) var<uniform> actor: ActorBlock;
+@group(1) @binding(0) var<storage, read> actor: ActorBlock;
 
 ///-----------------------------------------------------------------///
 // Mesh attributes.
diff --git a/Rendering/WebGPU/wgsl/PointShader.wgsl b/Rendering/WebGPU/wgsl/PointShader.wgsl
index 33f217c7c99cbce79959c5d7e87226dcb7b9dbb1..193197ff5f9c43d1c55e534cd745f7bff98c33c1 100644
--- a/Rendering/WebGPU/wgsl/PointShader.wgsl
+++ b/Rendering/WebGPU/wgsl/PointShader.wgsl
@@ -89,7 +89,7 @@ struct Topology {
 ///-------------------------------------------------------------------
 // Everything shader needs from the vtkActor and it's vtkProperty
 ///-------------------------------------------------------------------
-@group(1) @binding(0) var<uniform> actor: ActorBlock;
+@group(1) @binding(0) var<storage, read> actor: ActorBlock;
 
 ///-----------------------------------------------------------------///
 // Mesh attributes.
diff --git a/Rendering/WebGPU/wgsl/SurfaceMeshShader.wgsl b/Rendering/WebGPU/wgsl/SurfaceMeshShader.wgsl
index c55ba3bfed2fe4a96f67d3dc21c67cf65d0f3df3..b918631485904e23a59003f52de2e4fdff104874 100644
--- a/Rendering/WebGPU/wgsl/SurfaceMeshShader.wgsl
+++ b/Rendering/WebGPU/wgsl/SurfaceMeshShader.wgsl
@@ -70,7 +70,7 @@ struct Topology {
 ///-------------------------------------------------------------------
 // Everything shader needs from the vtkActor and it's vtkProperty
 ///-------------------------------------------------------------------
-@group(1) @binding(0) var<uniform> actor: ActorBlock;
+@group(1) @binding(0) var<storage, read> actor: ActorBlock;
 
 ///-----------------------------------------------------------------///
 // Mesh attributes.