🌫️

【visionOS】SceneにOcclusionを適用する

2024/05/27に公開

はじめに

【Swift】visionOSのカスタムジェスチャーで玉を飛ばすで紹介したSceneReconstructionProviderを使ってSceneにOcclusionを適用したいと思います。何も適用しないと壁があるのに鬼が透過して表示されてしまいます。

つくったもの

環境

  1. Xcode Version 15.3
  2. visionOS 1.1

Occlusionとは

Occlusionとは、ARを使って仮想オブジェクトを表示する際に、前にある現実の物体が奥にある仮想オブジェクトを隠して、位置関係を自然に表示する現象のことをいいます。

SceneにOcclusionを適用する

SceneにCollisionComponentやPhysicsBodyComponentなどを追加していますが、Occlusionを追加しているのはgenerateModelEntityという関数の中でlet material = OcclusionMaterial()しているだけです。
generateModelEntityの中身は以下の記事に詳しく書いてあるのでそちらを参照してください。
(ほぼそのまま参考にさせていただきました。ありがとうございます。)

https://zenn.dev/shu223/articles/visionos_scenemesh

// SceneReconstuctionのAnchorでMeshEntityやCollisionを更新
@MainActor
func processReconstructionUpdates() async {
    for await update in sceneReconstruction.anchorUpdates {
        let meshAnchor = update.anchor

        guard let shape = try? await ShapeResource.generateStaticMesh(from: meshAnchor) else { continue }
        switch update.event {
        case .added:
            let entity =  try! await generateModelEntity(geometry: meshAnchor.geometry)
            entity.name = "Scene"

            entity.transform = Transform(matrix: meshAnchor.originFromAnchorTransform)
            entity.collision = CollisionComponent(shapes: [shape], isStatic: true)
            entity.physicsBody = PhysicsBodyComponent(mode: .static)

            sceneMeshEntities[meshAnchor.id] = entity
            contentEntity.addChild(entity)
        case .updated:
            guard let entity = sceneMeshEntities[meshAnchor.id] else { continue }

            entity.transform = Transform(matrix: meshAnchor.originFromAnchorTransform)
            entity.collision = CollisionComponent(shapes: [shape], isStatic: true)
            entity.physicsBody = PhysicsBodyComponent(mode: .static)

            sceneMeshEntities[meshAnchor.id] = entity
            contentEntity.addChild(entity)
        case .removed:
            sceneMeshEntities[meshAnchor.id]?.removeFromParent()
            sceneMeshEntities.removeValue(forKey: meshAnchor.id)
        }
    }
}
@MainActor func generateModelEntity(geometry: MeshAnchor.Geometry) async throws -> ModelEntity {
    // generate mesh
    var desc = MeshDescriptor()
    let posValues = geometry.vertices.asSIMD3(ofType: Float.self)
    desc.positions = .init(posValues)
    let normalValues = geometry.normals.asSIMD3(ofType: Float.self)
    desc.normals = .init(normalValues)
    do {
        desc.primitives = .polygons(
            (0..<geometry.faces.count).map { _ in UInt8(3) },
            (0..<geometry.faces.count * 3).map {
                geometry.faces.buffer.contents()
                    .advanced(by: $0 * geometry.faces.bytesPerIndex)
                    .assumingMemoryBound(to: UInt32.self).pointee
            }
        )
    }
    let meshResource = try MeshResource.generate(from: [desc])
    // OcclusionMaterialを適用する
    let material = OcclusionMaterial()
    let modelEntity = ModelEntity(mesh: meshResource, materials: [material])
    return modelEntity
}

おわりに

以上、「SceneにOcclusionを適用する」でした。
今回の内容は結構いろんなパターンで使えるのではないでしょうか。
今後もvisionOSについて発信していきますので、この記事が参考になったと思ったらぜひ♡をお願いします。

また、今回の記事で紹介している空間シューティングゲーム「妖怪バスターZ」を日本発売前の2024年5月3日にリリースすることができました!!
ぜひインストールして遊んでみてください。
これからもvisionOSを学びながらこちらのアプリをアップデートしていくのでフィードバックもお待ちしております。

https://apps.apple.com/us/app/yokai-buster-z/id6502185713

Discussion