Ни великолепная форма геометрии, ни ее изысканная текстура не делают 3D-модель реалистичной в сцене AR / VR. Это скорее свет с его тенями, который делает свою работу. В AR тени - ключевой компонент интеграции модели, потому что тени являются объектами заземления. Объекты без теней кажутся парящими в воздухе. А без надлежащей интенсивности и направления света зритель никогда не поверит, что модель принадлежит реальной сцене.

RealityKit неявно использует алгоритм оценки освещенности, который помогает нам автоматически освещать виртуальные модели в соответствии с условиями освещения в реальном мире. Но также мы можем явно добавлять источники света в нашу сцену, когда захотим.

В RealityKit есть четыре типа источников света, которые помогают нам осветить сцену: точечный свет, точечный свет, направленный свет и на основе изображения. свет (IBL). В отличие от SceneKit, в котором есть только классы для освещения - класс SCNLight с соответствующей структурой LightType, - RealityKit, по порядку чтобы предложить удобный и эффективный интерфейс программирования для разработчиков Swift, использует как классы для наследования (парадигма ООП), так и протоколы для композиции (парадигма POP).

RealityKit 2.0 имеет четыре класса и три протокола для создания уникальных условий освещения. Вы можете использовать их вместе или по отдельности, на ваше усмотрение.

public class DirectionalLight: Entity, HasDirectionalLight
public class PointLight: Entity, HasPointLight
public class SpotLight: Entity, HasSpotLight
public struct ImageBasedLight

Структура ImageBasedLight вложена в структуру Environment, которая находится внутри представления RealityKit. Основанный на изображении свет используется для освещения окружающей среды.

extension ARView {
    public struct Environment {
        public struct ImageBasedLight {
            public var resource: EnvironmentResource?
            public var intensityExponent: Float
        }
    }
}

Следовательно, мы можем получить доступ к свойствам освещения окружающей среды, используя точечную нотацию Swift:

arView.environment.lighting.resource
arView.environment.lighting.intensityExponent

Давайте узнаем, что такое источники света RealityKit и какие типы теней они создают. Мы протестируем все типы источников света в простой сцене, где активирован только источник света RealityKit по умолчанию (по умолчанию IBL).

Направленный свет

Направленный свет имитирует параллельные лучи, исходящие от далекой звезды - Солнца. Наиболее важным аспектом этого типа света является его ориентация. Положение направленного света неважно. Этот источник света создает тени карты глубины. Интенсивность направленного света измеряется в люмен на квадратный метр.

Важно: Если в сцене нет источников света, кроме направленного, поверхности, параллельные направлению световых лучей, будут черными .

Вот свойства DirectionalLight:

let directionalLight = DirectionalLight()
directionalLight.light.color = .red
directionalLight.light.intensity = 20000
directionalLight.light.isRealWorldProxy = true
directionalLight.shadow?.maximumDistance = 10.0
directionalLight.shadow?.depthBias = 5.0
directionalLight.orientation = simd_quatf(angle: -.pi/1.5,
                                           axis: [0,1,0])

Точечный свет

Точечный свет - это всенаправленный свет, подобный электрической лампочке. Его положение имеет решающее значение, но ориентация не имеет значения. Этот тип источника света в настоящий момент не может генерировать тени, поэтому нет свойства экземпляра с именем shadow. Интенсивность точечного света измеряется в люменах.

Вот свойства PointLight:

let pointLight = PointLight()
pointLight.light.color = .blue
pointLight.light.intensity = 15000000
pointLight.light.attenuationRadius = 7.0
pointLight.position = [4,0,1]

Прожектор

Как следует из названия, SpotLight имитирует конический луч света, который вы много раз видели в театре, цирке или на концерте. Этот световой конус создает горячую точку, область между внутренним и внешним световыми конусами (также известную как полутень, которая определяет угол внутри светового конуса, при котором свет начинает переходить от полной силы к отсутствию освещения) и мягкие края тени. Если ваше устройство оснащено набором микросхем A12 или лучше, тип визуализируемых теней будет трассировка лучей (тени высокого качества), но более ранние версии наборов микросхем Apple ( A9, A10, A11) могут генерировать только тени с отображением глубины (поддельные проекции). Интенсивность прожектора измеряется в люменах.

Вот свойства SpotLight:

let spotLight = SpotLight()
spotLight.light.color = .green
spotLight.light.intensity = 2500000
spotLight.light.innerAngleInDegrees = 70
spotLight.light.outerAngleInDegrees = 120
spotLight.light.attenuationRadius = 9.0
spotLight.shadow = SpotLightComponent.Shadow()
spotLight.position.y = 5.0
spotLight.orientation = simd_quatf(angle: -.pi/1.5,
                                    axis: [1,0,0])

Освещение на основе изображения

В RealityKit ваша сцена может быть освещена с помощью 32-битного изображения с расширенным динамическим диапазоном, которое может быть в HDR или OpenEXR формат файла. Освещение на основе изображения работает с положительными и отрицательными значениями. HDRI может содержать девять или более изображений с шагом 1/3 ступени, но для работы с HDRI вам потребуется как минимум три экспозиции.

