Toggle menu
Toggle preferences menu
Toggle personal menu
Not logged in
Your IP address will be publicly visible if you make any edits.

Back-face culling is a rendering optimization in which polygons that face away from the viewer are discarded before they are drawn. For a scene made only of opaque, closed surfaces, the back-facing polygons can never be seen, so removing them saves work without changing the image.[1] The test is cheap: a polygon is classified as front-facing or back-facing from the sign of its projected area on screen, or from the angle between its surface normal and the direction to the viewer.[2][3]

The technique dates from the hidden-surface research of the 1960s and is a standard rasterizer setting in graphics APIs such as OpenGL, Vulkan, Direct3D and Metal. In virtual reality (VR) and augmented reality (AR), where a stereoscopic display needs a separate image for each eye, XR toolkits such as RealityKit, the Mixed Reality Toolkit and StereoKit enable it by default and warn developers that turning it off costs performance.[4][5][6]

Reviewed 13 October 2026. Checked every claim against the cited Khronos OpenGL 4 and OpenGL 1.0 texts, the Vulkan rasterization chapter, Microsoft Direct3D 11 and MRTK2 pages, Apple Metal and RealityKit documentation, Unity, StereoKit, A-Frame, NVIDIA and meshoptimizer pages, and the full texts or abstracts of the Sutherland-Sproull-Schumacker, Adelson et al., Zhang-Hoff, Kumar et al. and Shirman-Abi-Ezzi papers with Crossref metadata. About review dates.

How it works

A polygon has two sides. Which side counts as the front is set by convention, usually by the order in which its vertices are listed. When the polygon is projected to the screen, its vertices run either clockwise or counterclockwise around its interior. The OpenGL reference describes this as the path that "an imaginary object" takes when it moves from the first vertex to the second and on to the last, then back to the first.[1] The application tells the API which winding means "front"; every other polygon is back-facing. The Vulkan specification makes the rule precise: the decision is based on the sign of the polygon's area computed in framebuffer coordinates, and any triangle that is not front-facing, including a triangle with zero area, is back-facing.[2]

The same decision can be made in object space with the polygon's normal vector. Zhang and Hoff describe the typical test as a dot product between the normal and the vector from the viewpoint to any point on the polygon: a negative result means the polygon faces the viewer, a positive one means it faces away.[3] Adelson and colleagues give the equivalent plane-equation form: for a plane Ax + By + Cz + D = 0 whose normal points out of the front face, substituting the viewing position into the equation gives a negative value for a back face.[7] Because the test depends on where the eye is, a polygon's status changes as the viewer moves.

The method only works if a mesh's polygons are ordered consistently. Apple's Metal documentation says a model such as a sphere made of filled triangles can be culled correctly if it uses an orientable surface, meaning its primitives "consistently use the same ordering for its vertices".[8] A mesh with inconsistent winding loses visible faces when culling is on.

In graphics APIs

Graphics APIs expose back-face culling as part of the rasterizer state. All four below can also cull front faces instead, which is useful for geometry that is meant to be seen from the inside.

API Controls Culling options Default
OpenGL glEnable(GL_CULL_FACE), glCullFace, glFrontFace GL_FRONT, GL_BACK, GL_FRONT_AND_BACK Culling disabled; mode GL_BACK; counterclockwise polygons are front-facing[9][1]
Vulkan cullMode and frontFace in VkPipelineRasterizationStateCreateInfo; dynamic vkCmdSetCullMode and vkCmdSetFrontFace (Vulkan 1.3 or VK_EXT_extended_dynamic_state) VK_CULL_MODE_NONE, FRONT_BIT, BACK_BIT, FRONT_AND_BACK Set by the application in each pipeline[2]
Direct3D 11 CullMode and FrontCounterClockwise in D3D11_RASTERIZER_DESC D3D11_CULL_NONE, D3D11_CULL_FRONT, D3D11_CULL_BACK Back faces culled; FrontCounterClockwise is FALSE, so clockwise triangles are front-facing[10][11]
Metal setCullMode and setFrontFacing on the render command encoder MTLCullMode none, front, back No culling[8][12]

In OpenGL, setting the mode to GL_FRONT_AND_BACK stops all polygons from being drawn, but points and lines are still drawn.[9] The defaults differ between APIs: OpenGL and Metal start with culling off, while Direct3D 11 culls back faces unless told otherwise, and Direct3D 11 treats clockwise triangles as front-facing where OpenGL treats counterclockwise ones that way.[9][8][10]

