How glTF doubleSided Ensures Two-Sided Visibility

This article explains how the doubleSided property in the glTF (GL Transmission Format) 2.0 specification enables two-sided polygon rendering. It details the default behavior of 3D graphics pipelines regarding backface culling, how setting the doubleSided boolean alters this behavior, how real-time rendering engines handle lighting and normal orientation on back-facing surfaces, and the performance implications of enabling this feature.

The Default Behavior: Backface Culling

In standard real-time 3D rendering (such as WebGL, OpenGL, Vulkan, and DirectX), graphics hardware uses a process called backface culling to optimize performance. Triangles are defined by their vertex winding order—typically counter-clockwise for front-facing polygons. When a triangle faces away from the camera, the hardware automatically discards it before shading.

In glTF, materials default to single-sided rendering where the doubleSided property is set to false. Under these conditions, viewing the back side of a polygon results in complete invisibility, creating transparency where a surface should logically exist.

The Role of the doubleSided Property

The glTF specification allows materials to explicitly declare whether both sides of a surface should be rendered using the doubleSided boolean inside the material object:

{
  "materials": [
    {
      "name": "Fabric",
      "doubleSided": true
    }
  ]
}

When an engine parses a glTF file and encounters "doubleSided": true, it instructs the graphics API to disable backface culling for any mesh primitive referencing that material. As a result, rasterization occurs regardless of whether the triangle winds clockwise or counter-clockwise relative to the camera.

Surface Normal Inversion and Lighting

Disabling backface culling is only half of the requirement for correct visibility. In physically based rendering (PBR), surface normals dictate how light interacts with a mesh. If a backface simply used the original geometry's normal, light calculations would compute shading as if the light were striking the opposite side, resulting in incorrect dark patches or inverted specular highlights.

To ensure visual accuracy, the glTF specification mandates that when doubleSided is true, renderers must negate (flip) the normal vector for back-facing fragments during shading:

  • In GLSL-based pipelines, the shader checks the built-in boolean gl_FrontFacing.
  • If gl_FrontFacing is false, the normal vector (\(N\)) is multiplied by \(-1.0\).
  • If tangent vectors and normal maps are present, the bitangent and tangent space calculations are similarly mirrored so normal map details render correctly on the reverse side.

This conditional inversion allows both sides of thin geometry—such as leaves, paper, cloth, or chainlink fences—to receive proper diffuse and specular lighting based on their orientation relative to the light sources.

Performance Considerations

While doubleSided is essential for flat geometry that lacks volume, it carries a performance cost:

  • Fragment Shader Load: The GPU must process fragments that would otherwise be discarded during rasterization.
  • Shader Branching: Determining whether a face is front- or back-facing introduces minor shader logic overhead.
  • Overdraw: If applied carelessly to closed, watertight meshes (such as characters or solid buildings), it wastes GPU cycles rendering hidden interior faces.

Renderers conformant with the glTF 2.0 specification treat doubleSided strictly as a material-level instruction to disable face culling and dynamically invert back-facing normals, providing a standardized way to achieve two-sided visibility across disparate 3D software and runtime engines.