I have found a different approach that works for me. I have abandoned setting the content.environment property and use a sky dome model for the background and use ImageBasedLightComponent and ImageBasedLightReceiverComponent to choose the lighting for the cube.
For more information on this approach, see WWDC session Optimize your 3D assets for spatial computing, and jump to sections
15:07 - Sky dome setup
16:03 - Image-based lighting
I did everything programmatically (instead of using Reality Composer Pro), but it pretty much works the same.
Sample code (caveat, I have no idea if this is the preferred approach, but it works for me):
import SwiftUI
import RealityKit
import os.log
struct MyRealityView: View {
@Binding var useNebulaForLighting: Bool
@Binding var showNebula: Bool
@State private var nebulaIbl: ImageBasedLightComponent?
@State private var indoorIbl: ImageBasedLightComponent?
@State private var iblEntity: Entity?
@State private var litCube: Entity?
@State private var skydome: Entity?
var body: some View {
RealityView { content in
// Create a red cube 1m on a side
let mesh = MeshResource.generateBox(size: 1.0)
let simpleMaterial = SimpleMaterial(color: .red, isMetallic: false)
let model = ModelComponent(
mesh: mesh,
materials: [simpleMaterial]
)
let redBoxEntity = Entity()
redBoxEntity.components.set(model)
content.add(redBoxEntity)
litCube = redBoxEntity
// Get hi-res texture to show as background
let immersion_name = "BlueNebula"
guard let resource = try? await TextureResource(named: immersion_name) else {
fatalError("Unable to load texture.")
}
var material = UnlitMaterial()
material.color = .init(texture: .init(resource))
// Create sky dome sphere
let sphereMesh = MeshResource.generateSphere(radius: 1000)
let sphereModelComponent = ModelComponent(mesh: sphereMesh, materials: [material])
// Create an entity and set its model component
let sphereEntity = Entity()
sphereEntity.components.set(sphereModelComponent)
// Trick/hack to make the texture image point inward to the viewer.
sphereEntity.scale *= .init(x: -1, y: 1, z: 1)
// Add sky dome to the scene
skydome = sphereEntity
skydome?.isEnabled = showNebula
content.add(skydome!)
// Create Image Based Lighting entity for scene
iblEntity = Entity()
content.add(iblEntity!)
// Load low-res nebula resource for image based lighting
if let environmentResource = try? await EnvironmentResource(named: "BlueNeb2") {
let iblSource = ImageBasedLightComponent.Source.single(environmentResource)
let iblComponent = ImageBasedLightComponent(source: iblSource)
nebulaIbl = iblComponent
}
// Load low-res indoor light resource for image based lighting
if let environmentResource = try? await EnvironmentResource(named: "IndoorLights") {
let iblSource = ImageBasedLightComponent.Source.single(environmentResource)
let iblComponent = ImageBasedLightComponent(source: iblSource)
indoorIbl = iblComponent
}
// Set initial settings
applyModelSettings()
}
update: { content in
applyModelSettings()
}
.realityViewCameraControls(CameraControls.orbit)
}
func applyModelSettings() {
// Set image based lighting
if (useNebulaForLighting == true)
&& (litCube != nil)
&& (nebulaIbl != nil) {
iblEntity!.components.set(nebulaIbl!)
let iblrc = ImageBasedLightReceiverComponent(imageBasedLight: iblEntity!)
litCube?.components.set(iblrc)
}
else if (useNebulaForLighting == false)
&& (litCube != nil)
&& (indoorIbl != nil) {
iblEntity!.components.set(indoorIbl!)
let iblrc = ImageBasedLightReceiverComponent(imageBasedLight: iblEntity!)
litCube?.components.set(iblrc)
}
// set skydome's status
skydome?.isEnabled = showNebula
}
}
Topic:
Spatial Computing
SubTopic:
General
Tags: