Qt Quick 3D - Volumetric Light Example

Demonstrates how the QtQuick3D Render Extension can be used to implement volumetric light.

An stage with all kind of volumetric lights

Overview

This example shows how to use QtQuick3D Render Extension to make a volumetric light extension and how can it be use as a component in a project.

Controls

For navigation, you can orbit around the scene and you can use settings panel to change lights, volumetric fog and scene settings.

Implementation

The Volumetric fog extension is implemented in the VolumetricFogExtension. This is located in the separate sub-project VFExtension, so you can easily re-use it in other projects.

The VolumetricFogExtension has the following properties that need to be set:

 VolumetricFogExtension {
     id: froxelExtension
     froxelWidth: 160
     froxelHeight: 96
     froxelDepth: 96
     nearPlane: 1.0
     farPlane: 4000.0
     fogVolumes: [ fogSphere ]

     iesTexture: settings.iesLights ? iesAtlasTexture : null
     iesCount: iesTextureData.sources.length
     iesLightProfiles: [
     IESLightProfileIndex { light: pinkSpot; index: settings.iesLightIndex; intensity: 0.5}
     ]
 }

The froxelWidth, froxelHeight, and froxelDepth properties define the resolution of the 3D froxel grid used by the volumetric compute shader. Higher resolution produces more detailed light scattering at the cost of GPU memory and compute time.

The nearPlane and farPlane properties define the depth range over which the volumetric effect is computed, and should match the PerspectiveCamera's clip distances.

The fogVolumes property holds a list of Fog3DVolume nodes that define where volumetric fog is present in the scene.

IES Light Profiles

IES light profiles can be used to shape the angular light distribution of spot lights. The iesTexture property takes a Texture whose data is generated by an IESTextureData object that parses .ies files and packs them into a 2D atlas texture. The iesCount property specifies how many profiles are packed in the atlas, and iesLightProfiles maps individual lights to profile indices via IESLightProfileIndex objects.

 Texture {
     id: iesAtlasTexture
     textureData: IESTextureData {
         id: iesTextureData
         sources: [
             "qrc:/assets/l0.ies",
             "qrc:/assets/l1.ies",
             "qrc:/assets/l2.ies",
             "qrc:/assets/l3.ies",
             "qrc:/assets/l4.ies",
             "qrc:/assets/l5.ies"
         ]
     }
     tilingModeHorizontal: Texture.ClampToEdge
     tilingModeVertical: Texture.ClampToEdge
     minFilter: Texture.Linear
     magFilter: Texture.Linear
     generateMipmaps: false
 }
Attaching the Extension to a View3D

The extension is registered with the View3D through its extensions property, which lets the render pipeline invoke the extension's compute shader each frame:

 View3D {
     extensions: [ froxelExtension ]
 }
Fog Volumes

Fog regions are defined using Fog3DVolume nodes placed in the scene. Each volume supports two shapes via the type property: Fog3DVolume.Sphere and Fog3DVolume.Box. The extents property defines the bounding dimensions, while color and density control the visual appearance.

Animated noise is applied by advancing noiseOffset each frame. Height-based density falloff can be enabled with heightEnabled together with leastIntenseY, mostIntenseY, and heightCurve:

 Fog3DVolume {
     id: fogSphere
     type: Fog3DVolume.Sphere
     extents: Qt.vector3d(5000, 5000, 5000)
     color: settings.fogVolumeColor
     density: settings.fogVolumeDensity
     noiseOffset: Qt.vector3d(se.time * 0.1 * settings.fogSpeed, 0, 0)
     noiseScale: settings.fogVolumeNoiseScale
     heightEnabled: settings.fogVolumeHeightEnabled
     leastIntenseY: settings.fogVolumeHeightLeastY
     mostIntenseY: settings.fogVolumeHeightMostY
     heightCurve: settings.fogVolumeHeightCurve
 }
VolumetricFogEffect

The extension exposes its result through the read-only froxelTexture property, a 3D RGBA texture containing the accumulated light scattering data for each froxel. This texture is consumed by the VolumetricFogEffect post-processing effect added to the ExtendedSceneEnvironment. The effect ray-marches through the froxel texture and composites the volumetric light onto the rendered frame:

 environment: ExtendedSceneEnvironment {
     effects: [
         VolumetricFogEffect {
             froxelTexture: froxelExtension.froxelTexture
             cameraPosition: camera.scenePosition
             cameraForward: camera.forward
             invViewMatrix: camera.sceneTransform
             marchSteps: froxelExtension.froxelDepth
             nearPlane: froxelExtension.nearPlane
             farPlane: froxelExtension.farPlane
             frameBaseJitter: se.temporalAAEnabled &&
                              se.temporalAAMode === SceneEnvironment.TAAMotionVector &&
                              se.antialiasingMode !== SceneEnvironment.MSAA ? 1.0 : 0.0
             jitterIntensity: settings.jitterIntensity
         }
     ]
 }

The marchSteps property controls the number of ray marching steps and should match froxelDepth. The frameBaseJitter and jitterIntensity properties enable temporal dithering to reduce banding artifacts when used together with temporal anti-aliasing.

Example project @ code.qt.io