Game engines wrap the same setting. In Unity's ShaderLab language, the Cull command takes Back (the default), Front or Off. Unity's manual suggests front-face culling for "turning geometry inside-out" and turning culling off for transparent objects or double-sided walls.[13]

History

Back-face removal is one of the oldest steps in hidden-surface computation. In their 1974 survey of hidden-surface algorithms in Computing Surveys, Ivan Sutherland, Bob Sproull and Robert Schumacker defined a back face as a face that "cannot appear in the picture by virtue of being on the side of an object away from the observer", identified by a face normal that points away from the observer. They noted that most of the algorithms they compared began by culling back faces or back edges, along with geometry outside the picture or behind the observer. Their comparison table lists a back-edge cull, based on dot products with face normals, among the steps of the hidden-line algorithms of L. G. Roberts (1963), Appel (1967), Loutrel (1967) and Galimberti and colleagues (1969). When the authors estimated the cost of each algorithm, they assumed that half of the faces in a scene are back faces removed by this early cull.[14]

Graphics APIs later made the test a standard rasterizer feature. The OpenGL 1.0 specification by Mark Segal and Kurt Akeley (the revision Khronos publishes is dated 1 July 1994) already defined CullFace and FrontFace, with culling initially disabled, a default mode of BACK and counterclockwise polygons treated as front-facing.[15]

Researchers in the 1990s looked for ways to reject back faces in groups instead of one polygon at a time, before the geometry reached the graphics hardware:

  • Leon A. Shirman and Salim S. Abi-Ezzi's "cone of normals" technique (1993) built, for each curved surface patch, a truncated cone containing all of its points and normal directions. A single scalar product could then show that a whole patch was back-facing, so the patch did not have to be tessellated.[16]
  • Subodh Kumar, Dinesh Manocha, William Garrett and Ming C. Lin presented hierarchical back-face computation at the 1996 Eurographics Rendering Workshop, with a journal version in Computers & Graphics in 1999. Their algorithm groups polygons into hierarchical clusters by orientation and position and uses the coherence of viewpoint motion to decide whether a whole cluster is back-facing. They reported overall frame-rate gains of 40 to 75 percent compared with standard back-face culling implemented in hardware.[17]
  • Hansong Zhang and Kenneth Hoff of the University of North Carolina at Chapel Hill proposed "normal masks" at the 1997 Symposium on Interactive 3D Graphics. Each polygon stores a two-byte code for the cluster of normal directions it falls in, and per frame the system builds a mask of the clusters that face away from the viewer, so the test becomes a single logical AND per polygon. A cluster counts as back-facing only if all of its normals do, which makes the method conservative. The paper reports culling over 40 percent of the polygons and a 60 to 80 percent speedup over hardware-only back-face culling; the test scene was two copies of a 70,000-polygon bunny model on an SGI Indigo2 Maximum Impact, with hardware back-face culling enabled in all runs.[3]

Cluster culling on modern GPUs

The cluster idea returned with GPU-driven rendering. In a 2018 introduction to the mesh shaders of NVIDIA's Turing GPUs, Christoph Kubisch wrote that fixed-function pipelines can waste memory loads fetching vertices of triangles that are later removed by back-face, frustum or sub-pixel culling. His meshlet descriptors included a bounding box and "a cone for backface-cluster culling", following work presented by Graham Wihlidal, and his example task shader culls up to 32 meshlets at a time before mesh shading.[18] The open-source meshoptimizer library computes such cone bounds for each meshlet; its documentation says a cone test rejects the entire meshlet "if all triangles are guaranteed to be back-facing from the camera point of view", and recommends running cluster culling at a lower frequency than mesh shading, in task or amplification shaders or a separate compute dispatch.[19]

Applications in VR and AR

Stereoscopic rendering

A stereoscopic display needs two images, so back-face tests are needed for two viewpoints. In 1991 Stephen J. Adelson, Larry F. Hodges and three co-authors described a stereoscopic back-face removal algorithm as part of a study of generating both eye views at once. Because back-facing depends on the viewing position, a polygon can be a back face for both eyes, for neither, or for only one. Their combined test needed, in the worst case, 4 multiplications, 4 additions and 3 comparisons, against 6 multiplications, 6 additions and 2 comparisons when each eye was handled separately, which they put at roughly a 33 percent improvement in running time for that step.[7]

