diff --git a/src/Cxx.md b/src/Cxx.md
index 45372abf982c1bcfd3133283559e08b72e8880a7..8318e7ad775f06c8101e5b69edaa1f2bebf0663b 100644
--- a/src/Cxx.md
+++ b/src/Cxx.md
@@ -870,6 +870,7 @@ This section includes vtkUnstructuredGrid.
 [Cone4](/Cxx/Rendering/Cone4) | Modifying properties and transformation matrix based on the VTK example Cone4.cxx.
 [DiffuseSpheres](/Cxx/Rendering/DiffuseSpheres) | Demonstrates the effect of diffuse lighting on spheres.
 [FlatVersusGouraud](/Cxx/Rendering/FlatVersusGouraud) | Flat and Gouraud shading. Different shading methods can dramatically improve the look of an object represented with polygons. On the top, flat shading uses a constant surface normal across each polygon. On the bottom, Gouraud shading interpolates normals from polygon vertices to give a smoother look.
+[GradientBackground](/Cxx/Rendering/GradientBackground) | Demonstrates the background shading options.
 [HiddenLineRemoval](/Cxx/Rendering/HiddenLineRemoval) | Hidden lines removed.
 [Mace](/Cxx/Rendering/Mace) | An example of multiple inputs and outputs.
 [Model](/Cxx/Rendering/Model) | Illustrative diagram of graphics objects.
diff --git a/src/Cxx/Rendering/CMakeLists.txt b/src/Cxx/Rendering/CMakeLists.txt
index 7a25ff4b1c446265504a1f417f3c6615e6a5f206..d212d9446cf13d297f1b2a4c22f6e5fafdce1f20 100644
--- a/src/Cxx/Rendering/CMakeLists.txt
+++ b/src/Cxx/Rendering/CMakeLists.txt
@@ -61,6 +61,8 @@ Requires_Cxx_Version(PBR_Mapping ${CXX_VERSION_MIN} ALL_FILES)
 Requires_Cxx_Version(PBR_Materials ${CXX_VERSION_MIN} ALL_FILES)
 Requires_Cxx_Version(PBR_Materials_Coat ${CXX_VERSION_MIN} ALL_FILES)
 
+Requires_Cxx_Version(GradientBackground ${CXX_VERSION_MIN} ALL_FILES)
+
 include(${WikiExamples_SOURCE_DIR}/CMake/RequiresModule.cmake)
 Requires_Module(PBR_Skybox cli11)
 Requires_Module(PBR_Skybox_Texturing cli11)
@@ -86,6 +88,8 @@ Requires_Module(PBR_Mapping jsoncpp)
 Requires_Module(PBR_Materials jsoncpp)
 Requires_Module(PBR_Materials_Coat jsoncpp)
 
+Requires_Module(GradientBackground cli11)
+
 
 foreach(SOURCE_FILE ${ALL_FILES})
   string(REPLACE ".cxx" "" TMP ${SOURCE_FILE})
