🌫️
【visionOS】SceneにOcclusionを適用する
はじめに
【Swift】visionOSのカスタムジェスチャーで玉を飛ばすで紹介したSceneReconstructionProviderを使ってSceneにOcclusionを適用したいと思います。何も適用しないと壁があるのに鬼が透過して表示されてしまいます。
つくったもの
環境
- Xcode Version 15.3
- visionOS 1.1
Occlusionとは
Occlusionとは、ARを使って仮想オブジェクトを表示する際に、前にある現実の物体が奥にある仮想オブジェクトを隠して、位置関係を自然に表示する現象のことをいいます。
SceneにOcclusionを適用する
SceneにCollisionComponentやPhysicsBodyComponentなどを追加していますが、Occlusionを追加しているのはgenerateModelEntity
という関数の中でlet material = OcclusionMaterial()
しているだけです。
generateModelEntityの中身は以下の記事に詳しく書いてあるのでそちらを参照してください。
(ほぼそのまま参考にさせていただきました。ありがとうございます。)
// 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を学びながらこちらのアプリをアップデートしていくのでフィードバックもお待ちしております。
Discussion