Show/Hide Mobile Menu

Shadows & Lights in RealityKit

Nov 21, 2022

Shadows

In AR mode, RealityKit will generate ground shadows and estimate lighting from the environment. It doesn't seem to cast any shadows on the model itself. If you create model entities in code, ground shadows don't seem to be generated.

Realitykit shadows - progmatic
No ground shadows when the model is created programmatically.
RealityKit shadows - loaded model
Models loaded from USDZ file or Reality Composer project show ground shadows.

You can download a demo app that demonstrates the above here.

Lights

Lights only seem to work in non-AR mode. You can set this mode by setting cameraMode to .nonAR when constructing an ARView.

ARView(frame: .zero, cameraMode: .nonAR, automaticallyConfigureSession: true)

A RealityKit scene can contain up to eight dynamic lights which includes point, spot or directional lights. Only one directional light is supported in a scene. It can also contain an image light - you use a high dynamic range (HDR) image to generate the lighting. Lights are components but RealityKit provides wrapper entities for each of the light components.

Point Light

let pointLight = PointLight() // pointLight is an entity
pointLight.light.intensity = 1000000 // pointLight.light is a component
pointLight.light.color = .blue
pointLight.light.attenuationRadius = 5
pointLight.position = [0, 0.2, 0]

anchorEntity.addChild(pointLight)
Realitykit lights - point light

Point lights emit light in all directions. PointLight class extends Entity and has a PointLightComponent assigned to the light property. Point lights don't seem to cast any shadows.

  • intensity: The intensity of the light measured in lumens.
  • attenuationRadius: The distance in metres it takes for the light intensity to drop to zero i.e. the range of the light.

Spot Light

let spotLight = SpotLight()
spotLight.light.color = .green
spotLight.light.intensity = 1000000
spotLight.light.innerAngleInDegrees = 40
spotLight.light.outerAngleInDegrees = 60
spotLight.light.attenuationRadius = 10
spotLight.shadow = SpotLightComponent.Shadow()
spotLight.look(at: [1, 0, -4], from: [0, 5, -5], relativeTo: nil)

anchorEntity.addChild(spotLight)
Realitykit lights - spot light

Spot lights are like desk lamps - they emit light in a cone shape. If you want the spot light to cast shadows you will need to set the shadow property to a new SpotLightComponent.Shadow instance.

  • innerAngleInDegrees: The angle in degrees where the light begins to fade.
  • outerAngleInDegrees: The angle in degrees where the fading light ends.

Directional Light

let directionalLight = DirectionalLight()
directionalLight.light.color = .red
directionalLight.light.intensity = 1000000
directionalLight.shadow?.maximumDistance = 5
directionalLight.shadow?.depthBias = 1
directionalLight.look(at: [1, 0, 1], from: [0, 1, 0], relativeTo: nil)

anchorEntity.addChild(directionalLight)
Realitykit lights - directional light

A directional light is like the sun - it lights everywhere with the same intensity. It doesn't have a position but it does have a direction. DirectionalLight automatically assigns a DirectionalLightComponent.Shadow to a shadow property with maximumDistance set to 5 and depthBias set to 1.

  • shadow?.maximumDistance: If the distance between the object that is casting shadows and the object that is receiving shadows is equal or less than this value, shadows will be displayed.
  • shadow?.depthBias: Changing this value didn't seem to have any visible difference.

The shadows for lights are razor sharp and there doesn't seem to be a way to adjust them.

Image Light

RealityKit supports a high dynamic range image as a light. RealityKit supports these images either in HDR or OpenEXR format. Polyhaven is a good place to get free HDRIs - it supports both formats. Copy the image into the left sidebar of XCode making sure that the target is checked next to "Add to targets".

arView.environment.lighting.resource = try! .load(named: "dreifaltigkeitsberg_2k.hdr")
arView.environment.lighting.intensityExponent = 1

You don't specify the intensity directly instead you specify an exponent e.g. an exponent of 2 is 10^2 = 100, an exponent of 0 is 10^0 = 1 and an exponent of -2 is 10^-2 = 0.01.

You can download an app that demonstrates adding lights here.