RealityKit имеет HDR-освещение по умолчанию, и мы можем легко увеличить интенсивность этого света, остановив экспозицию следующим образом:

arView.environment.lighting.intensityExponent = 2

И, как я сказал ранее, интенсивность света HDR также может быть отрицательной. Мы могли бы уменьшить интенсивность окружающего света, прекратив его экспозицию:

arView.environment.lighting.intensityExponent = -2

Создание нестандартных источников света

Теперь, когда мы достаточно знаем о типах источников света RealityKit, давайте создадим нашу собственную установку источников света. Каждый класс должен наследовать от родительского класса Entity и соответствовать соответствующему протоколу.

Сначала мы создадим собственный направленный свет:

import ARKit
import RealityKit
class CustomDirectionalLight: Entity, HasDirectionalLight {
    required init() {
        super.init()
        self.light = DirectionalLightComponent(color: .red,
                                           intensity: 20000,
                                    isRealWorldProxy: true)
        self.shadow = DirectionalLightComponent.Shadow(
                                       maximumDistance: 10,
                                             depthBias: 5.0)
        self.orientation = simd_quatf(angle: -.pi/1.5, 
                                       axis: [0,1,0])
    }
}

Затем точечный свет:

class CustomPointLight: Entity, HasPointLight {
    required init() {
        super.init()
  
        self.light = PointLightComponent(color: .blue,
                                     intensity: 15000000,
                             attenuationRadius: 7.0)
        self.position = [4,0,1]
    }
}

И, наконец, прожектор:

class CustomSpotLight: Entity, HasSpotLight {
    required init() {
        super.init()
        self.light = SpotLightComponent(color: .green,
                                    intensity: 2500000,
                          innerAngleInDegrees: 70,
                          outerAngleInDegrees: 120,
                            attenuationRadius: 9.0)
        self.shadow = SpotLightComponent.Shadow()
        self.position.y = 5.0
        self.orientation = simd_quatf(angle: -.pi/1.5,
                                       axis: [1,0,0])
    }
}

Теперь мы можем использовать эти типы источников света вместе в файле ViewController.swift:

class ViewController: UIViewController {
    @IBOutlet weak var arView: ARView!
    override func viewDidLoad() {
        super.viewDidLoad()
        // Lights
        let directLight = CustomDirectionalLight()
        let pointLight = CustomPointLight()
        let spotLight = CustomSpotLight()
        let lightAnchor = AnchorEntity(world: [0,0,-3])
        lightAnchor.addChild(directLight)
        lightAnchor.addChild(pointLight)
        lightAnchor.addChild(spotLight)
        // Temple model from Reality Composer
        let sceneAnchor = try! Experience.loadTempleScene().   
        sceneAnchor.templeModel!.position.y = -0.6
        sceneAnchor.templeModel!.scale = [4,4,4]
   
        // Plane primitive
        let plane: MeshResource = .generatePlane(width: 7.0,
                                                 depth: 7.0)
        let material = SimpleMaterial(color: .darkGray,
                                 isMetallic: false)
        let entity = ModelEntity(mesh: plane,
                            materials: [material])
        entity.position.y = -0.6
        sceneAnchor.addChild(entity)
        arView.scene.anchors.append(sceneAnchor)
        arView.scene.anchors.append(lightAnchor)
    }
}

Вуаля!

Часто вам нужно осветить сцену собственным файлом HDR. Для этого просто добавьте ресурс среды в свой проект - создайте папку с именем «iskybox» и поместите HDR изображение внутри. Изображение должно быть картой окружающей среды в проекции широты и долготы. Перетащите папку в навигатор файлов проекта Xcode. В открывшейся раскрывающейся панели параметров выберите Создать ссылки на папки.

Затем вставьте эти строки кода в метод viewDidLoad ():

override func viewDidLoad() {
    super.viewDidLoad()
    arView.environment.lighting.resource = try! .load(named: "iskybox/city.hdr")
    arView.environment.lighting.intensityExponent = -1
    // blah-blah...
}

Однако, если вам не нужно освещение окружающей среды, вы можете отключить его, используя свойство типа disableAREnvironmentLighting из структуры RenderOptions. который соответствует протоколу OptionSet.

arView.renderOptions = [.disableAREnvironmentLighting,
                        .disableMotionBlur]

P. S.

Несомненно, на данный момент SceneKit имеет более богатый арсенал типов освещения, а точнее в 2 раза больше. Вот их список:

Ambient
Area
Directional
Environment HDR
Omni
Photometric IES
Probe
Spot

Но я уверен, что список светильников RealityKit тоже очень скоро вырастет.

Если вы хотите включить освещение, но не хотите перегружать процессор, обратите внимание на текстуры на основе теней.

Пожертвовать автору

addr1q9w70n62nu8p7f9ukfn66gzumm9d9uxwppkx7gk7vd7gy0ehfavj97gkncwm8t8l8l8x9e4adzmw2djh4y5gd9rmtewqr99zr3

На этом пока все.

Если эта публикация вам полезна, нажмите кнопку Хлопать и удерживайте ее. На Medium вы можете аплодировать до 50 за каждое сообщение.

Если у вас есть какие-либо вопросы, вы можете связаться со мной через StackOverflow.

До встречи!