Defaults and guidance in XR toolkits

XR frameworks keep back-face culling on by default and describe disabling it as a cost:

  • Apple's RealityKit, which is available on visionOS as well as iOS and macOS, culls back faces by default for its physically based material. Its documentation says this is usually correct because back faces are normally hidden by front-facing polygons, and that turning face culling off "results in less efficient rendering and may negatively impact your app's frame rate".[4]
  • The Standard shader of Microsoft's Mixed Reality Toolkit 2 defaults to back-face culling. The MRTK documentation says it "should be enabled as often as possible to improve rendering performance" and that culling should only be turned off when a two-sided mesh is required.[5]
  • StereoKit, an open-source OpenXR library for building XR applications, also culls back faces by default. Its documentation warns that with culling set to none "you can double the number of pixels the GPU ends up drawing".[6][20]

Inside-out geometry and 360-degree backgrounds

Front-face culling, the reverse setting, is a common tool in VR scenes that place the viewer inside an object. The A-Frame web framework for VR provides an a-sky primitive, a large sphere with a color or a 360-degree image mapped to its inside. Its documented defaults are a radius of 500 and a material side setting of back, while ordinary A-Frame materials default to front.[21][22][23] The documentation says that to be seamless, sky images should be equirectangular.[21] StereoKit and Unity both document front-face culling for flipping a mesh "inside-out".[6][13]

Limitations

Back-face culling only removes faces that point away from the viewer. It does not find front faces hidden behind other objects, or behind other parts of the same non-convex object. Adelson and colleagues note that the plane-equation test identifies the back faces of a convex object, and they used back-face removal as a preprocessing step before full hidden-surface elimination with a binary space partitioning tree combined with a z-buffer, or with a scan-line algorithm.[7] Removing hidden front-facing geometry needs other techniques, such as a depth buffer, viewing frustum culling and occlusion culling.

The method also assumes closed, opaque surfaces.[1] Single-sided surfaces that must be visible from both sides, and transparent objects whose far side should show through, need culling turned off.[13][5]

See also

