swiftuilightingrealitykit

RealityKit – How to disable default lighting in `.nonAR` ARView?


I am learning Apple's RealityKit for the first time and created the sphere in the code below. Without creating/adding any light source to the scene, the sphere is already fully lit all around in the preview and you can even see light source reflections on its surface.

Since I didn't create a light source, I expect at this point, to see just a black screen. When I uncomment the part of the code which does create a point light, I expect to see the sphere lit ONLY from the right side, with the opposite side completely dark.

I tried arView.renderOptions = [.disableAREnvironmentLighting] but this does nothing. Been scouring google searches for the past hour and cannot find a solution to this. Any help is appreciated.

import SwiftUI
import RealityKit

struct ARViewContainer : UIViewRepresentable {
    func makeUIView(context: Context) -> ARView {

        let arView = ARView(frame: .zero,
                            cameraMode: .nonAR,
                            automaticallyConfigureSession: false)

        arView.renderOptions = [.disableAREnvironmentLighting]
        
        /*let pointLight = PointLight()
        pointLight.light.intensity = 100000
        let lightAnchor = AnchorEntity(world: [1,0,0])
        lightAnchor.addChild(pointLight)
        arView.scene.addAnchor(lightAnchor)*/
        
        var sphereMaterial = SimpleMaterial()
        sphereMaterial.roughness = MaterialScalarParameter(floatLiteral: 0)
        let sphereEntity = ModelEntity(mesh: .generateSphere(radius: 0.5), materials: [sphereMaterial])
        let sphereAnchor = AnchorEntity(world: .zero)
        sphereAnchor.addChild(sphereEntity)
        arView.scene.anchors.append(sphereAnchor)
        
        return arView
    }
    func updateUIView(_ view: ARView, context: Context) { }
}
struct ContentView : View {
    var body: some View {
        ARViewContainer().ignoresSafeArea()
    }
}

Code result:

enter image description here


Solution

  • Disabling default environment lighting in ARView

    Since the common approach to disable HDR lighting in a RealityKit scene does not work, I propose a method that will help you bypass this limitation.

    arView.environment.lighting.resource = nil       // not working
    

    To disable a lighting environment resource data in AR scene, make a folder with a name that ends in .skybox, and place a single rectangular black .jpg, .png, .hdr or .exr image inside. Then drag the folder into your Xcode project file navigator. In the options pane, choose to create a folder reference (not a group), and add the folder to your app’s target. At build time, Xcode compiles the image for use as an environment resource and inserts the result into the app bundle.

    enter image description here

    Here's a code:

    import SwiftUI
    import RealityKit
    
    struct ContentView : View {
        @State var arView = ARView(frame: .zero)
        
        var body: some View {
            ARViewContainer(arView: arView)
                .ignoresSafeArea()
                .onAppear {
                    arView.cameraMode = .nonAR
                    arView.environment.lighting.resource = try! .load(named: "black")
                }
        }
    }
    

    struct ARViewContainer : UIViewRepresentable {
        var arView: ARView
        
        func makeUIView(context: Context) -> ARView {
            
            var sphereMaterial = SimpleMaterial()
            sphereMaterial.roughness = .float(0.0)
            sphereMaterial.metallic = .float(0.3)
    
            let sphereEntity = ModelEntity(mesh: .generateSphere(radius: 0.5), 
                                      materials: [sphereMaterial])
    
            let sphereAnchor = AnchorEntity(world: .zero)
            sphereAnchor.addChild(sphereEntity)
            arView.scene.anchors.append(sphereAnchor)
            
            let pointLight = PointLight()
            pointLight.light.intensity = 50_000
            pointLight.light.color = .red
            pointLight.position.z = 2.0
            sphereAnchor.addChild(pointLight)
    
            return arView
        }
    
        func updateUIView(_ view: ARView, context: Context) { }
    }
    

    The following image illustrates how a red-color Point Light is composited together with RealityKit's default environment HDR light and how it looks like without it.

    enter image description here