diff --git a/Chapter8/Chapter8.xcodeproj/project.pbxproj b/Chapter8/Chapter8.xcodeproj/project.pbxproj index 61f15f7..e501980 100644 --- a/Chapter8/Chapter8.xcodeproj/project.pbxproj +++ b/Chapter8/Chapter8.xcodeproj/project.pbxproj @@ -18,6 +18,7 @@ C3E575212BF1C633004E3EDC /* SceneReconstruction.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3E575202BF1C633004E3EDC /* SceneReconstruction.swift */; }; C3E575232BF1D739004E3EDC /* WorldTracking.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3E575222BF1D739004E3EDC /* WorldTracking.swift */; }; C3E575252BF1FFD9004E3EDC /* ImageTracking.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3E575242BF1FFD9004E3EDC /* ImageTracking.swift */; }; + C82B73A22C756EAD00D36A38 /* MeshResourceExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C82B73A12C756EAD00D36A38 /* MeshResourceExtension.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -34,6 +35,7 @@ C3E575202BF1C633004E3EDC /* SceneReconstruction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneReconstruction.swift; sourceTree = ""; }; C3E575222BF1D739004E3EDC /* WorldTracking.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WorldTracking.swift; sourceTree = ""; }; C3E575242BF1FFD9004E3EDC /* ImageTracking.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageTracking.swift; sourceTree = ""; }; + C82B73A12C756EAD00D36A38 /* MeshResourceExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeshResourceExtension.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -76,6 +78,7 @@ C3E575202BF1C633004E3EDC /* SceneReconstruction.swift */, C3E5751C2BF11433004E3EDC /* HandTracking.swift */, C3E575222BF1D739004E3EDC /* WorldTracking.swift */, + C82B73A12C756EAD00D36A38 /* MeshResourceExtension.swift */, C3E575112BEF6563004E3EDC /* Assets.xcassets */, C3E575162BEF6563004E3EDC /* Info.plist */, C3E575132BEF6563004E3EDC /* Preview Content */, @@ -174,6 +177,7 @@ files = ( C3E575212BF1C633004E3EDC /* SceneReconstruction.swift in Sources */, C3E5750E2BEF6562004E3EDC /* ContentView.swift in Sources */, + C82B73A22C756EAD00D36A38 /* MeshResourceExtension.swift in Sources */, C3E5750C2BEF6562004E3EDC /* Chapter8App.swift in Sources */, C3E5751F2BF1145F004E3EDC /* ShootingLogic.swift in Sources */, C3E575252BF1FFD9004E3EDC /* ImageTracking.swift in Sources */, diff --git a/Chapter8/Chapter8/MeshResourceExtension.swift b/Chapter8/Chapter8/MeshResourceExtension.swift new file mode 100644 index 0000000..c0bb521 --- /dev/null +++ b/Chapter8/Chapter8/MeshResourceExtension.swift @@ -0,0 +1,51 @@ +// +// MeshResourceExtension.swift +// Chapter8 +// +// Created by 鷲尾友人 on 2024/07/06. +// + +import RealityKit +import ARKit + +// 下記サイトを参考に作成。 +// https://forums.developer.apple.com/forums/thread/749759 +// https://zenn.dev/shu223/articles/visionos_scenemesh +// https://github.com/XRealityZone/what-vision-os-can-do/blob/main/WhatVisionOSCanDo/Extension/GeometrySource.swift + +extension MeshResource.Contents { + init(geom: MeshAnchor.Geometry) { + self.init() + self.instances = [MeshResource.Instance(id: "main", model: "model")] + var part = MeshResource.Part(id: "part", materialIndex: 0) + part.positions = MeshBuffer(geom.vertices.asSIMD3(ofType: Float.self)) + part.normals = MeshBuffer(geom.normals.asSIMD3(ofType: Float.self)) + part.triangleIndices = + MeshBuffer(geom.faces.asArray(ofType: UInt32.self)) + self.models = [MeshResource.Model(id: "model", parts: [part])] + } +} + +extension GeometrySource { + func asArray(ofType: T.Type) -> [T] { + assert(MemoryLayout.stride == stride) + return (0 ..< self.count).map { + buffer.contents().advanced(by: offset + stride * Int($0)) + .assumingMemoryBound(to: T.self).pointee + } + } + + func asSIMD3(ofType: T.Type) -> [SIMD3] { + return asArray(ofType: (T, T, T).self).map { .init($0.0, $0.1, $0.2) } + } +} + +extension GeometryElement { + func asArray(ofType: T.Type) -> [T] { + assert(MemoryLayout.stride == bytesPerIndex) + return (0 ..< self.count * self.primitive.indexCount).map { + buffer.contents().advanced(by: bytesPerIndex * Int($0)) + .assumingMemoryBound(to: T.self).pointee + } + } +} diff --git a/Chapter8/Chapter8/SceneReconstruction.swift b/Chapter8/Chapter8/SceneReconstruction.swift index f6761a9..f42b201 100644 --- a/Chapter8/Chapter8/SceneReconstruction.swift +++ b/Chapter8/Chapter8/SceneReconstruction.swift @@ -33,11 +33,17 @@ class SceneReconstruction: ObservableObject { // 障害物用のメッシュを作成 guard let shape = try? await ShapeResource .generateStaticMesh(from: meshAnchor) else { continue } + guard let mesh = try? await MeshResource( + from: MeshResource.Contents(geom: meshAnchor.geometry) + ) else { continue } switch update.event { // 障害物が新規に追加された場合 case .added: - // 追加された物体から障害物 Entity を作成、物理演算機能を追加 - let entity = ModelEntity() + // 追加された物体から障害物 Entity を作成、隠面処理と物理演算機能を追加 + let entity = ModelEntity( + mesh: mesh, + materials: [OcclusionMaterial()] + ) entity.transform = Transform( matrix: meshAnchor.originFromAnchorTransform ) @@ -54,6 +60,7 @@ class SceneReconstruction: ObservableObject { case .updated: // 物体の id を取得して形状と位置を更新 guard let entity = meshEntities[meshAnchor.id] else { continue } + entity.model?.mesh = mesh entity.transform = Transform( matrix: meshAnchor.originFromAnchorTransform )