@@ -103,6 +107,7 @@ if (BUILD_TESTING)
   set(KIT Rendering)
   set(NEEDS_ARGS
     FlatVersusGouraud
+    GradientBackground
     HiddenLineRemoval
     InterpolateCamera
     MotionBlur
@@ -135,6 +140,9 @@ if (BUILD_TESTING)
   add_test(${KIT}-FlatVersusGouraud ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${KIT}CxxTests
     TestFlatVersusGouraud ${DATA}/cow.obj)
 
+  add_test(${KIT}-GradientBackground ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${KIT}CxxTests
+    TestGradientBackground ${DATA}/star-wars-vader-tie-fighter.obj)
+
   add_test(${KIT}-HiddenLineRemoval ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${KIT}CxxTests
     TestHiddenLineRemoval ${DATA}/cow.obj)
 
diff --git a/src/Cxx/Rendering/GradientBackground.cxx b/src/Cxx/Rendering/GradientBackground.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..f4a959ecd431742e34a399ca155e151fb65974cb
--- /dev/null
+++ b/src/Cxx/Rendering/GradientBackground.cxx
@@ -0,0 +1,383 @@
+// Based on:
+//  https://gitlab.kitware.com/vtk/vtk/-/blob/master/Rendering/Core/Testing/Cxx/TestGradientBackground.cxx?ref_type=heads
+// See:
+//  [New in VTK 9.3: Radial Gradient
+//  Background](https://www.kitware.com/new-in-vtk-9-3-radial-gradient-background/)
+
+#include <vtkActor.h>
+#include <vtkActor2D.h>
+#include <vtkColor.h>
+#include <vtkConeSource.h>
+#include <vtkInteractorStyleTrackballCamera.h>
+#include <vtkNamedColors.h>
+#include <vtkNew.h>
+#include <vtkPolyDataMapper.h>
+#include <vtkProperty.h>
+#include <vtkRenderWindow.h>
+#include <vtkRenderWindowInteractor.h>
+#include <vtkRenderer.h>
+#include <vtkSphereSource.h>
+#include <vtkTextMapper.h>
+#include <vtkTextProperty.h>
+#include <vtkViewport.h>
+#include <vtk_cli11.h>
+
+// Readers
+#include <vtkBYUReader.h>
+#include <vtkOBJReader.h>
+#include <vtkPLYReader.h>
+#include <vtkPolyDataReader.h>
+#include <vtkSTLReader.h>
+#include <vtkXMLPolyDataReader.h>
+
+#include <vtkPolyDataMapper2D.h>
+#include <vtkPolyLine.h>
+#include <vtkProperty2D.h>
+
+#include <algorithm>
+#include <array>
+#include <cstdlib>
+#include <filesystem>
+#include <iomanip>
+#include <iostream>
+#include <string>
+
+namespace fs = std::filesystem;
+
+namespace {
+
+/**
+ * @brief ReadPolyData Read from a file containing vtkPolyData.
+ *
+ * ReadPolyData
+ *    If the path is empty a cone is returned.
+ *    If the extension is unknown a sphere is returned.
+ *
+ * @param path - The std::filesystem path to the file.
+ * @return The vtkPolyData.
+ */
+vtkNew<vtkPolyData> ReadPolyData(fs::path const& path);
+
+/**
+ * @brief ViewportBorder Set a border around a viewport.
+ *
+ * @param renderer - The renderer corresponding to the viewport.
+ * @param sides - A boolean array corresponding to [top, left, bottom, right].
+ * @param borderColor - The color of the border.
+ * @param borderWidth - The width of the border.
+ */
+void ViewportBorder(vtkRenderer* renderer, const std::array<bool, 4>& sides,
+                    std::string const& borderColor,
+                    double const& borderWidth = 2);
+
+} // namespace
+
+int main(int argc, char* argv[])
+{
+
+  CLI::App app{"Demonstrates the background shading options."};
+
+  // Define options
+  std::string fileName{""};
+  app.add_option("fileName", fileName,
+                 "A optional path to a file that contains vtkPolyData e.g. "
+                 "star-wars-vader-tie-fighter.obj");
+  CLI11_PARSE(app, argc, argv);
+
+  auto path = fs::path(fileName);
+  if (!path.empty())
+  {
+    if (!fs::is_regular_file(path))
+    {
+      std::cerr << "Unable to find: " << path << std::endl;
+      return EXIT_FAILURE;
+    }
+  }
+
+  auto pd = ReadPolyData(path);
+
+  vtkNew<vtkRenderWindow> renWin;
+  renWin->SetWindowName("GradientBackground");
+
+  vtkNew<vtkRenderWindowInteractor> iRen;
+  vtkNew<vtkRenderer> renderers[4];
+
+  // For each gradient specify the mode.
+  vtkViewport::GradientModes modes[4] = {
+      vtkViewport::GradientModes::VTK_GRADIENT_VERTICAL,
+      vtkViewport::GradientModes::VTK_GRADIENT_HORIZONTAL,
+      vtkViewport::GradientModes::VTK_GRADIENT_RADIAL_VIEWPORT_FARTHEST_SIDE,
+      vtkViewport::GradientModes::VTK_GRADIENT_RADIAL_VIEWPORT_FARTHEST_CORNER,
+  };
+
+  vtkNew<vtkNamedColors> colors;
+
+  vtkNew<vtkPolyDataMapper> mapper;
+  mapper->SetInputData(pd);
+
+  vtkNew<vtkActor> actor;
+  actor->SetMapper(mapper);
+  actor->GetProperty()->SetColor(colors->GetColor3d("Honeydew").GetData());
+  actor->GetProperty()->SetSpecular(0.3);
+  actor->GetProperty()->SetSpecularPower(60.0);
+
+  const auto renWidth = 640;
+  const auto renHeight = 480;
+
+  // The bounds for each view port.
+  double xmins[4] = {0.0, 0.5, 0.0, 0.5};
+  double ymins[4] = {0.0, 0.0, 0.5, 0.5};
+  double xmaxs[4] = {0.5, 1.0, 0.5, 1.0};
+  double ymaxs[4] = {0.5, 0.5, 1.0, 1.0};
+
+  // Here we select and name the colors.
+  // Feel free to change colors.
+  const auto bottomColor = colors->GetColor3d("Gold");
+  const auto topColor = colors->GetColor3d("OrangeRed");
+  const auto leftColor = colors->GetColor3d("Gold");
+  const auto rightColor = colors->GetColor3d("OrangeRed");
+  const auto centerColor = colors->GetColor3d("Gold");
+  const auto sideColor = colors->GetColor3d("OrangeRed");
+  const auto cornerColor = colors->GetColor3d("OrangeRed");
+
+  const std::array<std::string, 4> viewportTitle{"Vertical", "Horizontal",
+                                                 "Radial Farthest Side",
+                                                 "Radial Farthest Corner"};
+
+  // Create one text property for all.
+  vtkNew<vtkTextProperty> textProperty;
+  textProperty->SetJustificationToCentered();
+  textProperty->SetFontSize(renHeight / 12);
+  textProperty->SetColor(colors->GetColor3d("MidnightBlue").GetData());
+
+  vtkNew<vtkTextMapper> textMappers[4];
+  vtkNew<vtkActor2D> textActors[4];
+
+  // Define borders for the viewports {top, left, bottom, right}.
+  std::array<bool, 4> lb{false, true, true, false};
+  std::array<bool, 4> lbr{false, true, true, true};
+  std::array<bool, 4> tlb{true, true, true, false};
+  std::array<bool, 4> tlbr{true, true, true, true};
+  std::string borderColor = "DarkGreen";
+  auto borderWidth = 4.0;
+
+  for (int i = 0; i < 4; ++i)
+  {
+    auto textMapper = textMappers[i].Get();
+    textMapper->SetInput(viewportTitle[i].c_str());
+    textMapper->SetTextProperty(textProperty);
+
+    auto textActor = textActors[i].Get();
+    textActor->SetMapper(textMapper);
+    textActor->SetPosition(renWidth / 2, 8);
+
+    auto ren = renderers[i].Get();
+    ren->AddActor(textActor);
+    ren->AddActor(actor);
+    ren->GradientBackgroundOn();
+    ren->SetGradientMode(modes[i]);
+
+    ren->SetViewport(xmins[i], ymins[i], xmaxs[i], ymaxs[i]);
+
+    switch (i)
+    {
+    case 0:
+    default:
+      // Vertical
+      ren->SetBackground(bottomColor.GetData());
+      ren->SetBackground2(topColor.GetData());
+      ViewportBorder(ren, lb, borderColor, borderWidth);
+      break;
+    case 1:
+      // Horizontal
+      ren->SetBackground(leftColor.GetData());
+      ren->SetBackground2(rightColor.GetData());
+      ViewportBorder(ren, lbr, borderColor, borderWidth);
+      break;
+    case 2:
+      // Radial Farthest Side
+      ren->SetBackground(centerColor.GetData());
+      ren->SetBackground2(sideColor.GetData());
+      ViewportBorder(ren, tlb, borderColor, borderWidth);
+      break;
+    case 3:
+      // Radial Farthest Corner
+      ren->SetBackground(centerColor.GetData());
+      ren->SetBackground2(cornerColor.GetData());
+      ViewportBorder(ren, tlbr, borderColor, borderWidth);
+      break;
+    }
+
+    renWin->AddRenderer(ren);
+  }
+
+  renWin->SetInteractor(iRen);
+  renWin->Render();
+
+  vtkNew<vtkInteractorStyleTrackballCamera> style;
+  iRen->SetInteractorStyle(style);
+
+  iRen->Initialize();
+  iRen->UpdateSize(renWidth * 2, renHeight * 2);
+
+  iRen->Start();
+
+  return EXIT_SUCCESS;
+}
+
+namespace {
+
+vtkNew<vtkPolyData> ReadPolyData(fs::path const& path)
+{
+
+  vtkNew<vtkPolyData> polyData;
+
+  if (path.empty())
+  {
+    // Default to a cone if the path is empty.
+    vtkNew<vtkConeSource> source;
+    source->SetResolution(25);
+    source->SetDirection(0, 1, 0);
+    source->SetHeight(1);
+    source->Update();
+    polyData->DeepCopy(source->GetOutput());
+    return polyData;
+  }
+
+  std::string extension = path.extension().generic_string();
+  std::transform(extension.begin(), extension.end(), extension.begin(),
+                 [](char c) { return std::tolower(c); });
+
+  if (extension == ".ply")
+  {
+    vtkNew<vtkPLYReader> reader;
+    reader->SetFileName(path.c_str());
+    reader->Update();
+    polyData->DeepCopy(reader->GetOutput());
+  }
+  else if (extension == ".vtp")
+  {
+    vtkNew<vtkXMLPolyDataReader> reader;
+    reader->SetFileName(path.c_str());
+    reader->Update();
+    polyData->DeepCopy(reader->GetOutput());
+  }
+  else if (extension == ".obj")
+  {
+    vtkNew<vtkOBJReader> reader;
+    reader->SetFileName(path.c_str());
+    reader->Update();
+    polyData->DeepCopy(reader->GetOutput());
+  }
+  else if (extension == ".stl")
+  {
+    vtkNew<vtkSTLReader> reader;
+    reader->SetFileName(path.c_str());
+    reader->Update();
+    polyData->DeepCopy(reader->GetOutput());
+  }
+  else if (extension == ".vtk")
+  {
+    vtkNew<vtkPolyDataReader> reader;
+    reader->SetFileName(path.c_str());
+    reader->Update();
+    polyData->DeepCopy(reader->GetOutput());
+  }
+  else if (extension == ".g")
+  {
+    vtkNew<vtkBYUReader> reader;
+    reader->SetGeometryFileName(path.c_str());
+    reader->Update();
+    polyData->DeepCopy(reader->GetOutput());
+  }
+  else
+  {
+    std::cerr << "Warning: " << path
+              << " unknown extension, using a sphere instead." << std::endl;
+    vtkNew<vtkSphereSource> source;
+    source->SetPhiResolution(50);
+    source->SetThetaResolution(50);
+    source->Update();
+    polyData->DeepCopy(source->GetOutput());
+  }
+  return polyData;
+}
+
+void ViewportBorder(vtkRenderer* renderer, std::array<bool, 4> const& sides,
+                    std::string const& borderColor, double const& borderWidth)
+{
+  vtkNew<vtkNamedColors> colors;
+
+  // Points start at upper right and proceed anti-clockwise.
+  vtkNew<vtkPoints> points;
+  points->SetNumberOfPoints(4);
+  points->InsertPoint(0, 1, 1, 0);
+  points->InsertPoint(1, 0, 1, 0);
+  points->InsertPoint(2, 0, 0, 0);
+  points->InsertPoint(3, 1, 0, 0);
+
+  vtkNew<vtkCellArray> cells;
+  cells->Initialize();
+
+  if (sides[0])
+  {
+    // Top
+    vtkNew<vtkPolyLine> top;
+    top->GetPointIds()->SetNumberOfIds(2);
+    top->GetPointIds()->SetId(0, 0);
+    top->GetPointIds()->SetId(1, 1);
+    cells->InsertNextCell(top);
+  }
+  if (sides[1])
+  {
+    // Left
+    vtkNew<vtkPolyLine> left;
+    left->GetPointIds()->SetNumberOfIds(2);
+    left->GetPointIds()->SetId(0, 1);
+    left->GetPointIds()->SetId(1, 2);
+    cells->InsertNextCell(left);
+  }
+  if (sides[2])
+  {
+    // Bottom
+    vtkNew<vtkPolyLine> bottom;
+    bottom->GetPointIds()->SetNumberOfIds(2);
+    bottom->GetPointIds()->SetId(0, 2);
+    bottom->GetPointIds()->SetId(1, 3);
+    cells->InsertNextCell(bottom);
+  }
+  if (sides[3])
+  {
+    // Right
+    vtkNew<vtkPolyLine> right;
+    right->GetPointIds()->SetNumberOfIds(2);
+    right->GetPointIds()->SetId(0, 3);
+    right->GetPointIds()->SetId(1, 0);
+    cells->InsertNextCell(right);
+  }
+
+  // Now make the polydata and display it.
+  vtkNew<vtkPolyData> poly;
+  poly->Initialize();
+  poly->SetPoints(points);
+  poly->SetLines(cells);
+
+  // Use normalized viewport coordinates since
+  // they are independent of window size.
+  vtkNew<vtkCoordinate> coordinate;
+  coordinate->SetCoordinateSystemToNormalizedViewport();
+
+  vtkNew<vtkPolyDataMapper2D> mapper;
+  mapper->SetInputData(poly);
+  mapper->SetTransformCoordinate(coordinate);
+
+  vtkNew<vtkActor2D> actor;
+  actor->SetMapper(mapper);
+  actor->GetProperty()->SetColor(colors->GetColor3d(borderColor).GetData());
+
+  // Line width should be at least 2 to be visible at extremes.
+  actor->GetProperty()->SetLineWidth(borderWidth);
+  renderer->AddViewProp(actor);
+}
+
+} // namespace
diff --git a/src/Cxx/Rendering/GradientBackground.md b/src/Cxx/Rendering/GradientBackground.md
new file mode 100644
index 0000000000000000000000000000000000000000..d148d224a57f6955d08ee70576012b8c530e9126
--- /dev/null
+++ b/src/Cxx/Rendering/GradientBackground.md
@@ -0,0 +1,22 @@
+### Description
+
+Demonstrates the gradient backgrounds available in VTK.
+
+The gradient background modes are:
+
+- Vertical
+- Horizontal
+- Radial Farthest Side
+- Radial Farthest Corner
+
+The user can also edit the code to change the stop colors marking the beginning and end points in a gradient.
+
+An option is provided for the user to read in a data file so that more interesting objects can be viewed.
+
+The viewport border can also be set and colored.
+
+For more information, see [New in VTK 9.3: Radial Gradient Background](https://www.kitware.com/new-in-vtk-9-3-radial-gradient-background/)
+
+!!! note VTK 9.3 or later is required.
+
+!!! note The C++ version requires C++ 17 or later as std::filesystem is used.
diff --git a/src/Python.md b/src/Python.md
index 6fcae4fa2c3163019b5da604d5ee6ab602a42809..580fcc396bf87b94ec8141d283c97cdf2a425794 100644
--- a/src/Python.md
+++ b/src/Python.md
@@ -449,6 +449,7 @@ This section includes vtkUnstructuredGrid.
 [Cone4](/Python/Rendering/Cone4) | Modifying properties and transformation matrix based on the VTK example Cone4.py.
 [DiffuseSpheres](/Python/Rendering/DiffuseSpheres) | Demonstrates the effect of diffuse lighting on spheres.
 [FlatVersusGouraud](/Python/Rendering/FlatVersusGouraud) | Flat and Gouraud shading. Different shading methods can dramatically improve the look of an object represented with polygons. On the top, flat shading uses a constant surface normal across each polygon. On the bottom, Gouraud shading interpolates normals from polygon vertices to give a smoother look.
+[GradientBackground](/Python/Rendering/GradientBackground) | Demonstrates the background shading options.
 [Mace](/Python/Rendering/Mace) | An example of multiple inputs and outputs.
 [Model](/Python/Rendering/Model) | Illustrative diagram of graphics objects.
 [MotionBlur](/Python/Rendering/MotionBlur) | Example of motion blur.
diff --git a/src/Python/Rendering/GradientBackground.md b/src/Python/Rendering/GradientBackground.md
new file mode 100644
index 0000000000000000000000000000000000000000..d148d224a57f6955d08ee70576012b8c530e9126
--- /dev/null
+++ b/src/Python/Rendering/GradientBackground.md
@@ -0,0 +1,22 @@
+### Description
+
+Demonstrates the gradient backgrounds available in VTK.
+
+The gradient background modes are:
+
+- Vertical
+- Horizontal
+- Radial Farthest Side
+- Radial Farthest Corner
+
+The user can also edit the code to change the stop colors marking the beginning and end points in a gradient.
+
+An option is provided for the user to read in a data file so that more interesting objects can be viewed.
+
+The viewport border can also be set and colored.
+
+For more information, see [New in VTK 9.3: Radial Gradient Background](https://www.kitware.com/new-in-vtk-9-3-radial-gradient-background/)
+
+!!! note VTK 9.3 or later is required.
+
+!!! note The C++ version requires C++ 17 or later as std::filesystem is used.
diff --git a/src/Python/Rendering/GradientBackground.py b/src/Python/Rendering/GradientBackground.py
new file mode 100755
index 0000000000000000000000000000000000000000..3764c94e463c68589d5d8426616e6a7e0d5e3877
--- /dev/null
+++ b/src/Python/Rendering/GradientBackground.py
@@ -0,0 +1,342 @@
+#!/usr/bin/env python
+
+# Based on:
+#  https://gitlab.kitware.com/vtk/vtk/-/blob/master/Rendering/Core/Testing/Cxx/TestGradientBackground.cxx?ref_type=heads
+# See:
+#  [New in VTK 9.3: Radial Gradient Background](https://www.kitware.com/new-in-vtk-9-3-radial-gradient-background/)
+
+from pathlib import Path
+
+# noinspection PyUnresolvedReferences
+import vtkmodules.vtkInteractionStyle
+# noinspection PyUnresolvedReferences
+import vtkmodules.vtkRenderingFreeType
+# noinspection PyUnresolvedReferences
+import vtkmodules.vtkRenderingOpenGL2
+from vtkmodules.vtkCommonColor import vtkNamedColors
+from vtkmodules.vtkCommonCore import vtkPoints
+from vtkmodules.vtkCommonDataModel import (
+    vtkCellArray,
+    vtkPolyData,
+    vtkPolyLine
+)
+from vtkmodules.vtkFiltersSources import (
+    vtkConeSource,
+    vtkSphereSource
+)
+from vtkmodules.vtkIOGeometry import (
+    vtkBYUReader,
+    vtkOBJReader,
+    vtkSTLReader
+)
+from vtkmodules.vtkIOLegacy import vtkPolyDataReader
+from vtkmodules.vtkIOPLY import vtkPLYReader
+from vtkmodules.vtkIOXML import vtkXMLPolyDataReader
+from vtkmodules.vtkInteractionStyle import vtkInteractorStyleTrackballCamera
+from vtkmodules.vtkRenderingCore import (
+    vtkActor,
+    vtkActor2D,
+    vtkCoordinate,
+    vtkPolyDataMapper,
+    vtkPolyDataMapper2D,
+    vtkRenderWindow,
+    vtkRenderWindowInteractor,
+    vtkRenderer,
+    vtkTextMapper,
+    vtkTextProperty,
+    vtkViewport
+)
+
+
+def get_program_parameters(argv):
+    import argparse
+    description = 'Demonstrates the background shading options.'
+    epilogue = '''
+    '''
+    parser = argparse.ArgumentParser(description=description, epilog=epilogue,
+                                     formatter_class=argparse.RawDescriptionHelpFormatter)
+    parser.add_argument('-f', '--file_name', default=None,
+                        help='An optional file name, e.g. star-wars-vader-tie-fighter.obj.')
+    args = parser.parse_args()
+    return args.file_name
+
+
+def main(fn):
+    if fn:
+        fp = Path(fn)
+        if not fp.is_file():
+            print(f'The path: {fp} does not exist.')
+            return
+    else:
+        fp = None
+
+    pd = read_polydata_(fp)
+
+    ren_win = vtkRenderWindow()
+    ren_win.SetWindowName('GradientBackground')
+
+    iren = vtkRenderWindowInteractor()
+    renderers = []
+
+    # For each gradient specify the mode.
+    modes = [
+        vtkViewport.GradientModes.VTK_GRADIENT_VERTICAL,
+        vtkViewport.GradientModes.VTK_GRADIENT_HORIZONTAL,
+        vtkViewport.GradientModes.VTK_GRADIENT_RADIAL_VIEWPORT_FARTHEST_SIDE,
+        vtkViewport.GradientModes.VTK_GRADIENT_RADIAL_VIEWPORT_FARTHEST_CORNER,
+    ]
+
+    colors = vtkNamedColors()
+
+    mapper = vtkPolyDataMapper()
+    mapper.SetInputData(pd)
+
+    actor = vtkActor()
+    actor.SetMapper(mapper)
+    actor.GetProperty().SetColor(colors.GetColor3d('Honeydew'))
+    actor.GetProperty().SetSpecular(0.3)
+    actor.GetProperty().SetSpecularPower(60.0)
+
+    ren_width = 640
+    ren_height = 480
+
+    # The bounds for each view port.
+    xmins = [0.0, 0.5, 0.0, 0.5]
+    ymins = [0.0, 0.0, 0.5, 0.5]
+    xmaxs = [0.5, 1.0, 0.5, 1.0]
+    ymaxs = [0.5, 0.5, 1.0, 1.0]
+
+    # Here we select and name the colors.
+    # Feel free to change colors.
+    bottom_color = colors.GetColor3d('Gold')
+    top_color = colors.GetColor3d('OrangeRed')
+    left_color = colors.GetColor3d('Gold')
+    right_color = colors.GetColor3d('OrangeRed')
+    center_color = colors.GetColor3d('Gold')
+    side_color = colors.GetColor3d('OrangeRed')
+    corner_color = colors.GetColor3d('OrangeRed')
+
+    viewport_title = ["Vertical",
+                      "Horizontal",
+                      "Radial Farthest Side",
+                      "Radial Farthest Corner",
+                      ]
+
+    # Create one text property for all.
+    text_property = vtkTextProperty()
+    text_property.SetJustificationToCentered()
+    text_property.SetFontSize(ren_height // 12)
+    text_property.SetColor(colors.GetColor3d('MidnightBlue'))
+
+    text_mappers = []
+    text_actors = []
+
+    # Define borders for the viewports  = [top, left, bottom, right].
+    lb = [False, True, True, False]
+    lbr = [False, True, True, True]
+    tlb = [True, True, True, False]
+    tlbr = [True, True, True, True]
+    border_color = 'DarkGreen'
+    border_width = 4.0
+
+    for i in range(0, 4):
+        text_mappers.append(vtkTextMapper())
+        text_mappers[i].SetInput(viewport_title[i])
+        text_mappers[i].SetTextProperty(text_property)
+
+        text_actors.append(vtkActor2D())
+        text_actors[i].SetMapper(text_mappers[i])
+        text_actors[i].SetPosition(ren_width / 2, 8)
+
+        renderers.append(vtkRenderer())
+        renderers[i].AddActor(text_actors[i])
+        renderers[i].AddActor(actor)
+        renderers[i].GradientBackgroundOn()
+        renderers[i].SetGradientMode(modes[i])
+
+        renderers[i].SetViewport(xmins[i], ymins[i], xmaxs[i], ymaxs[i])
+
+        if i == 1:
+            # Horizontal
+            renderers[i].SetBackground(left_color)
+            renderers[i].SetBackground2(right_color)
+            viewport_border(renderers[i], lbr, border_color, border_width)
+        elif i == 2:
+            # Radial Farthest Side
+            renderers[i].SetBackground(center_color)
+            renderers[i].SetBackground2(side_color)
+            viewport_border(renderers[i], tlb, border_color, border_width)
+        elif i == 3:
+            # Radial Farthest Corner
+            renderers[i].SetBackground(center_color)
+            renderers[i].SetBackground2(corner_color)
+            viewport_border(renderers[i], tlbr, border_color, border_width)
+        else:
+            # Vertical
+            renderers[i].SetBackground(bottom_color)
+            renderers[i].SetBackground2(top_color)
+            viewport_border(renderers[i], lb, border_color, border_width)
+
+        ren_win.AddRenderer(renderers[i])
+
+    ren_win.SetInteractor(iren)
+    ren_win.Render()
+
+    style = vtkInteractorStyleTrackballCamera()
+    iren.SetInteractorStyle(style)
+
+    iren.Initialize()
+    iren.UpdateSize(ren_width * 2, ren_height * 2)
+
+    iren.Start()
+
+
+def read_polydata_(path):
+    """
+    Read from a file containing vtkPolyData.
+
+    If the path is empty a cone is returned.
+    If the extension is unknown a sphere is returned.
+    
+    :param path: The path to the file.
+    :return: The vtkPolyData.
+    """
+
+    poly_data = vtkPolyData()
+
+    if path is None:
+        # Default to a cone if the path is empty.
+        source = vtkConeSource()
+        source.SetResolution(25)
+        source.SetDirection(0, 1, 0)
+        source.SetHeight(1)
+        source.Update()
+        poly_data.DeepCopy(source.GetOutput())
+        return poly_data
+
+    valid_suffixes = ['.g', '.obj', '.stl', '.ply', '.vtk', '.vtp']
+    ext = path.suffix.lower()
+    if path.suffix not in valid_suffixes:
+        print('Warning:', path, 'unknown extension, using a sphere instead.')
+        source = vtkSphereSource()
+        source.SetPhiResolution(50)
+        source.SetThetaResolution(50)
+        source.Update()
+        poly_data.DeepCopy(source.GetOutput())
+    else:
+        if ext == '.ply':
+            reader = vtkPLYReader()
+            reader.SetFileName(file_name)
+            reader.Update()
+            poly_data.DeepCopy(reader.GetOutput())
+        elif ext == '.vtp':
+            reader = vtkXMLPolyDataReader()
+            reader.SetFileName(file_name)
+            reader.Update()
+            poly_data.DeepCopy(reader.GetOutput())
+        elif ext == '.obj':
+            reader = vtkOBJReader()
+            reader.SetFileName(file_name)
+            reader.Update()
+            poly_data.DeepCopy(reader.GetOutput())
+        elif ext == '.stl':
+            reader = vtkSTLReader()
+            reader.SetFileName(file_name)
+            reader.Update()
+            poly_data.DeepCopy(reader.GetOutput())
+        elif ext == '.vtk':
+            reader = vtkPolyDataReader()
+            reader.SetFileName(file_name)
+            reader.Update()
+            poly_data.DeepCopy(reader.GetOutput())
+        elif ext == '.g':
+            reader = vtkBYUReader()
+            reader.SetGeometryFileName(file_name)
+            reader.Update()
+            poly_data.DeepCopy(reader.GetOutput())
+
+    return poly_data
+
+
+def viewport_border(renderer, sides, border_color, border_width):
+    """
+    Set a border around a viewport.
+
+    :param renderer: The renderer corresponding to the viewport.
+    :param sides: An array of boolean corresponding to [top, left, bottom, right]
+    :param border_color: The color of the border.
+    :param border_width: The width of the border.
+    :return:
+    """
+    colors = vtkNamedColors()
+
+    # Points start at upper right and proceed anti-clockwise.
+    points = vtkPoints()
+    points.SetNumberOfPoints(4)
+    points.InsertPoint(0, 1, 1, 0)
+    points.InsertPoint(1, 0, 1, 0)
+    points.InsertPoint(2, 0, 0, 0)
+    points.InsertPoint(3, 1, 0, 0)
+
+    cells = vtkCellArray()
+    cells.Initialize()
+
+    if sides[0]:
+        # Top
+        top = vtkPolyLine()
+        top.GetPointIds().SetNumberOfIds(2)
+        top.GetPointIds().SetId(0, 0)
+        top.GetPointIds().SetId(1, 1)
+        cells.InsertNextCell(top)
+    if sides[1]:
+        # Left
+        left = vtkPolyLine()
+        left.GetPointIds().SetNumberOfIds(2)
+        left.GetPointIds().SetId(0, 1)
+        left.GetPointIds().SetId(1, 2)
+        cells.InsertNextCell(left)
+    if sides[2]:
+        # Bottom
+        bottom = vtkPolyLine()
+        bottom.GetPointIds().SetNumberOfIds(2)
+        bottom.GetPointIds().SetId(0, 2)
+        bottom.GetPointIds().SetId(1, 3)
+        cells.InsertNextCell(bottom)
+    if sides[3]:
+        # Right
+        right = vtkPolyLine()
+        right.GetPointIds().SetNumberOfIds(2)
+        right.GetPointIds().SetId(0, 3)
+        right.GetPointIds().SetId(1, 0)
+        cells.InsertNextCell(right)
+
+    # Now make the polydata and display it.
+    poly = vtkPolyData()
+    poly.Initialize()
+    poly.SetPoints(points)
+    poly.SetLines(cells)
+
+    # Use normalized viewport coordinates since
+    # they are independent of window size.
+    coordinate = vtkCoordinate()
+    coordinate.SetCoordinateSystemToNormalizedViewport()
+
+    mapper = vtkPolyDataMapper2D()
+    mapper.SetInputData(poly)
+    mapper.SetTransformCoordinate(coordinate)
+
+    actor = vtkActor2D()
+    actor.SetMapper(mapper)
+    actor.GetProperty().SetColor(colors.GetColor3d(border_color))
+
+    # Line width should be at least 2 to be visible at extremes.
+    actor.GetProperty().SetLineWidth(border_width)
+
+    renderer.AddViewProp(actor)
+
+
+if __name__ == '__main__':
+    import sys
+
+    file_name = get_program_parameters(sys.argv)
+    main(file_name)
diff --git a/src/Testing/Baseline/Cxx/Rendering/TestGradientBackground.png b/src/Testing/Baseline/Cxx/Rendering/TestGradientBackground.png
new file mode 100644
index 0000000000000000000000000000000000000000..6ea9aca48256bd4f4e7b7a98eb95c8ecf72fdfdd
--- /dev/null
+++ b/src/Testing/Baseline/Cxx/Rendering/TestGradientBackground.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:f98922c4356d7a3f80f5406ea4b047604c1c0c64c5ef0a693869802331358985
+size 292408
diff --git a/src/Testing/Baseline/Python/Rendering/TestGradientBackground.png b/src/Testing/Baseline/Python/Rendering/TestGradientBackground.png
new file mode 100644
index 0000000000000000000000000000000000000000..6ea9aca48256bd4f4e7b7a98eb95c8ecf72fdfdd
--- /dev/null
+++ b/src/Testing/Baseline/Python/Rendering/TestGradientBackground.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:f98922c4356d7a3f80f5406ea4b047604c1c0c64c5ef0a693869802331358985
+size 292408
diff --git a/src/Testing/Data/star-wars-vader-tie-fighter.obj b/src/Testing/Data/star-wars-vader-tie-fighter.obj
new file mode 100644
index 0000000000000000000000000000000000000000..2eb7df21a4445ee6337774dffe5f6e2732f14b73
--- /dev/null
+++ b/src/Testing/Data/star-wars-vader-tie-fighter.obj
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:595637d02489497885078e60990ee311e70e699882fac1ab7bf3ac2d2f729947
+size 11433883