Shadows & Lights in RealityKit
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.
You can download a demo app that demonstrates the above here.
Lights only seem to work in non-AR mode. You can set this mode by setting
.nonAR when constructing an
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.
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)
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.
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)
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
- innerAngleInDegrees: The angle in degrees where the light begins to fade.
- outerAngleInDegrees: The angle in degrees where the fading light ends.
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)
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.
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.