References

  1. ↑ 1.0 1.1 1.2 1.3 "glFrontFace - OpenGL 4 Reference Pages". OpenGL 4 Reference Pages. Khronos Group. https://registry.khronos.org/OpenGL-Refpages/gl4/html/glFrontFace.xhtml. Retrieved 2026-10-13.
  2. ↑ 2.0 2.1 2.2 "Rasterization". Vulkan Specification (Vulkan Documentation Project). Khronos Group. https://docs.vulkan.org/spec/latest/chapters/primsrast.html. Retrieved 2026-10-13.
  3. ↑ 3.0 3.1 3.2 Hansong Zhang, Kenneth E. Hoff III (1997). "Fast Backface Culling Using Normal Masks". Proceedings of the 1997 Symposium on Interactive 3D Graphics (SI3D '97). ACM. doi:10.1145/253284.253314. https://cgvr.informatik.uni-bremen.de/teaching/cg_literatur/backface_normal_masks.pdf. Retrieved 2026-10-13.
  4. ↑ 4.0 4.1 "faceCulling - PhysicallyBasedMaterial". RealityKit documentation. Apple. https://developer.apple.com/documentation/realitykit/physicallybasedmaterial/faceculling-swift.property. Retrieved 2026-10-13.
  5. ↑ 5.0 5.1 5.2 "MRTK2 standard shader". MRTK 2 documentation, Microsoft Learn. Microsoft. https://learn.microsoft.com/en-us/windows/mixed-reality/mrtk-unity/mrtk2/features/rendering/mrtk-standard-shader. Retrieved 2026-10-13.
  6. ↑ 6.0 6.1 6.2 "Cull". StereoKit Documentation. https://stereokit.net/Pages/StereoKit/Cull.html. Retrieved 2026-10-13.
  7. ↑ 7.0 7.1 7.2 Stephen J. Adelson, Jeffrey B. Bentley, In Seok Chong, Larry F. Hodges, Joseph Winograd (1991). "Simultaneous Generation of Stereoscopic Views". Computer Graphics Forum, vol. 10, no. 1, pp. 3-10. doi:10.1111/1467-8659.1010003. https://doi.org/10.1111/1467-8659.1010003. Retrieved 2026-10-13.
  8. ↑ 8.0 8.1 8.2 "setCullMode(_:) - MTLRenderCommandEncoder". Metal documentation. Apple. https://developer.apple.com/documentation/metal/mtlrendercommandencoder/setcullmode(_:). Retrieved 2026-10-13.
  9. ↑ 9.0 9.1 9.2 "glCullFace - OpenGL 4 Reference Pages". OpenGL 4 Reference Pages. Khronos Group. https://registry.khronos.org/OpenGL-Refpages/gl4/html/glCullFace.xhtml. Retrieved 2026-10-13.
  10. ↑ 10.0 10.1 "D3D11_RASTERIZER_DESC structure (d3d11.h)". Win32 apps documentation, Microsoft Learn. Microsoft. https://learn.microsoft.com/en-us/windows/win32/api/d3d11/ns-d3d11-d3d11_rasterizer_desc. Retrieved 2026-10-13.
  11. ↑ "D3D11_CULL_MODE enumeration (d3d11.h)". Win32 apps documentation, Microsoft Learn. Microsoft. https://learn.microsoft.com/en-us/windows/win32/api/d3d11/ne-d3d11-d3d11_cull_mode. Retrieved 2026-10-13.
  12. ↑ "MTLCullMode". Metal documentation. Apple. https://developer.apple.com/documentation/metal/mtlcullmode. Retrieved 2026-10-13.
  13. ↑ 13.0 13.1 13.2 "Cull command in ShaderLab reference". Unity Manual. Unity Technologies. https://docs.unity3d.com/Manual/SL-Cull.html. Retrieved 2026-10-13.
  14. ↑ Ivan E. Sutherland, Robert F. Sproull, Robert A. Schumacker (1974-03). "A Characterization of Ten Hidden-Surface Algorithms". Computing Surveys, vol. 6, no. 1, pp. 1-55. ACM. doi:10.1145/356625.356626. https://doi.org/10.1145/356625.356626. Retrieved 2026-10-13.
  15. ↑ Mark Segal, Kurt Akeley (1994-07-01). "The OpenGL Graphics System: A Specification (Version 1.0)". OpenGL Registry. Khronos Group (originally Silicon Graphics). https://registry.khronos.org/OpenGL/specs/gl/glspec10.pdf. Retrieved 2026-10-13.
  16. ↑ Leon A. Shirman, Salim S. Abi-Ezzi (1993-08). "The Cone of Normals Technique for Fast Processing of Curved Patches". Computer Graphics Forum, vol. 12, no. 3, pp. 261-272. doi:10.1111/1467-8659.1230261. https://doi.org/10.1111/1467-8659.1230261. Retrieved 2026-10-13.
  17. ↑ Subodh Kumar, Dinesh Manocha, William Garrett, Ming Lin (1999-10). "Hierarchical back-face computation". Computers & Graphics, vol. 23, no. 5, pp. 681-692. Elsevier. doi:10.1016/S0097-8493(99)00091-6. https://doi.org/10.1016/S0097-8493(99)00091-6. Retrieved 2026-10-13.
  18. ↑ Christoph Kubisch (2018-09-17). "Introduction to Turing Mesh Shaders". NVIDIA Technical Blog. NVIDIA. https://developer.nvidia.com/blog/introduction-turing-mesh-shaders/. Retrieved 2026-10-13.
  19. ↑ "meshoptimizer README". meshoptimizer (GitHub). https://github.com/zeux/meshoptimizer/blob/master/README.md. Retrieved 2026-10-13.
  20. ↑ "StereoKit". StereoKit Documentation. https://stereokit.net/. Retrieved 2026-10-13.
  21. ↑ 21.0 21.1 "a-sky". A-Frame 1.8.0 documentation. https://aframe.io/docs/1.8.0/primitives/a-sky.html. Retrieved 2026-10-13.
  22. ↑ "material". A-Frame 1.8.0 documentation. https://aframe.io/docs/1.8.0/components/material.html. Retrieved 2026-10-13.
  23. ↑ "Introduction". A-Frame 1.8.0 documentation. https://aframe.io/docs/1.8.0/introduction/. Retrieved 2026-10-13.