diff --git a/CHANGES.md b/CHANGES.md
index 531ba213aa00..a2b581960523 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -8,6 +8,7 @@
 
 ##### Additions :tada:
 
+- Added `backFaceCulling` property to `Cesium3DTileset` and `Model` to support viewing the underside or interior of a tileset or model. [#8981](https://github.com/CesiumGS/cesium/pull/8981)
 - Added `Ellipsoid.surfaceArea` for computing the approximate surface area of a rectangle on the surface of an ellipsoid. [#8986](https://github.com/CesiumGS/cesium/pull/8986)
 - Added support for PolylineVolume in CZML. [#8841](https://github.com/CesiumGS/cesium/pull/8841)
 - Added `Color.toCssHexString` for getting the CSS hex string equivalent for a color. [#8987](https://github.com/CesiumGS/cesium/pull/8987)
diff --git a/Source/Scene/Batched3DModel3DTileContent.js b/Source/Scene/Batched3DModel3DTileContent.js
index 2a9860c27e1a..5e38ecf48cce 100644
--- a/Source/Scene/Batched3DModel3DTileContent.js
+++ b/Source/Scene/Batched3DModel3DTileContent.js
@@ -432,6 +432,7 @@ function initialize(content, arrayBuffer, byteOffset) {
       luminanceAtZenith: tileset.luminanceAtZenith,
       sphericalHarmonicCoefficients: tileset.sphericalHarmonicCoefficients,
       specularEnvironmentMaps: tileset.specularEnvironmentMaps,
+      backFaceCulling: tileset.backFaceCulling,
     });
     content._model.readyPromise.then(function (model) {
       model.activeAnimations.addAll({
@@ -539,6 +540,7 @@ Batched3DModel3DTileContent.prototype.update = function (tileset, frameState) {
   this._model.luminanceAtZenith = this._tileset.luminanceAtZenith;
   this._model.sphericalHarmonicCoefficients = this._tileset.sphericalHarmonicCoefficients;
   this._model.specularEnvironmentMaps = this._tileset.specularEnvironmentMaps;
+  this._model.backFaceCulling = this._tileset.backFaceCulling;
   this._model.debugWireframe = this._tileset.debugWireframe;
 
   // Update clipping planes
diff --git a/Source/Scene/Cesium3DTileset.js b/Source/Scene/Cesium3DTileset.js
index 163790562211..b03ca969c1fd 100644
--- a/Source/Scene/Cesium3DTileset.js
+++ b/Source/Scene/Cesium3DTileset.js
@@ -89,6 +89,7 @@ import TileOrientedBoundingBox from "./TileOrientedBoundingBox.js";
  * @param {Number} [options.luminanceAtZenith=0.2] The sun's luminance at the zenith in kilo candela per meter squared to use for this model's procedural environment map.
  * @param {Cartesian3[]} [options.sphericalHarmonicCoefficients] The third order spherical harmonic coefficients used for the diffuse color of image-based lighting.
  * @param {String} [options.specularEnvironmentMaps] A URL to a KTX file that contains a cube map of the specular lighting and the convoluted specular mipmaps.
+ * @param {Boolean} [options.backFaceCulling=true] Whether to cull back-facing geometry. When true, back face culling is determined by the glTF material's doubleSided property; when false, back face culling is disabled.
  * @param {String} [options.debugHeatmapTilePropertyName] The tile variable to colorize as a heatmap. All rendered tiles will be colorized relative to each other's specified variable value.
  * @param {Boolean} [options.debugFreezeFrame=false] For debugging only. Determines if only the tiles from last frame should be used for rendering.
  * @param {Boolean} [options.debugColorizeTiles=false] For debugging only. When true, assigns a random color to each tile.
@@ -750,6 +751,15 @@ function Cesium3DTileset(options) {
    */
   this.specularEnvironmentMaps = options.specularEnvironmentMaps;
 
+  /**
+   * Whether to cull back-facing geometry. When true, back face culling is determined
+   * by the glTF material's doubleSided property; when false, back face culling is disabled.
+   *
+   * @type {Boolean}
+   * @default true
+   */
+  this.backFaceCulling = defaultValue(options.backFaceCulling, true);
+
   /**
    * This property is for debugging only; it is not optimized for production use.
    * <p>
diff --git a/Source/Scene/Instanced3DModel3DTileContent.js b/Source/Scene/Instanced3DModel3DTileContent.js
index 2031bca87669..bc4cf26acdd5 100644
--- a/Source/Scene/Instanced3DModel3DTileContent.js
+++ b/Source/Scene/Instanced3DModel3DTileContent.js
@@ -304,6 +304,7 @@ function initialize(content, arrayBuffer, byteOffset) {
     luminanceAtZenith: tileset.luminanceAtZenith,
     sphericalHarmonicCoefficients: tileset.sphericalHarmonicCoefficients,
     specularEnvironmentMaps: tileset.specularEnvironmentMaps,
+    backFaceCulling: tileset.backFaceCulling,
   };
 
   if (gltfFormat === 0) {
@@ -615,6 +616,7 @@ Instanced3DModel3DTileContent.prototype.update = function (
   this._modelInstanceCollection.luminanceAtZenith = this._tileset.luminanceAtZenith;
   this._modelInstanceCollection.sphericalHarmonicCoefficients = this._tileset.sphericalHarmonicCoefficients;
   this._modelInstanceCollection.specularEnvironmentMaps = this._tileset.specularEnvironmentMaps;
+  this._modelInstanceCollection.backFaceCulling = this._tileset.backFaceCulling;
   this._modelInstanceCollection.debugWireframe = this._tileset.debugWireframe;
 
   var model = this._modelInstanceCollection._model;
diff --git a/Source/Scene/Model.js b/Source/Scene/Model.js
index b3a2f3772ff5..b89fd91a944a 100644
--- a/Source/Scene/Model.js
+++ b/Source/Scene/Model.js
@@ -217,6 +217,7 @@ var uriToGuid = {};
  * @param {Cartesian3[]} [options.sphericalHarmonicCoefficients] The third order spherical harmonic coefficients used for the diffuse color of image-based lighting.
  * @param {String} [options.specularEnvironmentMaps] A URL to a KTX file that contains a cube map of the specular lighting and the convoluted specular mipmaps.
  * @param {Credit|String} [options.credit] A credit for the data source, which is displayed on the canvas.
+ * @param {Boolean} [options.backFaceCulling=true] Whether to cull back-facing geometry. When true, back face culling is determined by the material's doubleSided property; when false, back face culling is disabled. Back faces are not culled if {@link Model#color} is translucent or {@link Model#silhouetteSize} is greater than 0.0.
  *
  * @see Model.fromGltf
  *
@@ -493,6 +494,18 @@ function Model(options) {
   // to the root tile.
   this.clippingPlanesOriginMatrix = undefined;
 
+  /**
+   * Whether to cull back-facing geometry. When true, back face culling is
+   * determined by the material's doubleSided property; when false, back face
+   * culling is disabled. Back faces are not culled if {@link Model#color} is
+   * translucent or {@link Model#silhouetteSize} is greater than 0.0.
+   *
+   * @type {Boolean}
+   *
+   * @default true
+   */
+  this.backFaceCulling = defaultValue(options.backFaceCulling, true);
+
   /**
    * This property is for debugging only; it is not for production use nor is it optimized.
    * <p>
@@ -1371,6 +1384,7 @@ function containsGltfMagic(uint8Array) {
  * @param {ClippingPlaneCollection} [options.clippingPlanes] The {@link ClippingPlaneCollection} used to selectively disable rendering the model.
  * @param {Boolean} [options.dequantizeInShader=true] Determines if a {@link https://github.com/google/draco|Draco} encoded model is dequantized on the GPU. This decreases total memory usage for encoded models.
  * @param {Credit|String} [options.credit] A credit for the model, which is displayed on the canvas.
+ * @param {Boolean} [options.backFaceCulling=true] Whether to cull back-facing geometry. When true, back face culling is determined by the material's doubleSided property; when false, back face culling is disabled. Back faces are not culled if {@link Model#color} is translucent or {@link Model#silhouetteSize} is greater than 0.0.
  *
  * @returns {Model} The newly created model.
  *
@@ -3947,6 +3961,9 @@ function createCommand(model, gltfNode, runtimeNode, context, scene3DOnly) {
       // Generated on demand when color alpha is less than 1.0
       translucentCommand: undefined,
       translucentCommand2D: undefined,
+      // Generated on demand when back face culling is false
+      disableCullingCommand: undefined,
+      disableCullingCommand2D: undefined,
       // For updating node commands on shader reconstruction
       programId: programId,
     };
@@ -4516,6 +4533,44 @@ function updateColor(model, frameState, forceDerive) {
   }
 }
 
+function getDisableCullingRenderState(renderState) {
+  var rs = clone(renderState, true);
+  rs.cull.enabled = false;
+  return RenderState.fromCache(rs);
+}
+
+function deriveDisableCullingCommand(command) {
+  var disableCullingCommand = DrawCommand.shallowClone(command);
+  disableCullingCommand.renderState = getDisableCullingRenderState(
+    command.renderState
+  );
+  return disableCullingCommand;
+}
+
+function updateBackFaceCulling(model, frameState, forceDerive) {
+  var scene3DOnly = frameState.scene3DOnly;
+  var backFaceCulling = model.backFaceCulling;
+  if (!backFaceCulling) {
+    var nodeCommands = model._nodeCommands;
+    var length = nodeCommands.length;
+    if (!defined(nodeCommands[0].disableCullingCommand) || forceDerive) {
+      for (var i = 0; i < length; ++i) {
+        var nodeCommand = nodeCommands[i];
+        var command = nodeCommand.command;
+        nodeCommand.disableCullingCommand = deriveDisableCullingCommand(
+          command
+        );
+        if (!scene3DOnly) {
+          var command2D = nodeCommand.command2D;
+          nodeCommand.disableCullingCommand2D = deriveDisableCullingCommand(
+            command2D
+          );
+        }
+      }
+    }
+  }
+}
+
 function getProgramId(model, program) {
   var programs = model._rendererResources.programs;
   for (var id in programs) {
@@ -5347,6 +5402,7 @@ Model.prototype.update = function (frameState) {
   var silhouette = hasSilhouette(this, frameState);
   var translucent = isTranslucent(this);
   var invisible = isInvisible(this);
+  var backFaceCulling = this.backFaceCulling;
   var displayConditionPassed = defined(this.distanceDisplayCondition)
     ? distanceDisplayConditionVisible(this, frameState)
     : true;
@@ -5491,6 +5547,7 @@ Model.prototype.update = function (frameState) {
       regenerateShaders(this, frameState);
     } else {
       updateColor(this, frameState, false);
+      updateBackFaceCulling(this, frameState, false);
       updateSilhouette(this, frameState, false);
     }
   }
@@ -5525,8 +5582,14 @@ Model.prototype.update = function (frameState) {
       for (i = 0; i < length; ++i) {
         nc = nodeCommands[i];
         if (nc.show) {
-          var command = translucent ? nc.translucentCommand : nc.command;
-          command = silhouette ? nc.silhouetteModelCommand : command;
+          var command = nc.command;
+          if (silhouette) {
+            command = nc.silhouetteModelCommand;
+          } else if (translucent) {
+            command = nc.translucentCommand;
+          } else if (!backFaceCulling) {
+            command = nc.disableCullingCommand;
+          }
           commandList.push(command);
           boundingVolume = nc.command.boundingVolume;
           if (
@@ -5534,10 +5597,14 @@ Model.prototype.update = function (frameState) {
             (boundingVolume.center.y + boundingVolume.radius > idl2D ||
               boundingVolume.center.y - boundingVolume.radius < idl2D)
           ) {
-            var command2D = translucent
-              ? nc.translucentCommand2D
-              : nc.command2D;
-            command2D = silhouette ? nc.silhouetteModelCommand2D : command2D;
+            var command2D = nc.command2D;
+            if (silhouette) {
+              command2D = nc.silhouetteModelCommand2D;
+            } else if (translucent) {
+              command2D = nc.translucentCommand2D;
+            } else if (!backFaceCulling) {
+              command2D = nc.disableCullingCommand2D;
+            }
             commandList.push(command2D);
           }
         }
@@ -5664,6 +5731,7 @@ function regenerateShaders(model, frameState) {
 
   // Force update silhouette commands/shaders
   updateColor(model, frameState, true);
+  updateBackFaceCulling(model, frameState, true);
   updateSilhouette(model, frameState, true);
 }
 
diff --git a/Source/Scene/ModelInstanceCollection.js b/Source/Scene/ModelInstanceCollection.js
index 120f77cb4fed..a94956523945 100644
--- a/Source/Scene/ModelInstanceCollection.js
+++ b/Source/Scene/ModelInstanceCollection.js
@@ -18,6 +18,7 @@ import Buffer from "../Renderer/Buffer.js";
 import BufferUsage from "../Renderer/BufferUsage.js";
 import DrawCommand from "../Renderer/DrawCommand.js";
 import Pass from "../Renderer/Pass.js";
+import RenderState from "../Renderer/RenderState.js";
 import ShaderSource from "../Renderer/ShaderSource.js";
 import ForEach from "../ThirdParty/GltfPipeline/ForEach.js";
 import when from "../ThirdParty/when.js";
@@ -62,6 +63,7 @@ var LoadState = {
  * @param {Number} [options.luminanceAtZenith=0.2] The sun's luminance at the zenith in kilo candela per meter squared to use for this model's procedural environment map.
  * @param {Cartesian3[]} [options.sphericalHarmonicCoefficients] The third order spherical harmonic coefficients used for the diffuse color of image-based lighting.
  * @param {String} [options.specularEnvironmentMaps] A URL to a KTX file that contains a cube map of the specular lighting and the convoluted specular mipmaps.
+ * @param {Boolean} [options.backFaceCulling=true] Whether to cull back-facing geometry. When true, back face culling is determined by the glTF material's doubleSided property; when false, back face culling is disabled.
  * @param {Boolean} [options.debugShowBoundingVolume=false] For debugging only. Draws the bounding sphere for the collection.
  * @param {Boolean} [options.debugWireframe=false] For debugging only. Draws the instances in wireframe.
  *
@@ -114,6 +116,9 @@ function ModelInstanceCollection(options) {
   this._drawCommands = [];
   this._modelCommands = undefined;
 
+  this._renderStates = undefined;
+  this._disableCullingRenderStates = undefined;
+
   this._boundingSphere = createBoundingSphere(this);
   this._center = Cartesian3.clone(this._boundingSphere.center);
   this._rtcTransform = new Matrix4();
@@ -157,6 +162,8 @@ function ModelInstanceCollection(options) {
   this.luminanceAtZenith = options.luminanceAtZenith;
   this.sphericalHarmonicCoefficients = options.sphericalHarmonicCoefficients;
   this.specularEnvironmentMaps = options.specularEnvironmentMaps;
+  this.backFaceCulling = defaultValue(options.backFaceCulling, true);
+  this._backFaceCulling = this.backFaceCulling;
 }
 
 Object.defineProperties(ModelInstanceCollection.prototype, {
@@ -787,8 +794,8 @@ function createModel(collection, context) {
   }
 }
 
-function updateWireframe(collection) {
-  if (collection._debugWireframe !== collection.debugWireframe) {
+function updateWireframe(collection, force) {
+  if (collection._debugWireframe !== collection.debugWireframe || force) {
     collection._debugWireframe = collection.debugWireframe;
 
     // This assumes the original primitive was TRIANGLES and that the triangles
@@ -803,9 +810,45 @@ function updateWireframe(collection) {
     }
   }
 }
-function updateShowBoundingVolume(collection) {
+
+function getDisableCullingRenderState(renderState) {
+  var rs = clone(renderState, true);
+  rs.cull.enabled = false;
+  return RenderState.fromCache(rs);
+}
+
+function updateBackFaceCulling(collection, force) {
+  if (collection._backFaceCulling !== collection.backFaceCulling || force) {
+    collection._backFaceCulling = collection.backFaceCulling;
+
+    var commands = collection._drawCommands;
+    var length = commands.length;
+    var i;
+
+    if (!defined(collection._disableCullingRenderStates)) {
+      collection._disableCullingRenderStates = new Array(length);
+      collection._renderStates = new Array(length);
+      for (i = 0; i < length; ++i) {
+        var renderState = commands[i].renderState;
+        var derivedRenderState = getDisableCullingRenderState(renderState);
+        collection._disableCullingRenderStates[i] = derivedRenderState;
+        collection._renderStates[i] = renderState;
+      }
+    }
+
+    for (i = 0; i < length; ++i) {
+      commands[i].renderState = collection._backFaceCulling
+        ? collection._renderStates[i]
+        : collection._disableCullingRenderStates[i];
+    }
+  }
+}
+
+function updateShowBoundingVolume(collection, force) {
   if (
-    collection.debugShowBoundingVolume !== collection._debugShowBoundingVolume
+    collection.debugShowBoundingVolume !==
+      collection._debugShowBoundingVolume ||
+    force
   ) {
     collection._debugShowBoundingVolume = collection.debugShowBoundingVolume;
 
@@ -939,13 +982,16 @@ function commandsDirty(model) {
   var nodeCommands = model._nodeCommands;
   var length = nodeCommands.length;
 
+  var commandsDirty = false;
+
   for (var i = 0; i < length; i++) {
     var nc = nodeCommands[i];
     if (nc.command.dirty) {
-      return true;
+      nc.command.dirty = false;
+      commandsDirty = true;
     }
   }
-  return false;
+  return commandsDirty;
 }
 
 function generateModelCommands(modelInstanceCollection, instancingSupported) {
@@ -960,8 +1006,8 @@ function generateModelCommands(modelInstanceCollection, instancingSupported) {
   }
 }
 
-function updateShadows(collection) {
-  if (collection.shadows !== collection._shadows) {
+function updateShadows(collection, force) {
+  if (collection.shadows !== collection._shadows || force) {
     collection._shadows = collection.shadows;
 
     var castShadows = ShadowMode.castShadows(collection.shadows);
@@ -1067,7 +1113,8 @@ ModelInstanceCollection.prototype.update = function (frameState) {
   }
 
   // If the model was set to rebuild shaders during update, rebuild instanced commands.
-  if (commandsDirty(model)) {
+  var modelCommandsDirty = commandsDirty(model);
+  if (modelCommandsDirty) {
     generateModelCommands(this, instancingSupported);
   }
 
@@ -1081,9 +1128,10 @@ ModelInstanceCollection.prototype.update = function (frameState) {
     updateCommandsNonInstanced(this);
   }
 
-  updateShadows(this);
-  updateWireframe(this);
-  updateShowBoundingVolume(this);
+  updateShadows(this, modelCommandsDirty);
+  updateWireframe(this, modelCommandsDirty);
+  updateBackFaceCulling(this, modelCommandsDirty);
+  updateShowBoundingVolume(this, modelCommandsDirty);
 
   var passes = frameState.passes;
   if (!passes.render && !passes.pick) {
diff --git a/Specs/Data/Models/Box-Back-Face-Culling/Box-Back-Face-Culling.gltf b/Specs/Data/Models/Box-Back-Face-Culling/Box-Back-Face-Culling.gltf
new file mode 100644
index 000000000000..5c278ddb2141
--- /dev/null
+++ b/Specs/Data/Models/Box-Back-Face-Culling/Box-Back-Face-Culling.gltf
@@ -0,0 +1,100 @@
+{
+    "asset" : {
+        "generator" : "Khronos glTF Blender I/O v1.1.46",
+        "version" : "2.0"
+    },
+    "scene" : 0,
+    "scenes" : [
+        {
+            "name" : "Scene",
+            "nodes" : [
+                0
+            ]
+        }
+    ],
+    "nodes" : [
+        {
+            "mesh" : 0,
+            "name" : "Cube"
+        }
+    ],
+    "meshes" : [
+        {
+            "name" : "Cube.001",
+            "primitives" : [
+                {
+                    "attributes" : {
+                        "POSITION" : 0,
+                        "NORMAL" : 1,
+                        "TEXCOORD_0" : 2
+                    },
+                    "indices" : 3
+                }
+            ]
+        }
+    ],
+    "accessors" : [
+        {
+            "bufferView" : 0,
+            "componentType" : 5126,
+            "count" : 20,
+            "max" : [
+                1,
+                0.9999998807907104,
+                1
+            ],
+            "min" : [
+                -1,
+                -0.9999998807907104,
+                -1
+            ],
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 1,
+            "componentType" : 5126,
+            "count" : 20,
+            "type" : "VEC3"
+        },
+        {
+            "bufferView" : 2,
+            "componentType" : 5126,
+            "count" : 20,
+            "type" : "VEC2"
+        },
+        {
+            "bufferView" : 3,
+            "componentType" : 5123,
+            "count" : 30,
+            "type" : "SCALAR"
+        }
+    ],
+    "bufferViews" : [
+        {
+            "buffer" : 0,
+            "byteLength" : 240,
+            "byteOffset" : 0
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 240,
+            "byteOffset" : 240
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 160,
+            "byteOffset" : 480
+        },
+        {
+            "buffer" : 0,
+            "byteLength" : 60,
+            "byteOffset" : 640
+        }
+    ],
+    "buffers" : [
+        {
+            "byteLength" : 700,
+            "uri" : "data:application/octet-stream;base64,/v9/P/7/fz8AAIA//v9/P/7/f78AAIA/AACAP/7/f7/+/3+/AACAP/7/fz/+/3+/AACAv/7/fz/+/38/AACAv/7/f7/+/38//v9/P/7/f78AAIA//v9/P/7/fz8AAIA/AACAP/7/fz/+/3+/AACAP/7/f7/+/3+//v9/v/7/f78AAIC//v9/v/7/fz8AAIC/AACAv/7/f7/+/38//v9/v/7/f78AAIC/AACAP/7/f7/+/3+//v9/P/7/f78AAIA/AACAP/7/fz/+/3+//v9/v/7/fz8AAIC/AACAv/7/fz/+/38//v9/P/7/fz8AAIA/AACAPwAAAAABAIAzAACAPwAAAAABAIAzAACAPwAAAAABAIAzAACAPwAAAAABAIAzAQCAswAAAAAAAIA/AQCAswAAAAAAAIA/AQCAswAAAAAAAIA/AQCAswAAAAAAAIA/AQCAMwAAAAAAAIC/AQCAMwAAAAAAAIC/AQCAMwAAAAAAAIC/AQCAMwAAAAAAAIC/AAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgD8AAACAAAAAAAAAgD8AAACAAAAAAAAAgD8AAACAAAAAAAAAgD8AAACAAAAgPwAAQD8AAMA+AABAPwAAwD4AAIA/AAAgPwAAgD8AACA/AAAAPwAAwD4AAAA/AADAPgAAQD8AACA/AABAPwAAID8AAAAAAADAPgAAAAAAAMA+AACAPgAAID8AAIA+AADAPgAAAD8AAMA+AACAPgAAAD4AAIA+AAAAPgAAAD8AAGA/AACAPgAAID8AAIA+AAAgPwAAAD8AAGA/AAAAPwAAAQACAAAAAgADAAQABQAGAAQABgAHAAgACQAKAAgACgALAAwADQAOAAwADgAPABAAEQASABMAEAASAA=="
+        }
+    ]
+}
diff --git a/Specs/Scene/Cesium3DTilesetSpec.js b/Specs/Scene/Cesium3DTilesetSpec.js
index cb1ac36aade8..19af1f790c85 100644
--- a/Specs/Scene/Cesium3DTilesetSpec.js
+++ b/Specs/Scene/Cesium3DTilesetSpec.js
@@ -7,6 +7,7 @@ import { defined } from "../../Source/Cesium.js";
 import { getAbsoluteUri } from "../../Source/Cesium.js";
 import { getStringFromTypedArray } from "../../Source/Cesium.js";
 import { HeadingPitchRange } from "../../Source/Cesium.js";
+import { HeadingPitchRoll } from "../../Source/Cesium.js";
 import { Intersect } from "../../Source/Cesium.js";
 import { JulianDate } from "../../Source/Cesium.js";
 import { Math as CesiumMath } from "../../Source/Cesium.js";
@@ -2467,6 +2468,61 @@ describe(
       );
     });
 
+    function testBackFaceCulling(url, setViewOptions) {
+      var renderOptions = {
+        scene: scene,
+        time: new JulianDate(2457522.154792),
+      };
+      return Cesium3DTilesTester.loadTileset(scene, url).then(function (
+        tileset
+      ) {
+        scene.camera.setView(setViewOptions);
+        expect(renderOptions).toRenderAndCall(function (rgba) {
+          expect(rgba).toEqual([0, 0, 0, 255]);
+          tileset.backFaceCulling = false;
+          expect(renderOptions).toRenderAndCall(function (rgba2) {
+            expect(rgba2).not.toEqual(rgba);
+          });
+        });
+      });
+    }
+
+    it("renders b3dm tileset when back face culling is disabled", function () {
+      var setViewOptions = {
+        destination: new Cartesian3(
+          1215012.6853779217,
+          -4736313.101374343,
+          4081603.4657718465
+        ),
+        orientation: new HeadingPitchRoll(
+          6.283185307179584,
+          -0.49999825387267993,
+          6.283185307179586
+        ),
+        endTransform: Matrix4.IDENTITY,
+      };
+
+      return testBackFaceCulling(withoutBatchTableUrl, setViewOptions);
+    });
+
+    it("renders i3dm tileset when back face culling is disabled", function () {
+      var setViewOptions = {
+        destination: new Cartesian3(
+          1215015.8599828142,
+          -4736324.65638894,
+          4081609.967056947
+        ),
+        orientation: new HeadingPitchRoll(
+          6.283185307179585,
+          -0.5000006393986758,
+          6.283185307179586
+        ),
+        endTransform: Matrix4.IDENTITY,
+      };
+
+      return testBackFaceCulling(instancedUrl, setViewOptions);
+    });
+
     ///////////////////////////////////////////////////////////////////////////
     // Styling tests
 
diff --git a/Specs/Scene/ModelSpec.js b/Specs/Scene/ModelSpec.js
index b2db67d54604..01b20f31acf6 100644
--- a/Specs/Scene/ModelSpec.js
+++ b/Specs/Scene/ModelSpec.js
@@ -148,6 +148,9 @@ describe(
     var boxGltf2WithTechniquesUrl =
       "./Data/Models/Box-Gltf-2-Techniques/Box.gltf";
 
+    var boxBackFaceCullingUrl =
+      "./Data/Models/Box-Back-Face-Culling/Box-Back-Face-Culling.gltf";
+
     var texturedBoxModel;
     var cesiumAirModel;
     var animBoxesModel;
@@ -3857,6 +3860,34 @@ describe(
       });
     });
 
+    it("renders box when back face culling is disabled", function () {
+      return loadModel(boxBackFaceCullingUrl).then(function (model) {
+        expect(model.ready).toBe(true);
+        model.show = true;
+
+        // Look at the model
+        model.zoomTo();
+
+        expect({
+          scene: scene,
+          time: JulianDate.fromDate(new Date("January 1, 2014 12:00:00 UTC")),
+        }).toRenderAndCall(function (rgba) {
+          expect(rgba).toEqual([0, 0, 0, 255]);
+        });
+
+        model.backFaceCulling = false;
+
+        expect({
+          scene: scene,
+          time: JulianDate.fromDate(new Date("January 1, 2014 12:00:00 UTC")),
+        }).toRenderAndCall(function (rgba) {
+          expect(rgba).not.toEqual([0, 0, 0, 255]);
+        });
+
+        primitives.remove(model);
+      });
+    });
+
     describe("height referenced model", function () {
       function createMockGlobe() {
         var globe = {