├── Examples
└── Photons
│ ├── Packages
│ └── RealityKitContent
│ │ ├── README.md
│ │ ├── Sources
│ │ └── RealityKitContent
│ │ │ ├── RealityKitContent.swift
│ │ │ └── RealityKitContent.rkassets
│ │ │ ├── Materials
│ │ │ └── GridMaterial.usda
│ │ │ └── Immersive.usda
│ │ ├── Package.realitycomposerpro
│ │ ├── PluginData
│ │ │ └── AF09ED6F-1707-48FD-8720-65B998362C09
│ │ │ │ └── ShaderGraphEditorPluginID
│ │ │ │ └── ShaderGraphEditorPluginID
│ │ ├── WorkspaceData
│ │ │ ├── Settings.rcprojectdata
│ │ │ ├── SceneMetadataList.json
│ │ │ └── lakiiinbor.rcuserdata
│ │ └── ProjectData
│ │ │ └── main.json
│ │ └── Package.swift
│ ├── Photons
│ ├── Assets.xcassets
│ │ ├── Contents.json
│ │ ├── AppIcon.solidimagestack
│ │ │ ├── Back.solidimagestacklayer
│ │ │ │ ├── Contents.json
│ │ │ │ └── Content.imageset
│ │ │ │ │ └── Contents.json
│ │ │ ├── Front.solidimagestacklayer
│ │ │ │ ├── Contents.json
│ │ │ │ └── Content.imageset
│ │ │ │ │ └── Contents.json
│ │ │ ├── Middle.solidimagestacklayer
│ │ │ │ ├── Contents.json
│ │ │ │ └── Content.imageset
│ │ │ │ │ └── Contents.json
│ │ │ └── Contents.json
│ │ └── hello_particles.imageset
│ │ │ ├── hello_particles.jpg
│ │ │ └── Contents.json
│ ├── ECS
│ │ ├── SettingsComponent.swift
│ │ ├── ParticlesUpdateSystem.swift
│ │ ├── SimulationSystem.swift
│ │ └── SceneUpdateSystem.swift
│ ├── Preview Content
│ │ └── Preview Assets.xcassets
│ │ │ └── Contents.json
│ ├── AppModel.swift
│ ├── Info.plist
│ ├── PhotonsApp.swift
│ ├── Scene
│ │ ├── SceneMeshAssembler.metal
│ │ ├── SceneCollision.metal
│ │ ├── SceneMeshBuilder.swift
│ │ ├── SceneMeshProvider.swift
│ │ ├── SceneMeshAssembler.swift
│ │ └── SceneCollisionEncoder.swift
│ ├── Particles
│ │ ├── ParticleMeshUpdater.metal
│ │ └── ParticleMeshBuilder.swift
│ ├── UI
│ │ ├── ToggleImmersiveSpaceButton.swift
│ │ ├── ContentView.swift
│ │ ├── ViewModel.swift
│ │ └── ImmersiveView.swift
│ ├── Utils.h
│ └── Simulation
│ │ ├── Simulation.metal
│ │ └── Simulation.swift
│ ├── Photons.xcodeproj
│ ├── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ └── IDEWorkspaceChecks.plist
│ ├── xcshareddata
│ │ └── xcschemes
│ │ │ └── TheSpatialPhoto.xcscheme
│ └── project.pbxproj
│ └── README.md
└── .gitignore
/Examples/Photons/Packages/RealityKitContent/README.md:
--------------------------------------------------------------------------------
1 | # RealityKitContent
2 |
3 | A description of this package.
--------------------------------------------------------------------------------
/Examples/Photons/Photons/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Examples/Photons/Photons/ECS/SettingsComponent.swift:
--------------------------------------------------------------------------------
1 | import RealityKit
2 |
3 | struct SettingsComponent: Component {
4 | let settings: Settings
5 | }
6 |
--------------------------------------------------------------------------------
/Examples/Photons/Photons/Preview Content/Preview Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Examples/Photons/Photons/Assets.xcassets/AppIcon.solidimagestack/Back.solidimagestacklayer/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Examples/Photons/Photons/Assets.xcassets/AppIcon.solidimagestack/Front.solidimagestacklayer/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Examples/Photons/Photons/Assets.xcassets/AppIcon.solidimagestack/Middle.solidimagestacklayer/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Examples/Photons/Packages/RealityKitContent/Sources/RealityKitContent/RealityKitContent.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | /// Bundle for the RealityKitContent project
4 | public let realityKitContentBundle = Bundle.module
5 |
--------------------------------------------------------------------------------
/Examples/Photons/Photons/Assets.xcassets/hello_particles.imageset/hello_particles.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/computer-graphics-tools/examples/HEAD/Examples/Photons/Photons/Assets.xcassets/hello_particles.imageset/hello_particles.jpg
--------------------------------------------------------------------------------
/Examples/Photons/Photons.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Examples/Photons/Packages/RealityKitContent/Package.realitycomposerpro/PluginData/AF09ED6F-1707-48FD-8720-65B998362C09/ShaderGraphEditorPluginID/ShaderGraphEditorPluginID:
--------------------------------------------------------------------------------
1 | {
2 | "materialPreviewEnvironmentType" : 2,
3 | "materialPreviewObjectType" : 0
4 | }
--------------------------------------------------------------------------------
/Examples/Photons/Photons/Assets.xcassets/AppIcon.solidimagestack/Back.solidimagestacklayer/Content.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "vision",
5 | "scale" : "2x"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Examples/Photons/Photons/Assets.xcassets/AppIcon.solidimagestack/Front.solidimagestacklayer/Content.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "vision",
5 | "scale" : "2x"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Examples/Photons/Photons/Assets.xcassets/AppIcon.solidimagestack/Middle.solidimagestacklayer/Content.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "vision",
5 | "scale" : "2x"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Examples/Photons/Photons.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Examples/Photons/Packages/RealityKitContent/Package.realitycomposerpro/WorkspaceData/Settings.rcprojectdata:
--------------------------------------------------------------------------------
1 | {
2 | "cameraPresets" : {
3 |
4 | },
5 | "secondaryToolbarData" : {
6 | "isGridVisible" : true
7 | },
8 | "unitDefaults" : {
9 | "kg" : "g",
10 | "kg⋅m²" : "kg⋅m²",
11 | "m" : "cm",
12 | "m\/s" : "m\/s",
13 | "m\/s²" : "m\/s²",
14 | "s" : "s",
15 | "°" : "°"
16 | }
17 | }
--------------------------------------------------------------------------------
/Examples/Photons/Photons/Assets.xcassets/AppIcon.solidimagestack/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | },
6 | "layers" : [
7 | {
8 | "filename" : "Front.solidimagestacklayer"
9 | },
10 | {
11 | "filename" : "Middle.solidimagestacklayer"
12 | },
13 | {
14 | "filename" : "Back.solidimagestacklayer"
15 | }
16 | ]
17 | }
18 |
--------------------------------------------------------------------------------
/Examples/Photons/Photons/Assets.xcassets/hello_particles.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "hello_particles.jpg",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Examples/Photons/Photons/AppModel.swift:
--------------------------------------------------------------------------------
1 | import SwiftUI
2 |
3 | /// Maintains app-wide state
4 | @MainActor
5 | @Observable
6 | class AppModel {
7 | let immersiveSpaceID = "ImmersiveSpace"
8 | enum ImmersiveSpaceState {
9 | case closed
10 | case inTransition
11 | case open
12 | }
13 | var immersiveSpaceState = ImmersiveSpaceState.closed
14 | }
15 |
16 | let device = MTLCreateSystemDefaultDevice()!
17 | let commandQueue = device.makeCommandQueue()!
18 |
--------------------------------------------------------------------------------
/Examples/Photons/Photons/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | NSHandsTrackingUsageDescription
6 | For fun
7 | NSWorldSensingUsageDescription
8 | "collision"
9 | UIApplicationSceneManifest
10 |
11 | UIApplicationPreferredDefaultSceneSessionRole
12 | UIWindowSceneSessionRoleApplication
13 | UIApplicationSupportsMultipleScenes
14 |
15 | UISceneConfigurations
16 |
17 | UISceneSessionRoleImmersiveSpaceApplication
18 |
19 |
20 | UISceneInitialImmersionStyle
21 | UIImmersionStyleMixed
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/Examples/Photons/Photons/PhotonsApp.swift:
--------------------------------------------------------------------------------
1 | import SwiftUI
2 |
3 | @main
4 | struct PhotonsApp: App {
5 | @State private var appModel = AppModel()
6 | @State private var viewModel = ViewModel()
7 |
8 | var body: some Scene {
9 | WindowGroup {
10 | ContentView()
11 | .environment(appModel)
12 | .environmentObject(viewModel)
13 | }
14 | .defaultSize(width: 600, height: 400)
15 |
16 | ImmersiveSpace(id: appModel.immersiveSpaceID) {
17 | ImmersiveView()
18 | .environment(appModel)
19 | .onAppear {
20 | appModel.immersiveSpaceState = .open
21 | }
22 | .onDisappear {
23 | appModel.immersiveSpaceState = .closed
24 | }
25 | }
26 | .immersionStyle(selection: .constant(.mixed), in: .mixed)
27 | .environmentObject(viewModel)
28 |
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/Examples/Photons/Packages/RealityKitContent/Package.realitycomposerpro/ProjectData/main.json:
--------------------------------------------------------------------------------
1 | {
2 | "pathsToIds" : {
3 | "\/RealityKitContent\/Sources\/RealityKitContent\/RealityKitContent.rkassets\/GridMaterial.usda" : "CB766F92-EE55-4A63-9401-E7B8C009764D",
4 | "\/RealityKitContent\/Sources\/RealityKitContent\/RealityKitContent.rkassets\/Immersive.usda" : "65F6F990-A780-4474-B78B-572E0E4E273D",
5 | "\/RealityKitContent\/Sources\/RealityKitContent\/RealityKitContent.rkassets\/Scene.usda" : "0A9B4653-B11E-4D6A-850E-C6FCB621626C",
6 | "\/RealityKitContent\/Sources\/RealityKitContent\/RealityKitContent.rkassets\/Untitled Scene.usda" : "D560BB77-AAF3-4BDE-B7C4-989332A4688B",
7 | "RealityKitContent\/Sources\/RealityKitContent\/RealityKitContent.rkassets\/GridMaterial.usda" : "66168B71-AB05-424E-8B6C-D33D6E61B08F",
8 | "RealityKitContent\/Sources\/RealityKitContent\/RealityKitContent.rkassets\/Immersive.usda" : "AF09ED6F-1707-48FD-8720-65B998362C09",
9 | "RealityKitContent\/Sources\/RealityKitContent\/RealityKitContent.rkassets\/Scene.usda" : "D66134B1-3681-4A8E-AFE5-29F257229F3B"
10 | }
11 | }
--------------------------------------------------------------------------------
/Examples/Photons/Packages/RealityKitContent/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version:5.9
2 | // The swift-tools-version declares the minimum version of Swift required to build this package.
3 |
4 | import PackageDescription
5 |
6 | let package = Package(
7 | name: "RealityKitContent",
8 | platforms: [
9 | .visionOS(.v1),
10 | .macOS(.v14),
11 | .iOS(.v17)
12 | ],
13 | products: [
14 | // Products define the executables and libraries a package produces, and make them visible to other packages.
15 | .library(
16 | name: "RealityKitContent",
17 | targets: ["RealityKitContent"]),
18 | ],
19 | dependencies: [
20 | // Dependencies declare other packages that this package depends on.
21 | // .package(url: /* package url */, from: "1.0.0"),
22 | ],
23 | targets: [
24 | // Targets are the basic building blocks of a package. A target can define a module or a test suite.
25 | // Targets can depend on other targets in this package, and on products in packages this package depends on.
26 | .target(
27 | name: "RealityKitContent",
28 | dependencies: []),
29 | ]
30 | )
31 |
--------------------------------------------------------------------------------
/Examples/Photons/README.md:
--------------------------------------------------------------------------------
1 | # Photons Project
2 |
3 | ## Overview
4 |
5 | Photons is an example project showcasing the use of particle simulation, scene reconstruction, collision handling, and tracking techniques for hands and head. This project demonstrates how to integrate RealityKit, Metal, and ARKit to create an interactive expirience with particle physics, powered by simulation-tools and metal-tools packages.
6 |
7 | ## Features
8 |
9 | - **Particle Simulation:** Implements particle simulation using Metal compute shaders.
10 | - **Scene Reconstruction:** Utilizes ARKit for real-time scene reconstruction, allowing the app to understand and interact with the physical environment.
11 | - **Collision Handling:** Uses spatial hashing and collision detection to manage interactions between particles and the environment.
12 | - **Hand and Head Tracking:** Employs ARKit to track the user's hands and head.
13 |
14 |
15 | ## Getting Started
16 |
17 | ### Prerequisites
18 |
19 | - Xcode 16 or later
20 | - visionOS 2.0 or later
21 |
22 | ### Usage
23 |
24 | 1. Launch the app on your device.
25 | 2. Use the "Reset" button to reset the particle simulation.
26 | 3. Tap the import icon to select an image from your photo library.
27 | 4. Toggle between immersive and standard modes using the immersive space button.
28 | 5. Interact with the particles using your hands and observe real-time scene reconstruction and collision handling.
29 |
--------------------------------------------------------------------------------
/Examples/Photons/Photons/ECS/ParticlesUpdateSystem.swift:
--------------------------------------------------------------------------------
1 | import RealityKit
2 | import Metal
3 |
4 | struct ParticlesUpdateComponent: Component {
5 | var particleMeshBuilder: ParticleMeshBuilder
6 | }
7 |
8 | struct ParticlesUpdateSystem: System {
9 | static let query = EntityQuery(where: .has(ParticlesUpdateComponent.self) && .has(SimulationComponent.self))
10 |
11 | init(scene: RealityKit.Scene) {
12 | ParticlesUpdateComponent.registerComponent()
13 | }
14 |
15 | func update(context: SceneUpdateContext) {
16 | for entity in context.entities(matching: Self.query, updatingSystemWhen: .rendering) {
17 | guard let meshComponent = entity.components[ParticlesUpdateComponent.self],
18 | let simulationComponent = entity.components[SimulationComponent.self],
19 | let commandBuffer = commandQueue.makeCommandBuffer()
20 | else { continue }
21 |
22 |
23 | if let simulator = simulationComponent.simulator {
24 | meshComponent.particleMeshBuilder.replaceMeshBuffer(
25 | poisitionsBuffer: simulator.positions.buffer,
26 | vertexNeighbors: simulator.selfCollisionCandidates.buffer,
27 | commandBuffer: commandBuffer
28 | )
29 |
30 | commandBuffer.commit()
31 | }
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/Examples/Photons/Photons/Scene/SceneMeshAssembler.metal:
--------------------------------------------------------------------------------
1 | #include
2 | using namespace metal;
3 |
4 | kernel void assembleScenePositions(device packed_float3* outputVertices [[buffer(0)]],
5 | device const packed_float3* inputVertices [[buffer(1)]],
6 | constant uint& positionsCount [[buffer(2)]],
7 | constant uint& offset [[buffer(3)]],
8 | constant float4x4& transform [[buffer(4)]],
9 | uint gid [[thread_position_in_grid]])
10 | {
11 | if (gid >= positionsCount) { return; }
12 | float3 position = inputVertices[gid];
13 | float4 transformedVertex = transform * float4(position, 1.0);
14 | outputVertices[gid + offset] = transformedVertex.xyz;
15 | }
16 |
17 | kernel void assembleSceneIndices(device uint* outputIndices [[buffer(0)]],
18 | device const uint* inputIndices [[buffer(1)]],
19 | constant uint& indicesCount [[buffer(2)]],
20 | constant uint& offset [[buffer(3)]],
21 | constant uint& vertexOffset [[buffer(4)]],
22 | constant float4x4& transform [[buffer(5)]],
23 | uint gid [[thread_position_in_grid]])
24 | {
25 | if (gid >= indicesCount) { return; }
26 | uint inputIndex = inputIndices[gid];
27 | outputIndices[gid + offset] = inputIndex + vertexOffset;
28 | }
29 |
--------------------------------------------------------------------------------
/Examples/Photons/Photons/ECS/SimulationSystem.swift:
--------------------------------------------------------------------------------
1 | import RealityKit
2 |
3 | struct SimulationComponent: Component {
4 | weak var simulator: Simulation?
5 | }
6 |
7 | struct SimulationSystem: System {
8 | static let query = EntityQuery(where: .has(SimulationComponent.self))
9 |
10 | init(scene: RealityKit.Scene) {
11 | SimulationComponent.registerComponent()
12 | }
13 |
14 | func update(context: SceneUpdateContext) {
15 | for entity in context.entities(matching: Self.query, updatingSystemWhen: .rendering) {
16 | guard
17 | let simulationComponent = entity.components[SimulationComponent.self],
18 | let leftPalm = context.scene.findEntity(named: "LeftPalm") as? AnchorEntity,
19 | let rightPalm = context.scene.findEntity(named: "RightPalm") as? AnchorEntity,
20 | let head = context.scene.findEntity(named: "Head") as? AnchorEntity,
21 | let commandBuffer = commandQueue.makeCommandBuffer()
22 | else { continue }
23 |
24 | simulationComponent.simulator?.update(
25 | leftHandPosition: leftPalm.position(relativeTo: nil),
26 | rightHandPosition: rightPalm.position(relativeTo: nil),
27 | headPosition: head.position(relativeTo: nil),
28 | commandBuffer: commandBuffer,
29 | dt: context.deltaTime
30 | )
31 |
32 | commandBuffer.commit()
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/Examples/Photons/Photons/Particles/ParticleMeshUpdater.metal:
--------------------------------------------------------------------------------
1 | #include
2 | using namespace metal;
3 |
4 | struct ParticleVertex {
5 | half4 position;
6 | float2 uv;
7 | float2 uv2;
8 | };
9 |
10 | kernel void updateVertexBuffer(
11 | device ParticleVertex *vertices [[buffer(0)]],
12 | const device float4 *positions [[buffer(1)]],
13 | constant uint &positionsCount [[ buffer(2) ]],
14 | const device float2 *uvs [[buffer(3)]],
15 | constant float &ratio [[ buffer(4) ]],
16 | constant float &particleSize [[ buffer(5) ]],
17 | uint id [[ thread_position_in_grid ]]
18 | ) {
19 |
20 | if (id >= positionsCount) { return; }
21 | uint particleIndex = id / 4;
22 | uint vertexInParticleIndex = id % 4;
23 |
24 | float4 particlePosition = positions[particleIndex];
25 | float halfSize = particleSize * -0.5;
26 |
27 | float3 newPosition = particlePosition.xyz;
28 |
29 | float2 particleUV = uvs[particleIndex];
30 | float2 uv[4] = {
31 | particleUV + float2(-halfSize * ratio, -halfSize),
32 | particleUV + float2(halfSize * ratio, -halfSize),
33 | particleUV + float2(-halfSize * ratio, halfSize),
34 | particleUV + float2(halfSize * ratio, halfSize)
35 | };
36 |
37 | const float2 uv2[4] = {
38 | float2(0.0, 0.0), float2(1.0, 0.0), float2(0.0, 1.0), float2(1.0, 1.0)
39 | };
40 |
41 | vertices[id].position = half4(half3(newPosition), 1.0);
42 |
43 | vertices[id].uv = uv[vertexInParticleIndex % 4];
44 | vertices[id].uv2 = uv2[vertexInParticleIndex % 4];
45 |
46 | }
47 |
--------------------------------------------------------------------------------
/Examples/Photons/Photons/UI/ToggleImmersiveSpaceButton.swift:
--------------------------------------------------------------------------------
1 |
2 | import SwiftUI
3 |
4 | struct ToggleImmersiveSpaceButton: View {
5 | @Environment(AppModel.self) private var appModel
6 |
7 | @Environment(\.dismissImmersiveSpace) private var dismissImmersiveSpace
8 | @Environment(\.openImmersiveSpace) private var openImmersiveSpace
9 |
10 | var body: some View {
11 | Button {
12 | Task { @MainActor in
13 | switch appModel.immersiveSpaceState {
14 | case .open:
15 | appModel.immersiveSpaceState = .inTransition
16 | await dismissImmersiveSpace()
17 |
18 | case .closed:
19 | appModel.immersiveSpaceState = .inTransition
20 | switch await openImmersiveSpace(id: appModel.immersiveSpaceID) {
21 | case .opened:
22 | break
23 |
24 | case .userCancelled, .error:
25 | fallthrough
26 | @unknown default:
27 | appModel.immersiveSpaceState = .closed
28 | }
29 |
30 | case .inTransition:
31 | break
32 | }
33 | }
34 | } label: {
35 | Image(systemName: appModel.immersiveSpaceState == .open ? "rectangle.portrait.fill" : "rectangle.portrait")
36 | }
37 | .disabled(appModel.immersiveSpaceState == .inTransition)
38 | .animation(.none, value: 0)
39 | .fontWeight(.semibold)
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/Examples/Photons/Photons/ECS/SceneUpdateSystem.swift:
--------------------------------------------------------------------------------
1 | import RealityKit
2 | import SwiftUI
3 |
4 | struct SceneMeshProviderComponent: Component {
5 | var meshBuilder: SceneMeshBuilder
6 | }
7 |
8 | #if !targetEnvironment(simulator)
9 | struct SceneUpdateSystem: System {
10 | static let query = EntityQuery(
11 | where: .has(SceneMeshProviderComponent.self) && .has(SettingsComponent.self)
12 | )
13 |
14 | init(scene: RealityKit.Scene) {
15 | SceneMeshProviderComponent.registerComponent()
16 | }
17 |
18 | func update(context: SceneUpdateContext) {
19 | for entity in context.entities(matching: Self.query, updatingSystemWhen: .rendering) {
20 | guard let providerComponent = entity.components[SceneMeshProviderComponent.self],
21 | let settingsComponent = entity.components[SettingsComponent.self]
22 | else {
23 | continue
24 | }
25 |
26 | if let entity = entity.findEntity(named: "SceneDebugEntity") {
27 | entity.components.set(OpacityComponent(opacity: settingsComponent.settings.showWireframe ? 1.0 : 0.0))
28 | }
29 |
30 | if providerComponent.meshBuilder.needsMeshUpdate, let resource = try? providerComponent.meshBuilder.createMeshResource() {
31 | updateSceneMeshEntities(entity: entity, meshResource: resource)
32 | }
33 |
34 | entity.components[SceneMeshProviderComponent.self] = providerComponent
35 | }
36 | }
37 |
38 | private func updateSceneMeshEntities(entity: Entity, meshResource: MeshResource) {
39 | let occlusionMaterial = OcclusionMaterial()
40 | var lineMaterial = SimpleMaterial()
41 | lineMaterial.triangleFillMode = .lines
42 |
43 | for i in 0..<2 {
44 | let entityName = i == 0 ? "SceneEntity" : "SceneDebugEntity"
45 | let material: RealityKit.Material = i == 0 ? occlusionMaterial : lineMaterial
46 |
47 | if let existingEntity = entity.findEntity(named: entityName) {
48 | existingEntity.components.set(ModelComponent(mesh: meshResource, materials: [material]))
49 | } else {
50 | let newEntity = ModelEntity(mesh: meshResource, materials: [material])
51 | newEntity.name = entityName
52 | entity.addChild(newEntity)
53 | }
54 | }
55 | }
56 | }
57 | #endif
58 |
--------------------------------------------------------------------------------
/Examples/Photons/Photons/Utils.h:
--------------------------------------------------------------------------------
1 | #ifndef Utils_h
2 | #define Utils_h
3 |
4 | #include
5 | using namespace metal;
6 |
7 | METAL_FUNC float3 closestPointTriangle(float3 p0, float3 p1, float3 p2, float3 p, thread float3& uvw) {
8 | float b0 = 1.0 / 3.0;
9 | float b1 = b0;
10 | float b2 = b0;
11 |
12 | float3 d1 = p1 - p0;
13 | float3 d2 = p2 - p0;
14 | float3 pp0 = p - p0;
15 | float a = length_squared(d1);
16 | float b = dot(d2, d1);
17 | float c = dot(pp0, d1);
18 | float d = b;
19 | float e = length_squared(d2);
20 | float f = dot(pp0, d2);
21 | float det = a * e - b * d;
22 |
23 | if (det != 0.0) {
24 | float s = (c * e - b * f) / det;
25 | float t = (a * f - c * d) / det;
26 | b0 = 1.0 - s - t; // inside triangle
27 | b1 = s;
28 | b2 = t;
29 | if (b0 < 0.0) { // on edge 1-2
30 | float3 d = p2 - p1;
31 | float d2 = length_squared(d);
32 | float t = (d2 == 0.0) ? 0.5 : dot(d, p - p1) / d2;
33 | t = saturate(t);
34 |
35 | b0 = 0.0;
36 | b1 = (1.0 - t);
37 | b2 = t;
38 | }
39 | else if (b1 < 0.0) { // on edge 2-0
40 | float3 d = p0 - p2;
41 | float d2 = length_squared(d);
42 | float t = (d2 == 0.0) ? 0.5 : dot(d, p - p2) / d2;
43 | t = saturate(t);
44 |
45 | b1 = 0.0;
46 | b2 = (1.0 - t);
47 | b0 = t;
48 | }
49 | else if (b2 < 0.0) { // on edge 0-1
50 | float3 d = p1 - p0;
51 | float d2 = length_squared(d);
52 | float t = (d2 == 0.0) ? 0.5 : dot(d, (p - p0)) / d2;
53 | t = saturate(t);
54 |
55 | b2 = 0.0;
56 | b0 = (1.0 - t);
57 | b1 = t;
58 | }
59 | }
60 |
61 | uvw = float3(b0, b1, b2);
62 |
63 | return b0 * p0 + b1 * p1 + b2 * p2;
64 | }
65 |
66 | METAL_FUNC float3 computeFriction(float3 norm, float error, float3 relVelocity, float frictionCoeff) {
67 | float3 friction = float3(0);
68 | if (frictionCoeff > 0 && error > 0) {
69 | float3 tanVelocity = relVelocity - norm * dot(relVelocity, norm);
70 | float tanLength = length(tanVelocity);
71 | float maxTanLength = error * frictionCoeff;
72 | friction = -tanVelocity * min(maxTanLength / tanLength, 1.0);
73 | }
74 |
75 | return friction;
76 | }
77 |
78 | #endif /* Utils_h */
79 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | #
3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
4 |
5 | ## User settings
6 | xcuserdata/
7 |
8 | ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9)
9 | *.xcscmblueprint
10 | *.xccheckout
11 |
12 | ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4)
13 | build/
14 | DerivedData/
15 | *.moved-aside
16 | *.pbxuser
17 | !default.pbxuser
18 | *.mode1v3
19 | !default.mode1v3
20 | *.mode2v3
21 | !default.mode2v3
22 | *.perspectivev3
23 | !default.perspectivev3
24 |
25 | ## Obj-C/Swift specific
26 | *.hmap
27 |
28 | ## App packaging
29 | *.ipa
30 | *.dSYM.zip
31 | *.dSYM
32 |
33 | ## Playgrounds
34 | timeline.xctimeline
35 | playground.xcworkspace
36 |
37 | # Swift Package Manager
38 | #
39 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
40 | # Packages/
41 | # Package.pins
42 | # Package.resolved
43 | # *.xcodeproj
44 | #
45 | # Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata
46 | # hence it is not needed unless you have added a package configuration file to your project
47 | # .swiftpm
48 |
49 | .build/
50 |
51 | # CocoaPods
52 | #
53 | # We recommend against adding the Pods directory to your .gitignore. However
54 | # you should judge for yourself, the pros and cons are mentioned at:
55 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
56 | #
57 | # Pods/
58 | #
59 | # Add this line if you want to avoid checking in source code from the Xcode workspace
60 | # *.xcworkspace
61 |
62 | # Carthage
63 | #
64 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
65 | # Carthage/Checkouts
66 |
67 | Carthage/Build/
68 |
69 | # Accio dependency management
70 | Dependencies/
71 | .accio/
72 |
73 | # fastlane
74 | #
75 | # It is recommended to not store the screenshots in the git repo.
76 | # Instead, use fastlane to re-generate the screenshots whenever they are needed.
77 | # For more information about the recommended setup visit:
78 | # https://docs.fastlane.tools/best-practices/source-control/#source-control
79 |
80 | fastlane/report.xml
81 | fastlane/Preview.html
82 | fastlane/screenshots/**/*.png
83 | fastlane/test_output
84 |
85 | # Code Injection
86 | #
87 | # After new code Injection tools there's a generated folder /iOSInjectionProject
88 | # https://github.com/johnno1962/injectionforxcode
89 |
90 | iOSInjectionProject/
91 | .swiftpm
92 | *.DS_Store
93 | Package.resolved
94 | *.swiftformat
95 |
--------------------------------------------------------------------------------
/Examples/Photons/Photons/Scene/SceneCollision.metal:
--------------------------------------------------------------------------------
1 | #include "../Utils.h"
2 |
3 | kernel void handleVertexTriangleCollision(
4 | device float4 *positions [[ buffer(0) ]],
5 | constant float4 *prevPositions [[ buffer(1) ]],
6 | constant uint *collisionCandidates [[ buffer(2) ]],
7 | constant packed_float3 *wordPositions [[ buffer(3) ]],
8 | constant packed_uint3* sceneTriangles [[buffer(4) ]],
9 | constant float &frictionCoeff [[ buffer(5) ]],
10 | constant uint& maxCollisionCandidatesCount [[ buffer(6) ]],
11 | constant uint &gridSize [[ buffer(7) ]],
12 | uint gid [[ thread_position_in_grid ]]
13 | ) {
14 | if (gid >= gridSize) { return; }
15 | uint vertexIndex = gid;
16 |
17 | float3 position = positions[vertexIndex].xyz;
18 | float3 prevPosition = prevPositions[vertexIndex].xyz;
19 | float3 velocity = position - prevPosition;
20 |
21 | const float proximity = 0.025;
22 | float3 totalCorrection = 0.0;
23 |
24 | for (uint i = 0; i < maxCollisionCandidatesCount; i++) {
25 | uint triangleIndex = collisionCandidates[gid * maxCollisionCandidatesCount + i];
26 | if (triangleIndex == UINT_MAX) { continue; }
27 | uint3 triangleVertices = sceneTriangles[triangleIndex].xyz;
28 |
29 |
30 | float3 uvw;
31 | float3 closestPoint = closestPointTriangle(
32 | wordPositions[triangleVertices.x].xyz,
33 | wordPositions[triangleVertices.y].xyz,
34 | wordPositions[triangleVertices.z].xyz,
35 | position,
36 | uvw
37 | );
38 |
39 | float3 pointToVertex = position - closestPoint;
40 | float distance = length(pointToVertex);
41 | if (!isnormal(distance)) { continue; }
42 | float3 direction = pointToVertex / distance;
43 | float error = distance - proximity;
44 |
45 | if (error < 0) {
46 | float3 triangleNormal = cross(wordPositions[triangleVertices.y].xyz - wordPositions[triangleVertices.x].xyz, wordPositions[triangleVertices.z].xyz - wordPositions[triangleVertices.x].xyz);
47 | float3 triangleVelocity = 0;
48 | float3 relativeVelocity = velocity - triangleVelocity;
49 | float normalProjection = dot(triangleNormal, direction);
50 | float3 correction = error * direction;
51 | if (normalProjection < 0.0) { continue; }
52 |
53 | correction *= sign(normalProjection);
54 |
55 | const float relaxation = 1.0;
56 | float3 friction = computeFriction(direction, -error, relativeVelocity, frictionCoeff);
57 | totalCorrection += -correction * relaxation + friction;
58 | break;
59 | }
60 | }
61 |
62 | float3 newPosition = position + totalCorrection;
63 | positions[vertexIndex].xyz = newPosition;
64 | }
65 |
--------------------------------------------------------------------------------
/Examples/Photons/Photons/Scene/SceneMeshBuilder.swift:
--------------------------------------------------------------------------------
1 | import RealityKit
2 |
3 | struct SimpleVertex {
4 | var position: (Float, Float, Float) = (0, 0, 0)
5 | }
6 |
7 | extension SimpleVertex {
8 | static var vertexAttributes: [LowLevelMesh.Attribute] = [
9 | .init(semantic: .position, format: .float3, offset: 0),
10 | ]
11 |
12 | static var vertexLayouts: [LowLevelMesh.Layout] = [
13 | .init(bufferIndex: 0, bufferStride: MemoryLayout.stride)
14 | ]
15 |
16 | static var descriptor: LowLevelMesh.Descriptor {
17 | var descriptor = LowLevelMesh.Descriptor()
18 | descriptor.vertexAttributes = SimpleVertex.vertexAttributes
19 | descriptor.vertexLayouts = SimpleVertex.vertexLayouts
20 | descriptor.indexType = .uint32
21 |
22 | return descriptor
23 | }
24 | }
25 |
26 | final class SceneMeshBuilder {
27 | enum Error: Swift.Error {
28 | case missingGeometry
29 | case bufferCreationFailed
30 | }
31 |
32 | private(set) var needsMeshUpdate = false
33 | private(set) var geometry: SimpleGeometry?
34 | private var lowLevelMesh: LowLevelMesh?
35 |
36 | func updateGeometry(geometry: SimpleGeometry) {
37 | self.geometry = geometry
38 | needsMeshUpdate = true
39 | }
40 |
41 | @MainActor func createMeshResource() throws -> MeshResource {
42 | let lowLevelMesh = try buildMesh()
43 | let resource = try MeshResource(from: lowLevelMesh)
44 | self.lowLevelMesh = lowLevelMesh
45 | needsMeshUpdate = false
46 |
47 | return resource
48 | }
49 |
50 | @MainActor func buildMesh() throws -> LowLevelMesh {
51 | guard let geometry else { throw Error.missingGeometry }
52 | var desc = SimpleVertex.descriptor
53 | desc.vertexCapacity = geometry.positionsCount
54 | desc.indexCapacity = geometry.trianglesCount * 3
55 |
56 | let lowMesh = try LowLevelMesh(descriptor: desc)
57 | guard let commandBuffer = commandQueue.makeCommandBuffer() else { throw Error.bufferCreationFailed }
58 |
59 | let positionsBuffer = lowMesh.replace(bufferIndex: 0, using: commandBuffer)
60 | let indicesBuffer = lowMesh.replaceIndices(using: commandBuffer)
61 | commandBuffer.blit { encoder in
62 | encoder.copy(from: geometry.positions, sourceOffset: 0, to: positionsBuffer, destinationOffset: 0, size: geometry.positions.length)
63 | encoder.copy(from: geometry.triangles, sourceOffset: 0, to: indicesBuffer, destinationOffset: 0, size: geometry.triangles.length)
64 | }
65 | commandBuffer.commit()
66 | let meshBounds = BoundingBox(min: [-100, -100, -100], max: [100, 100, 100])
67 | lowMesh.parts.replaceAll([
68 | LowLevelMesh.Part(
69 | indexCount: geometry.trianglesCount * 3,
70 | topology: .triangle,
71 | bounds: meshBounds
72 | )
73 | ])
74 |
75 | return lowMesh
76 | }
77 | }
78 |
79 |
--------------------------------------------------------------------------------
/Examples/Photons/Photons.xcodeproj/xcshareddata/xcschemes/TheSpatialPhoto.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
9 |
10 |
16 |
22 |
23 |
24 |
25 |
26 |
32 |
33 |
44 |
46 |
52 |
53 |
54 |
55 |
61 |
63 |
69 |
70 |
71 |
72 |
74 |
75 |
78 |
79 |
80 |
--------------------------------------------------------------------------------
/Examples/Photons/Photons/UI/ContentView.swift:
--------------------------------------------------------------------------------
1 | import SwiftUI
2 | import _PhotosUI_SwiftUI
3 | import RealityKit
4 | import RealityKitContent
5 |
6 | struct ContentView: View {
7 | @EnvironmentObject private var viewModel: ViewModel
8 | @State private var selectedItem: PhotosPickerItem?
9 |
10 | var body: some View {
11 | VStack {
12 | ZStack {
13 | VStack {
14 | HStack {
15 | Spacer()
16 | Button {
17 | viewModel.reset()
18 | } label: {
19 | Text("Reset")
20 | }
21 | .padding()
22 | }
23 | Spacer()
24 | }
25 | VStack {
26 | Spacer()
27 | HStack {
28 | PhotosPicker(selection: $selectedItem, matching: .images, photoLibrary: .shared()) {
29 | Image(systemName: "plus.rectangle")
30 | }
31 | .onChange(of: selectedItem) { _, _ in
32 | Task {
33 | if let data = try? await selectedItem?.loadTransferable(type: Data.self),
34 | let image = UIImage(data: data) {
35 | viewModel.setSelectedImage(image)
36 | }
37 | }
38 | }
39 | .frame(width: 72)
40 | ToggleImmersiveSpaceButton()
41 | .frame(width: 72)
42 | Toggle(isOn: $viewModel.settings.showWireframe) {
43 | Image(systemName: "squareshape.split.3x3")
44 | }
45 | .toggleStyle(.button)
46 | .frame(width: 72)
47 | }
48 | Spacer()
49 | }.padding(.horizontal, 128)
50 | }
51 | }
52 | .padding()
53 | }
54 | }
55 |
56 | #Preview(windowStyle: .automatic) {
57 | ContentView()
58 | .environment(AppModel())
59 | .environmentObject(ViewModel())
60 | }
61 |
62 | struct ProfileImage: Transferable {
63 | let image: Image
64 |
65 | static var transferRepresentation: some TransferRepresentation {
66 | DataRepresentation(importedContentType: .image) { data in
67 | #if canImport(AppKit)
68 | guard let nsImage = NSImage(data: data) else {
69 | throw TransferError.importFailed
70 | }
71 | let image = Image(nsImage: nsImage)
72 | return ProfileImage(image: image)
73 | #elseif canImport(UIKit)
74 | guard let uiImage = UIImage(data: data) else {
75 | throw NSError(domain: "failed to load", code: 293583)
76 | }
77 | let image = Image(uiImage: uiImage)
78 | return ProfileImage(image: image)
79 | #else
80 | throw TransferError.importFailed
81 | #endif
82 | }
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/Examples/Photons/Packages/RealityKitContent/Package.realitycomposerpro/WorkspaceData/SceneMetadataList.json:
--------------------------------------------------------------------------------
1 | {
2 | "0A9B4653-B11E-4D6A-850E-C6FCB621626C" : {
3 | "objectMetadataList" : [
4 | [
5 | "0A9B4653-B11E-4D6A-850E-C6FCB621626C",
6 | "Root"
7 | ],
8 | {
9 | "isExpanded" : true,
10 | "isLocked" : false
11 | }
12 | ]
13 | },
14 | "65F6F990-A780-4474-B78B-572E0E4E273D" : {
15 | "objectMetadataList" : [
16 | [
17 | "65F6F990-A780-4474-B78B-572E0E4E273D",
18 | "Root"
19 | ],
20 | {
21 | "isExpanded" : true,
22 | "isLocked" : false
23 | }
24 | ]
25 | },
26 | "66168B71-AB05-424E-8B6C-D33D6E61B08F" : {
27 | "objectMetadataList" : [
28 | [
29 | "66168B71-AB05-424E-8B6C-D33D6E61B08F",
30 | "Root"
31 | ],
32 | {
33 | "isExpanded" : true,
34 | "isLocked" : false
35 | }
36 | ]
37 | },
38 | "AF09ED6F-1707-48FD-8720-65B998362C09" : {
39 | "objectMetadataList" : [
40 | [
41 | "AF09ED6F-1707-48FD-8720-65B998362C09",
42 | "Root",
43 | "BillboardMaterial",
44 | "ParticleSpacePosition"
45 | ],
46 | {
47 | "isExpanded" : true,
48 | "isLocked" : false
49 | },
50 | [
51 | "AF09ED6F-1707-48FD-8720-65B998362C09",
52 | "Root",
53 | "Sphere",
54 | "DefaultMaterial"
55 | ],
56 | {
57 | "isExpanded" : true,
58 | "isLocked" : false
59 | },
60 | [
61 | "AF09ED6F-1707-48FD-8720-65B998362C09",
62 | "Root",
63 | "BillboardMaterial"
64 | ],
65 | {
66 | "isExpanded" : true,
67 | "isLocked" : false
68 | },
69 | [
70 | "AF09ED6F-1707-48FD-8720-65B998362C09",
71 | "Root",
72 | "BillboardMaterial",
73 | "ViewFrameTest"
74 | ],
75 | {
76 | "isExpanded" : true,
77 | "isLocked" : false
78 | },
79 | [
80 | "AF09ED6F-1707-48FD-8720-65B998362C09",
81 | "Root"
82 | ],
83 | {
84 | "isExpanded" : true,
85 | "isLocked" : false
86 | },
87 | [
88 | "AF09ED6F-1707-48FD-8720-65B998362C09",
89 | "Root",
90 | "BillboardMaterial",
91 | "SimpleMath"
92 | ],
93 | {
94 | "isExpanded" : true,
95 | "isLocked" : false
96 | },
97 | [
98 | "AF09ED6F-1707-48FD-8720-65B998362C09",
99 | "Root",
100 | "BillboardMaterial",
101 | "ViewFrame"
102 | ],
103 | {
104 | "isExpanded" : true,
105 | "isLocked" : false
106 | }
107 | ]
108 | },
109 | "CB766F92-EE55-4A63-9401-E7B8C009764D" : {
110 | "objectMetadataList" : [
111 | [
112 | "CB766F92-EE55-4A63-9401-E7B8C009764D",
113 | "Root",
114 | "GridMaterial"
115 | ],
116 | {
117 | "isExpanded" : true,
118 | "isLocked" : false
119 | },
120 | [
121 | "CB766F92-EE55-4A63-9401-E7B8C009764D",
122 | "Root"
123 | ],
124 | {
125 | "isExpanded" : true,
126 | "isLocked" : false
127 | }
128 | ]
129 | },
130 | "D560BB77-AAF3-4BDE-B7C4-989332A4688B" : {
131 | "objectMetadataList" : [
132 |
133 | ]
134 | },
135 | "D66134B1-3681-4A8E-AFE5-29F257229F3B" : {
136 | "objectMetadataList" : [
137 | [
138 | "D66134B1-3681-4A8E-AFE5-29F257229F3B",
139 | "Root",
140 | "GridMaterial",
141 | "GridMaterial"
142 | ],
143 | {
144 | "isExpanded" : true,
145 | "isLocked" : false
146 | },
147 | [
148 | "D66134B1-3681-4A8E-AFE5-29F257229F3B",
149 | "Root"
150 | ],
151 | {
152 | "isExpanded" : true,
153 | "isLocked" : false
154 | }
155 | ]
156 | }
157 | }
--------------------------------------------------------------------------------
/Examples/Photons/Photons/Scene/SceneMeshProvider.swift:
--------------------------------------------------------------------------------
1 | import Metal
2 | import ARKit
3 | import RealityKit
4 |
5 | public struct SimpleGeometry {
6 | let positions: MTLBuffer
7 | let triangles: MTLBuffer
8 | let positionsCount: Int
9 | let trianglesCount: Int
10 |
11 | init(positions: MTLBuffer, triangles: MTLBuffer, positionsCount: Int, trianglesCount: Int) {
12 | self.positions = positions
13 | self.triangles = triangles
14 | self.positionsCount = positionsCount
15 | self.trianglesCount = trianglesCount
16 | }
17 | }
18 |
19 | struct AnchorGeometry {
20 | let vertices: GeometrySource
21 | let faces: GeometryElement
22 | var transform: simd_float4x4
23 | let vertexCount: Int
24 | let faceCount: Int
25 | }
26 |
27 | final class SceneMeshProvider {
28 | private let session = ARKitSession()
29 | private let sceneReconstruction = SceneReconstructionProvider()
30 | private var anchorGeometries: [UUID: AnchorGeometry] = [:]
31 | private var cancellable: Task?
32 | private let assembler: MeshAssembler
33 |
34 | var onMeshUpdate: ((SimpleGeometry, AnchorUpdate.Event) -> Void)?
35 | var started: Bool = false
36 |
37 | init(device: MTLDevice) throws {
38 | assembler = try MeshAssembler(device: device)
39 | #if !targetEnvironment(simulator)
40 | setupARSession()
41 | #endif
42 | }
43 |
44 | func forceUpdate() {
45 | #if !targetEnvironment(simulator)
46 | guard started else { return }
47 | guard !sceneReconstruction.allAnchors.isEmpty else { return }
48 | sceneReconstruction.allAnchors.forEach { achor in
49 | updateAnchorGeometry(achor)
50 | }
51 |
52 | assembler.assembleMeshes(from: anchorGeometries) { [weak self] collider in
53 | self?.onMeshUpdate?(collider, .added)
54 | }
55 | #endif
56 | }
57 |
58 | private func setupARSession() {
59 | Task {
60 | do {
61 | try await session.run([sceneReconstruction])
62 | subscribeToContinuousUpdates()
63 | started = true
64 | } catch {
65 | print("Failed to run session: \(error)")
66 | }
67 | }
68 | }
69 |
70 | private func subscribeToContinuousUpdates() {
71 | cancellable = Task {
72 | for await update in sceneReconstruction.anchorUpdates {
73 | await handleAnchorUpdate(update)
74 | }
75 | }
76 | }
77 |
78 | private func handleAnchorUpdate(_ update: AnchorUpdateSequence.Iterator.Element) async {
79 | switch update.event {
80 | case .added:
81 | updateAnchorGeometry(update.anchor)
82 | case .updated:
83 | anchorGeometries[update.anchor.id]?.transform = update.anchor.originFromAnchorTransform
84 | case .removed:
85 | removeAnchorGeometry(update.anchor.id)
86 |
87 | }
88 |
89 | assembler.assembleMeshes(from: anchorGeometries) { [weak self] collider in
90 | guard let self else { return }
91 | self.onMeshUpdate?(collider, update.event)
92 | }
93 | }
94 |
95 | private func updateAnchorGeometry(_ anchor: MeshAnchor) {
96 | let geometry = anchor.geometry
97 | let transform = anchor.originFromAnchorTransform
98 |
99 | let anchorGeometry = AnchorGeometry(
100 | vertices: geometry.vertices,
101 | faces: geometry.faces,
102 | transform: transform,
103 | vertexCount: geometry.vertices.count,
104 | faceCount: geometry.faces.count
105 | )
106 |
107 | anchorGeometries[anchor.id] = anchorGeometry
108 | }
109 |
110 | private func removeAnchorGeometry(_ anchorID: UUID) {
111 | anchorGeometries.removeValue(forKey: anchorID)
112 | }
113 |
114 | deinit {
115 | cancellable?.cancel()
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/Examples/Photons/Photons/Scene/SceneMeshAssembler.swift:
--------------------------------------------------------------------------------
1 | import Metal
2 | import ARKit
3 |
4 | final class MeshAssembler {
5 | private let device: MTLDevice
6 | private let positionsPipelineState: MTLComputePipelineState
7 | private let indicesPipelineState: MTLComputePipelineState
8 |
9 | private var outputVertexBuffer: MTLBuffer?
10 | private var outputIndexBuffer: MTLBuffer?
11 |
12 | private(set) var totalVertexCount: Int = 0
13 | private(set) var totalIndexCount: Int = 0
14 |
15 | init(device: MTLDevice) throws {
16 | self.device = device
17 |
18 | let library = try device.makeDefaultLibrary(bundle: .main)
19 | positionsPipelineState = try library.computePipelineState(function: "assembleScenePositions")
20 | indicesPipelineState = try library.computePipelineState(function: "assembleSceneIndices")
21 | }
22 |
23 | func assembleMeshes(from geometries: [UUID: AnchorGeometry], completion: @escaping (SimpleGeometry) -> Void) {
24 | computeOutputBufferSizes(from: geometries)
25 | createOutputBufffers()
26 |
27 | guard let commandBuffer = commandQueue.makeCommandBuffer() else { return }
28 |
29 | var vertexOffset: Int = 0
30 | var indexOffset: Int = 0
31 |
32 | guard let computeEncoder = commandBuffer.makeComputeCommandEncoder(dispatchType: .concurrent) else { return }
33 | for geometry in geometries.values {
34 | encodePositionsKernel(computeEncoder: computeEncoder, geometry: geometry, vertexOffset: vertexOffset)
35 | encodeIndicesKernel(computeEncoder: computeEncoder, geometry: geometry, indexOffset: indexOffset, vertexOffset: UInt32(vertexOffset))
36 |
37 | vertexOffset += geometry.vertexCount
38 | indexOffset += geometry.faceCount * 3
39 | }
40 |
41 | computeEncoder.endEncoding()
42 |
43 | commandBuffer.addCompletedHandler { [weak self] _ in
44 | guard let self, let outputVertexBuffer, let outputIndexBuffer else { return }
45 | completion(
46 | .init(
47 | positions: outputVertexBuffer,
48 | triangles: outputIndexBuffer,
49 | positionsCount: self.totalVertexCount,
50 | trianglesCount: self.totalIndexCount / 3
51 | )
52 | )
53 | }
54 | commandBuffer.commit()
55 | }
56 |
57 | private func encodePositionsKernel(computeEncoder: MTLComputeCommandEncoder, geometry: AnchorGeometry, vertexOffset: Int) {
58 | computeEncoder.setBuffer(outputVertexBuffer, offset: 0, index: 0)
59 | computeEncoder.setBuffer(geometry.vertices.buffer, offset: 0, index: 1)
60 |
61 | computeEncoder.setValue(UInt32(geometry.vertexCount), at: 2)
62 | computeEncoder.setValue(UInt32(vertexOffset), at: 3)
63 | computeEncoder.setValue(geometry.transform, at: 4)
64 |
65 | computeEncoder.dispatch1d(state: positionsPipelineState, exactlyOrCovering: geometry.vertexCount)
66 | }
67 |
68 | private func encodeIndicesKernel(computeEncoder: MTLComputeCommandEncoder, geometry: AnchorGeometry, indexOffset: Int, vertexOffset: UInt32) {
69 | computeEncoder.setBuffer(outputIndexBuffer, offset: 0, index: 0)
70 | computeEncoder.setBuffer(geometry.faces.buffer, offset: 0, index: 1)
71 |
72 | computeEncoder.setValue(UInt32(geometry.faceCount * 3), at: 2)
73 | computeEncoder.setValue(UInt32(indexOffset), at: 3)
74 | computeEncoder.setValue(vertexOffset, at: 4)
75 | computeEncoder.setValue(geometry.transform, at: 5)
76 |
77 | computeEncoder.dispatch1d(state: indicesPipelineState, exactlyOrCovering: geometry.faceCount * 3)
78 | }
79 |
80 | private func computeOutputBufferSizes(from geometries: [UUID: AnchorGeometry]) {
81 | totalVertexCount = geometries.values.reduce(0) { $0 + $1.vertexCount }
82 | totalIndexCount = geometries.values.reduce(0) { $0 + $1.faceCount * 3 }
83 | }
84 |
85 | private func createOutputBufffers() {
86 | outputVertexBuffer = device.makeBuffer(length: MemoryLayout.size * 3 * totalVertexCount, options: [])
87 | outputIndexBuffer = device.makeBuffer(length: MemoryLayout.size * totalIndexCount, options: [])
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/Examples/Photons/Photons/UI/ViewModel.swift:
--------------------------------------------------------------------------------
1 | import SwiftUI
2 |
3 | final class ViewModel: ObservableObject {
4 | @Published var selectedImage: UIImage {
5 | didSet {
6 | let correctedImage = selectedImage.correctlyOrientedImage()
7 | let (particles, uvs) = Self.buildParticles(for: correctedImage)
8 | do {
9 | particleMeshBuilder = try .init(
10 | device: device,
11 | positions: particles,
12 | uvs: uvs,
13 | cellSize: SimulationConstants.cellSize,
14 | size: correctedImage.size
15 | )
16 | simulator = try Simulation(device: device, positions: particles)
17 | settings.startTime = CACurrentMediaTime()
18 | } catch {
19 | fatalError("initialization failed")
20 | }
21 | }
22 | }
23 |
24 | @Published var settings = Settings()
25 |
26 | var particleMeshBuilder: ParticleMeshBuilder
27 | var sceneMeshBuilder: SceneMeshBuilder
28 | var simulator: Simulation
29 | let sceneMeshProvider: SceneMeshProvider
30 |
31 | init() {
32 | sceneMeshBuilder = SceneMeshBuilder()
33 | let image = UIImage(named: "hello_particles")!
34 | selectedImage = image
35 | let correctedImage = image.correctlyOrientedImage()
36 | let (particles, uvs) = Self.buildParticles(for: correctedImage)
37 | do {
38 | sceneMeshProvider = try SceneMeshProvider(device: device)
39 | particleMeshBuilder = try ParticleMeshBuilder(
40 | device: device,
41 | positions: particles,
42 | uvs: uvs,
43 | cellSize: SimulationConstants.cellSize,
44 | size: image.size
45 | )
46 | simulator = try Simulation(device: device, positions: particles)
47 | } catch {
48 | fatalError("initialization failed")
49 | }
50 |
51 | settings.startTime = CACurrentMediaTime()
52 | sceneMeshProvider.onMeshUpdate = { geometry, event in
53 | DispatchQueue.main.async { [weak self] in
54 | self?.simulator.updateScene(sceneGeometry: geometry, event: event)
55 | Task {
56 | self?.sceneMeshBuilder.updateGeometry(geometry: geometry)
57 | }
58 | }
59 | }
60 | }
61 |
62 |
63 | func setSelectedImage(_ image: UIImage) {
64 | selectedImage = image
65 | }
66 |
67 | func reset() {
68 | sceneMeshProvider.forceUpdate()
69 | simulator.reset()
70 | settings.startTime = CACurrentMediaTime()
71 | objectWillChange.send()
72 | }
73 | }
74 |
75 | extension ViewModel {
76 | private static func buildParticles(for image: UIImage) -> ([SIMD4], [SIMD2]) {
77 | let fixedHeight = 40
78 | let aspectRatio = Float(image.size.width / image.size.height)
79 | let width = Int(ceil(Float(fixedHeight) * aspectRatio))
80 | let depth = 11
81 |
82 | let count = width * fixedHeight * depth
83 | var positions = [SIMD4](repeating: .zero, count: count)
84 | var uvs = [SIMD2](repeating: .zero, count: count)
85 |
86 | let boxSize: SIMD3 = [aspectRatio, 1.0, 1.0]
87 | let cellSizeX = 1.0 / Float(width)
88 | let cellSizeY = 1.0 / Float(fixedHeight)
89 |
90 | for x in 0..(xPos, yPos, zPos, 1)
102 | let uv = SIMD2(u + cellSizeX * 0.5, v + cellSizeY * 0.5)
103 |
104 | positions[index] = position
105 | uvs[index] = uv
106 | }
107 | }
108 | }
109 |
110 | return (positions, uvs)
111 | }
112 | }
113 |
114 | final class Settings: Observable {
115 | var showWireframe = false
116 | var startTime: TimeInterval = CACurrentMediaTime()
117 | }
118 |
119 | extension UIImage {
120 | func correctlyOrientedImage() -> UIImage {
121 | UIGraphicsBeginImageContextWithOptions(size, false, scale)
122 | draw(in: CGRect(origin: .zero, size: size))
123 | let normalizedImage = UIGraphicsGetImageFromCurrentImageContext()!
124 | UIGraphicsEndImageContext()
125 |
126 | return normalizedImage
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/Examples/Photons/Photons/Simulation/Simulation.metal:
--------------------------------------------------------------------------------
1 | #include "../Utils.h"
2 |
3 | kernel void predictPositions(
4 | device float3 *positions [[buffer(0)]],
5 | device float3 *prevPositions [[buffer(1)]],
6 | device float3 *predictedPositions [[buffer(2)]],
7 | constant float3 &gravity [[buffer(3)]],
8 | constant float &timeStep [[buffer(4)]],
9 | constant uint &positionsCount [[buffer(5)]],
10 | constant float3 &left [[buffer(6)]],
11 | constant float3 &right [[buffer(7)]],
12 | constant float3 &head [[buffer(8)]],
13 | uint id [[thread_position_in_grid]]
14 | ) {
15 | if (id >= positionsCount) { return; }
16 |
17 | float3 position = positions[id];
18 | float3 prevPosition = prevPositions[id];
19 | float3 velocity = position - prevPosition;
20 |
21 | const float3 attractor = mix(head, (left + right) / 2.0, 2.0);
22 | float3 toAttractor = attractor - position;
23 | float3 attractorForce = normalize(toAttractor) * smoothstep(0.2, 0.0, length(left - right)) * 12.0;
24 |
25 | const float damping = 0.98;
26 | velocity *= damping;
27 | velocity = min(max(velocity, -0.05), 0.05);
28 | velocity += attractorForce * timeStep * timeStep;
29 | float3 newPosition = position + velocity + gravity * timeStep * timeStep;
30 |
31 | prevPositions[id] = position;
32 | positions[id] = newPosition;
33 | predictedPositions[id] = newPosition;
34 | }
35 |
36 | kernel void solveConstraints(
37 | constant float3 &leftHandCollider [[buffer(0)]],
38 | constant float3 &rightHandCollider [[buffer(1)]],
39 | device uint *collisionCandidates [[buffer(2)]],
40 | device float3 *positions [[buffer(3)]],
41 | device float3 *prevPositions [[buffer(4)]],
42 | constant uint &collisionCandidatesCount [[buffer(5)]],
43 | constant float &particleRadius [[buffer(9)]],
44 | device float3 *targetPositions [[buffer(10)]],
45 | constant uint &positionsCount [[buffer(11)]],
46 | uint gid [[ thread_position_in_grid ]]
47 | ) {
48 | if (gid >= positionsCount) { return; }
49 | uint vertexIndex = gid;
50 |
51 | float3 position = positions[vertexIndex].xyz;
52 | float3 prevPosition = prevPositions[vertexIndex].xyz;
53 | float3 velocity = position - prevPosition;
54 | float3 totalCorrection = 0;
55 | float correctionCount = 0;
56 |
57 | if (position.y < 0) {
58 | float3 direction = float3(0, 1, 0);
59 | float lambda = -position.y;
60 | float3 friction = computeFriction(direction, lambda, velocity, 0.5);
61 |
62 | float3 correction = (lambda * direction + friction) * 0.5;
63 | totalCorrection += correction;
64 | correctionCount += 1.0;
65 | }
66 |
67 | float leftHandDistance = length(leftHandCollider - position);
68 | float rightHandDistance = length(rightHandCollider - position);
69 |
70 | if (leftHandDistance < 0.1) {
71 | float3 direction = normalize(leftHandCollider - position);
72 | float error = leftHandDistance - 0.1;
73 | float3 correction = (error * direction);
74 | totalCorrection += correction;
75 | correctionCount += 1.0;
76 | }
77 |
78 | if (rightHandDistance < 0.1) {
79 | float3 direction = normalize(rightHandDistance - position);
80 | float error = rightHandDistance - 0.1;
81 | float3 correction = (error * direction);
82 | totalCorrection += correction;
83 | correctionCount += 1.0;
84 | }
85 |
86 | for (int i = 0; i < int(collisionCandidatesCount); i++) {
87 | uint collisionVertexIndex = collisionCandidates[gid * collisionCandidatesCount + i];
88 | if (collisionVertexIndex != vertexIndex && collisionVertexIndex != UINT_MAX) {
89 | float3 neighborPosition = positions[collisionVertexIndex].xyz;
90 | float3 diff = position - neighborPosition;
91 | float diameter2 = particleRadius * 4;
92 | float distance = length_squared(diff);
93 | if (distance < pow(diameter2, 2.0)) {
94 | distance = sqrt(distance);
95 | float3 diff = position - neighborPosition;
96 | float diameter = particleRadius * 2;
97 | float error = distance - diameter;
98 |
99 | float3 prevNeighborPosition = prevPositions[collisionVertexIndex].xyz;
100 | float3 neighborVelocity = neighborPosition - prevNeighborPosition;
101 | if (!isnormal(distance)) { continue; }
102 | float3 direction = diff / distance;
103 | float3 friction = computeFriction(direction, -error, velocity - neighborVelocity, 0.5);
104 |
105 | float relaxation = error < 0 ? 0.125 : 0.0000001;
106 | float3 correction = (-error * direction + friction) * relaxation;
107 | totalCorrection += correction;
108 | correctionCount += 1.0;
109 | }
110 | }
111 | }
112 |
113 | targetPositions[vertexIndex].xyz = position + (totalCorrection / max(1.0, totalCorrection));
114 | }
115 |
116 |
--------------------------------------------------------------------------------
/Examples/Photons/Photons/UI/ImmersiveView.swift:
--------------------------------------------------------------------------------
1 | import SwiftUI
2 | import RealityKit
3 | import RealityKitContent
4 | import PhotosUI
5 |
6 | struct ImmersiveView: View {
7 | private enum Constants {
8 | static let textureParamterName = "texture"
9 | static let timeParameterName = "time"
10 | static let cellSizeParamaterName = "cellSize"
11 | }
12 |
13 | @Environment(AppModel.self) private var appModel
14 | @EnvironmentObject private var viewModel: ViewModel
15 | @State private var particlesEntity: Entity?
16 | private let session = SpatialTrackingSession()
17 |
18 | var body: some View {
19 | RealityView(make: { content in
20 | #if !targetEnvironment(simulator)
21 | _ = await session.run(.init(tracking: [.hand]))
22 | #endif
23 | let rootEntity = Entity()
24 | Task {
25 | var particleMaterial = try await ShaderGraphMaterial(named: "/Root/BillboardMaterial", from: "Immersive", in: realityKitContentBundle)
26 | try await configureParticleMaterial(material: &particleMaterial, startTime: CACurrentMediaTime())
27 | try updateParticlesModel(rootEntity: rootEntity, material: particleMaterial)
28 | }
29 |
30 | let leftPalm = AnchorEntity(.hand(.left, location: .palm))
31 | leftPalm.name = "LeftPalm"
32 | let rightPalm = AnchorEntity(.hand(.right, location: .palm))
33 | rightPalm.name = "RightPalm"
34 | let head = AnchorEntity(.head)
35 | head.name = "Head"
36 | rootEntity.addChild(leftPalm)
37 | rootEntity.addChild(rightPalm)
38 | rootEntity.addChild(head)
39 |
40 | #if !targetEnvironment(simulator)
41 | rootEntity.components[SceneMeshProviderComponent.self] = .init(meshBuilder: viewModel.sceneMeshBuilder)
42 | #endif
43 | rootEntity.components[SettingsComponent.self] = .init(settings: viewModel.settings)
44 |
45 | content.add(rootEntity)
46 |
47 | SimulationSystem.registerSystem()
48 | ParticlesUpdateSystem.registerSystem()
49 | #if !targetEnvironment(simulator)
50 | SceneUpdateSystem.registerSystem()
51 | #endif
52 | }, update: { content in
53 | let model = particlesEntity?.components[ModelComponent.self]
54 | particlesEntity?.components.set(OpacityComponent(opacity: 0.0))
55 | Task {
56 | if var material = model?.materials.first as? ShaderGraphMaterial, var model {
57 | try? await self.configureParticleMaterial(material: &material, startTime: viewModel.settings.startTime)
58 | model.materials = [material]
59 | particlesEntity?.components[ModelComponent.self] = model
60 | particlesEntity?.components.set(OpacityComponent(opacity: 1.0))
61 |
62 | if let simulatorComponent = particlesEntity?.components[SimulationComponent.self] {
63 | if let rootEntity = particlesEntity?.parent, simulatorComponent.simulator == nil {
64 | try updateParticlesModel(rootEntity: rootEntity, material: material)
65 | }
66 | }
67 | }
68 | }
69 | })
70 | .onChange(of: appModel.immersiveSpaceState) { _, _ in
71 | self.viewModel.settings.startTime = CACurrentMediaTime()
72 | }
73 | }
74 |
75 | private func updateParticlesModel(rootEntity: Entity, material: RealityKit.Material) throws {
76 | let meshResource = try viewModel.particleMeshBuilder.createMeshResource()
77 | let particlesEntity = ModelEntity(mesh: meshResource, materials: [material])
78 | particlesEntity.components[SimulationComponent.self] = .init(simulator: viewModel.simulator)
79 | particlesEntity.components[ParticlesUpdateComponent.self] = .init(
80 | ParticlesUpdateComponent(particleMeshBuilder: viewModel.particleMeshBuilder)
81 | )
82 |
83 | self.particlesEntity?.removeFromParent()
84 | rootEntity.addChild(particlesEntity)
85 | self.particlesEntity = particlesEntity
86 | }
87 |
88 | private func configureParticleMaterial(material: inout ShaderGraphMaterial, startTime: TimeInterval) async throws {
89 | let correctedImage = viewModel.selectedImage.correctlyOrientedImage()
90 | let texResource = try await TextureResource(image: correctedImage.cgImage!, options: .init(semantic: .color))
91 | try? material.setParameter(name: Constants.timeParameterName, value: .float(Float(startTime)))
92 | try? material.setParameter(name: Constants.textureParamterName, value: .textureResource(texResource))
93 | try? material.setParameter(name: Constants.cellSizeParamaterName, value: .float(Float(SimulationConstants.cellSize)))
94 | }
95 | }
96 |
97 |
98 | #Preview(immersionStyle: .mixed) {
99 | ImmersiveView()
100 | .environment(AppModel())
101 | .environmentObject(ViewModel())
102 | }
103 |
--------------------------------------------------------------------------------
/Examples/Photons/Packages/RealityKitContent/Package.realitycomposerpro/WorkspaceData/lakiiinbor.rcuserdata:
--------------------------------------------------------------------------------
1 | {
2 | "advancedEditorSelectedIdentifier" : "ShaderGraphEditorPluginID",
3 | "openSceneRelativePaths" : [
4 | "Immersive.usda"
5 | ],
6 | "recentIdentifiers" : {
7 | "AF09ED6F-1707-48FD-8720-65B998362C09" : [
8 |
9 | ]
10 | },
11 | "sceneCameraHistory" : {
12 | "AF09ED6F-1707-48FD-8720-65B998362C09" : [
13 | {
14 | "date" : 743449497.199421,
15 | "title" : "Untitled",
16 | "transform" : [
17 | -0.30034718,
18 | -2.245644e-07,
19 | -0.9538299,
20 | 0,
21 | -0.6761133,
22 | 0.7053688,
23 | 0.21289818,
24 | 0,
25 | 0.6728017,
26 | 0.7088406,
27 | -0.21185574,
28 | 0,
29 | 1.9565905,
30 | 1.3026586,
31 | -0.6841501,
32 | 1
33 | ]
34 | },
35 | {
36 | "date" : 743449495.514256,
37 | "title" : "Untitled",
38 | "transform" : [
39 | -0.30034718,
40 | -2.245644e-07,
41 | -0.9538299,
42 | 0,
43 | -0.6761133,
44 | 0.7053688,
45 | 0.21289818,
46 | 0,
47 | 0.6728016,
48 | 0.70884055,
49 | -0.21185571,
50 | 0,
51 | 1.7989547,
52 | 1.1365789,
53 | -0.63451284,
54 | 1
55 | ]
56 | },
57 | {
58 | "date" : 743445650.000333,
59 | "title" : "Untitled",
60 | "transform" : [
61 | -0.36677638,
62 | -2.1992936e-07,
63 | -0.9303091,
64 | 0,
65 | -0.6901559,
66 | 0.6705586,
67 | 0.27209538,
68 | 0,
69 | 0.6238267,
70 | 0.7418567,
71 | -0.24594526,
72 | 0,
73 | 1.6970452,
74 | 1.2267116,
75 | -0.7388323,
76 | 1
77 | ]
78 | },
79 | {
80 | "date" : 743445635.835906,
81 | "title" : "Untitled",
82 | "transform" : [
83 | -0.392946,
84 | -2.415399e-07,
85 | -0.9195615,
86 | 0,
87 | -0.6775717,
88 | 0.67606485,
89 | 0.28953904,
90 | 0,
91 | 0.6216831,
92 | 0.73684216,
93 | -0.2656572,
94 | 0,
95 | 1.0855639,
96 | 0.78196156,
97 | -0.5093876,
98 | 1
99 | ]
100 | },
101 | {
102 | "date" : 743445576.354388,
103 | "title" : "Untitled",
104 | "transform" : [
105 | -0.48596212,
106 | -2.395339e-07,
107 | -0.87398,
108 | 0,
109 | -0.56089497,
110 | 0.7668963,
111 | 0.31187624,
112 | 0,
113 | 0.6702518,
114 | 0.6417711,
115 | -0.37268272,
116 | 0,
117 | 1.1076587,
118 | 0.617968,
119 | -0.6637743,
120 | 1
121 | ]
122 | },
123 | {
124 | "date" : 743444484.940188,
125 | "title" : "Untitled",
126 | "transform" : [
127 | -0.7830175,
128 | -2.4674938e-07,
129 | -0.62199974,
130 | 0,
131 | -0.42037454,
132 | 0.7370452,
133 | 0.52919716,
134 | 0,
135 | 0.45844176,
136 | 0.6758435,
137 | -0.5771194,
138 | 0,
139 | 1.2745374,
140 | 1.1456946,
141 | -1.718534,
142 | 1
143 | ]
144 | },
145 | {
146 | "date" : 743444328.867092,
147 | "title" : "Untitled",
148 | "transform" : [
149 | -0.7830175,
150 | -2.252324e-07,
151 | -0.6219997,
152 | 0,
153 | -0.42037445,
154 | 0.7370451,
155 | 0.5291972,
156 | 0,
157 | 0.4584418,
158 | 0.67584366,
159 | -0.5771191,
160 | 0,
161 | 1.160296,
162 | 1.7760057,
163 | -1.1034439,
164 | 1
165 | ]
166 | },
167 | {
168 | "date" : 743444216.781989,
169 | "title" : "Untitled",
170 | "transform" : [
171 | -0.76026016,
172 | -2.2520796e-07,
173 | -0.6496186,
174 | 0,
175 | -0.29235822,
176 | 0.8930055,
177 | 0.34215185,
178 | 0,
179 | 0.5801132,
180 | 0.45004594,
181 | -0.6789164,
182 | 0,
183 | 1.4738626,
184 | 1.2780889,
185 | -1.3828553,
186 | 1
187 | ]
188 | },
189 | {
190 | "date" : 743441632.580276,
191 | "title" : "Untitled",
192 | "transform" : [
193 | -0.5130864,
194 | -2.1608403e-07,
195 | -0.8583369,
196 | 0,
197 | -0.6266195,
198 | 0.68340546,
199 | 0.3745731,
200 | 0,
201 | 0.58659214,
202 | 0.7300392,
203 | -0.3506459,
204 | 0,
205 | 1.0549824,
206 | 1.4728544,
207 | -0.42908505,
208 | 1
209 | ]
210 | },
211 | {
212 | "date" : 743401170.161768,
213 | "title" : "Untitled",
214 | "transform" : [
215 | -0.51308644,
216 | -2.1608406e-07,
217 | -0.85833704,
218 | 0,
219 | -0.6266195,
220 | 0.68340546,
221 | 0.3745731,
222 | 0,
223 | 0.58659214,
224 | 0.7300392,
225 | -0.3506459,
226 | 0,
227 | 1.0387927,
228 | 1.8636781,
229 | -0.48001266,
230 | 1
231 | ]
232 | }
233 | ]
234 | },
235 | "selectedSceneRelativePath" : "Immersive.usda"
236 | }
--------------------------------------------------------------------------------
/Examples/Photons/Photons/Particles/ParticleMeshBuilder.swift:
--------------------------------------------------------------------------------
1 | import RealityKit
2 | import Metal
3 |
4 | struct ParticleVertex {
5 | var position: SIMD4 = .zero
6 | var uv: SIMD2 = .zero
7 | var uv2: SIMD2 = .zero
8 |
9 | }
10 |
11 | extension ParticleVertex {
12 | static var vertexAttributes: [LowLevelMesh.Attribute] = [
13 | .init(semantic: .position, format: .half4, offset: MemoryLayout.offset(of: \.position)!),
14 | .init(semantic: .uv0, format: .float2, offset: MemoryLayout.offset(of: \.uv)!),
15 | .init(semantic: .uv1, format: .float2, offset: MemoryLayout.offset(of: \.uv2)!),
16 | ]
17 |
18 | static var vertexLayouts: [LowLevelMesh.Layout] = [
19 | .init(bufferIndex: 0, bufferStride: MemoryLayout.stride)
20 | ]
21 |
22 | static var descriptor: LowLevelMesh.Descriptor {
23 | var desc = LowLevelMesh.Descriptor()
24 | desc.vertexAttributes = ParticleVertex.vertexAttributes
25 | desc.vertexLayouts = ParticleVertex.vertexLayouts
26 | desc.indexType = .uint32
27 | return desc
28 | }
29 | }
30 |
31 | final class ParticleMeshBuilder {
32 | private var pipelineState: MTLComputePipelineState
33 | private let device: MTLDevice
34 | private var lowLevelMesh: LowLevelMesh?
35 | private var particlePositions: [SIMD4]
36 | private var uvs: [SIMD2]
37 | private var size: CGSize
38 | private var cellSize: Float
39 | private(set) var uvBuffer: MTLBuffer
40 |
41 | init(
42 | device: MTLDevice,
43 | positions: [SIMD4],
44 | uvs: [SIMD2],
45 | cellSize: Float,
46 | size: CGSize
47 | ) throws {
48 | let library = try device.makeDefaultLibrary(bundle: .main)
49 | self.device = device
50 | self.particlePositions = positions
51 | self.uvs = uvs
52 | self.size = size
53 | self.cellSize = cellSize
54 | uvBuffer = try device.buffer(with: uvs)
55 | pipelineState = try library.computePipelineState(function: "updateVertexBuffer")
56 | }
57 |
58 | @MainActor func createMeshResource() throws -> MeshResource {
59 | let lowLevelMesh = try buildMesh()
60 | let resource = try MeshResource(from: lowLevelMesh)
61 | self.lowLevelMesh = lowLevelMesh
62 | return resource
63 | }
64 |
65 | @MainActor func replaceMeshBuffer(
66 | poisitionsBuffer: MTLBuffer,
67 | vertexNeighbors: MTLBuffer,
68 | commandBuffer: MTLCommandBuffer
69 | ) {
70 | guard let lowLevelMesh else { return }
71 | let vertexBuffer = lowLevelMesh.replace(bufferIndex: 0, using: commandBuffer)
72 | let positionsCount = lowLevelMesh.vertexCapacity
73 |
74 | commandBuffer.compute { encoder in
75 | encoder.setBuffer(vertexBuffer, offset: 0, index: 0)
76 | encoder.setBuffer(poisitionsBuffer, offset: 0, index: 1)
77 | encoder.setValue(UInt32(positionsCount), at: 2)
78 | encoder.setBuffer(uvBuffer, offset: 0, index: 3)
79 | encoder.setValue(Float(size.height / size.width), at: 4)
80 | encoder.setValue(cellSize, at: 5)
81 | encoder.dispatch1d(state: pipelineState, exactlyOrCovering: positionsCount)
82 | }
83 | }
84 |
85 | @MainActor private func buildMesh() throws -> LowLevelMesh {
86 | let halfSize = cellSize / 2
87 |
88 | var positions: [SIMD4] = []
89 | var indices: [UInt32] = []
90 |
91 | for particlePosition in particlePositions {
92 | let particlePos = SIMD3(particlePosition.x, particlePosition.y, particlePosition.z)
93 |
94 | let quadVertices: [SIMD4] = [
95 | SIMD4(particlePos.x - halfSize, particlePos.y - halfSize, particlePos.z - halfSize, 1.0),
96 | SIMD4(particlePos.x + halfSize, particlePos.y - halfSize, particlePos.z - halfSize, 1.0),
97 | SIMD4(particlePos.x - halfSize, particlePos.y + halfSize, particlePos.z - halfSize, 1.0),
98 | SIMD4(particlePos.x + halfSize, particlePos.y + halfSize, particlePos.z - halfSize, 1.0),
99 | ]
100 |
101 | positions.append(contentsOf: quadVertices)
102 | let baseIndex = UInt32(positions.count - 4)
103 | let quadIndices: [UInt32] = (0..<1).flatMap { face -> [UInt32] in
104 | let faceBaseIndex = baseIndex + UInt32(face * 4)
105 | return [
106 | faceBaseIndex, faceBaseIndex + 1, faceBaseIndex + 2,
107 | faceBaseIndex + 1, faceBaseIndex + 3, faceBaseIndex + 2
108 | ]
109 | }
110 | indices.append(contentsOf: quadIndices)
111 | }
112 |
113 | var desciptor = ParticleVertex.descriptor
114 | desciptor.vertexCapacity = positions.count
115 | desciptor.indexCapacity = indices.count
116 |
117 | let lowMesh = try LowLevelMesh(descriptor: desciptor)
118 | lowMesh.withUnsafeMutableIndices { rawIndices in
119 | let targetIndices = rawIndices.bindMemory(to: UInt32.self)
120 | for i in 0.. {
141 | .init(x: x, y: y, z: z)
142 | }
143 | }
144 |
--------------------------------------------------------------------------------
/Examples/Photons/Photons/Scene/SceneCollisionEncoder.swift:
--------------------------------------------------------------------------------
1 | import Metal
2 | import SimulationTools
3 |
4 | final class SceneCollisionEncoder {
5 | private let backgroundQueue: DispatchQueue = .init(label: "Mesh Processing")
6 | private var triangleNeigbhors: MTLTypedBuffer?
7 |
8 | private let handleSceneCollision: MTLComputePipelineState
9 | private var triangles: MTLTypedBuffer?
10 | private var scenePositions: MTLTypedBuffer?
11 | private var triangleSpatialHashing: TriangleSpatialHashing?
12 | private var initialized = false
13 |
14 | init(device: MTLDevice) throws {
15 | handleSceneCollision = try device.makeDefaultLibrary(bundle: .main).computePipelineState(function: "handleVertexTriangleCollision")
16 | }
17 |
18 | func update(collider: SimpleGeometry, updateTriangleNeigbhors: Bool) throws {
19 | let cellSize: Float = 0.05
20 | let configuration = TriangleSpatialHashing.Configuration(cellSize: cellSize)
21 | triangleSpatialHashing = try .init(
22 | heap: device.heap(
23 | size: TriangleSpatialHashing.totalBuffersSize(maxTrianglesCount: collider.trianglesCount, configuration: configuration),
24 | storageMode: .private
25 | ),
26 | configuration: configuration,
27 | maxTrianglesCount: collider.trianglesCount
28 | )
29 |
30 | triangles = device.typedBuffer(with: collider.triangles, valueType: .packedUInt3)
31 | scenePositions = device.typedBuffer(with: collider.positions, valueType: .packedFloat3)
32 |
33 | if updateTriangleNeigbhors {
34 | backgroundQueue.async { [weak self] in
35 | if let indices = collider.triangles.array(of: UInt32.self, count: collider.trianglesCount * 3) {
36 | let adjacentTriangles = findAdjacentTriangles(indices: indices)
37 | self?.triangleNeigbhors = try? device.typedBuffer(with: adjacentTriangles, valueType: .uint3)
38 | }
39 | }
40 | }
41 |
42 | initialized = false
43 | }
44 |
45 | func build(
46 | commandBuffer: MTLCommandBuffer,
47 | positions: MTLTypedBuffer,
48 | collisionCandidates: MTLTypedBuffer,
49 | vertexNeighbors: MTLTypedBuffer
50 | ) {
51 | guard let triangles = triangles, let scenePositions = scenePositions, let triangleSpatialHashing else { return }
52 |
53 | if !initialized {
54 | triangleSpatialHashing.build(
55 | colliderPositions: scenePositions,
56 | indices: triangles,
57 | in: commandBuffer
58 | )
59 | }
60 |
61 | triangleSpatialHashing.find(
62 | collidablePositions: positions,
63 | colliderPositions: scenePositions,
64 | indices: triangles,
65 | collisionCandidates: collisionCandidates,
66 | in: commandBuffer
67 | )
68 |
69 | initialized = true
70 | }
71 |
72 | func reuse(
73 | commandBuffer: MTLCommandBuffer,
74 | positions: MTLTypedBuffer,
75 | collisionCandidates: MTLTypedBuffer,
76 | vertexNeighbors: MTLTypedBuffer
77 | ) {
78 | guard let triangles = triangles, let scenePositions = scenePositions, let triangleSpatialHashing else { return }
79 |
80 | triangleSpatialHashing.reuse(
81 | collidablePositions: positions,
82 | colliderPositions: scenePositions,
83 | indices: triangles,
84 | collisionCandidates: collisionCandidates,
85 | vertexNeighbors: vertexNeighbors,
86 | trinagleNeighbors: triangleNeigbhors,
87 | in: commandBuffer
88 | )
89 | }
90 |
91 | func encode(
92 | commandBuffer: MTLCommandBuffer,
93 | positions: MTLTypedBuffer,
94 | prevPositions: MTLTypedBuffer,
95 | collisionCandidates: MTLTypedBuffer,
96 | frictionCoefficent: Float
97 | ) {
98 | guard let triangles = triangles, let scenePositions = scenePositions else { return }
99 |
100 | commandBuffer.compute { encoder in
101 | encoder.setBuffer(positions.buffer, offset: 0, index: 0)
102 | encoder.setBuffer(prevPositions.buffer, offset: 0, index: 1)
103 | encoder.setBuffer(collisionCandidates.buffer, offset: 0, index: 2)
104 | encoder.setBuffer(scenePositions.buffer, offset: 0, index: 3)
105 | encoder.setBuffer(triangles.buffer, offset: 0, index: 4)
106 | encoder.setValue(frictionCoefficent, at: 5)
107 | encoder.setValue(UInt32(collisionCandidates.descriptor.count / positions.descriptor.count), at: 6)
108 | encoder.setValue(UInt32(positions.descriptor.count), at: 7)
109 |
110 | encoder.dispatch1d(state: handleSceneCollision, exactlyOrCovering: positions.descriptor.count)
111 | }
112 | }
113 | }
114 |
115 |
116 | private func findAdjacentTriangles(indices: [UInt32]) -> [SIMD3] {
117 | let triangleCount = indices.count / 3
118 | var edgeToTriangle = [Set: Set]()
119 |
120 | for i in 0..()].insert(UInt32(i))
133 | }
134 | }
135 |
136 | var result = [SIMD3]()
137 | for i in 0.. = [0, -9.8, 0]
8 | static let particleRadius: Float = 0.025 / 2
9 | static var cellSize: Float { particleRadius * 2.0 }
10 | static let maxCollisionCandidates = 8
11 | static let solverIterations = 1
12 | }
13 |
14 | class Simulation {
15 | let device: MTLDevice
16 |
17 | private let predictPositionsPipelineState: MTLComputePipelineState
18 | private let solveConstraintsPipelineState: MTLComputePipelineState
19 |
20 | private let spatialHashing: SpatialHashing
21 | private let sceneCollisionEngine: SceneCollisionEncoder
22 |
23 | let positions: MTLTypedBuffer
24 | let selfCollisionCandidates: MTLTypedBuffer
25 | private let originalPositions: MTLTypedBuffer
26 | private let prevPositions: MTLTypedBuffer
27 | private let predictedPositions: MTLTypedBuffer
28 | private let collisionCandidates: MTLTypedBuffer
29 |
30 | private var time: Float = 0
31 | private var frame: Int = 0
32 |
33 | init(device: MTLDevice, positions: [SIMD4]) throws {
34 | self.device = device
35 |
36 | self.positions = try device.typedBuffer(with: positions, valueType: .float4)
37 | originalPositions = try device.typedBuffer(with: positions, valueType: .float4)
38 | prevPositions = try device.typedBuffer(with: positions, valueType: .float4)
39 | predictedPositions = try device.typedBuffer(with: positions, valueType: .float4)
40 | selfCollisionCandidates = try device.typedBuffer(descriptor: .init(valueType: .uint, count: positions.count * SimulationConstants.maxCollisionCandidates))
41 | collisionCandidates = try device.typedBuffer(descriptor: .init(valueType: .uint,count: positions.count * SimulationConstants.maxCollisionCandidates))
42 |
43 | let library = try device.makeDefaultLibrary(bundle: .main)
44 | predictPositionsPipelineState = try library.computePipelineState(function: "predictPositions")
45 | solveConstraintsPipelineState = try library.computePipelineState(function: "solveConstraints")
46 |
47 | let config = SpatialHashing.Configuration(cellSize: SimulationConstants.cellSize, radius: SimulationConstants.particleRadius)
48 | sceneCollisionEngine = try SceneCollisionEncoder(device: device)
49 | spatialHashing = try SpatialHashing(
50 | heap: device.heap(size: SpatialHashing.totalBuffersSize(maxPositionsCount: positions.count), storageMode: .private),
51 | configuration: config,
52 | maxPositionsCount: positions.count
53 | )
54 | }
55 |
56 | func updateScene(sceneGeometry: SimpleGeometry, event: AnchorUpdate.Event) {
57 | try? sceneCollisionEngine.update(
58 | collider: sceneGeometry,
59 | updateTriangleNeigbhors: event != .updated
60 | )
61 | }
62 |
63 | func reset() {
64 | time = 0
65 | frame = 0
66 | }
67 |
68 | func update(
69 | leftHandPosition: SIMD3,
70 | rightHandPosition: SIMD3,
71 | headPosition: SIMD3,
72 | commandBuffer: MTLCommandBuffer,
73 | dt: TimeInterval
74 | ) {
75 |
76 | if frame == 0 && time == 0 {
77 | commandBuffer.blit { encoder in
78 | encoder.copy(from: originalPositions.buffer, sourceOffset: 0, to: positions.buffer, destinationOffset: 0, size: positions.buffer.length)
79 | encoder.copy(from: originalPositions.buffer, sourceOffset: 0, to: prevPositions.buffer, destinationOffset: 0, size: positions.buffer.length)
80 | encoder.copy(from: originalPositions.buffer, sourceOffset: 0, to: predictedPositions.buffer, destinationOffset: 0, size: positions.buffer.length)
81 |
82 | }
83 | }
84 |
85 | frame += 1
86 | let dt = 1.0 / 90
87 | time += Float(dt)
88 | for _ in 0.. 120 {
90 | commandBuffer.compute { predictEncoder in
91 | predictEncoder.setBuffer(positions.buffer, offset: 0, index: 0)
92 | predictEncoder.setBuffer(prevPositions.buffer, offset: 0, index: 1)
93 | predictEncoder.setBuffer(predictedPositions.buffer, offset: 0, index: 2)
94 | predictEncoder.setValue(SIMD3(0, -10, 0.0), at: 3)
95 | predictEncoder.setValue(Float(dt), at: 4)
96 | predictEncoder.setValue(UInt32(positions.descriptor.count), at: 5)
97 | predictEncoder.setValue(leftHandPosition, at: 6)
98 | predictEncoder.setValue(rightHandPosition, at: 7)
99 | predictEncoder.setValue(headPosition, at: 8)
100 | predictEncoder.dispatch1d(state: predictPositionsPipelineState, exactlyOrCovering: positions.descriptor.count)
101 | }
102 | }
103 |
104 | spatialHashing.build(
105 | positions: predictedPositions,
106 | in: commandBuffer
107 | )
108 |
109 | spatialHashing.find(
110 | collidablePositions: nil,
111 | collisionCandidates: selfCollisionCandidates,
112 | connectedVertices: nil,
113 | in: commandBuffer
114 | )
115 |
116 | sceneCollisionEngine.build(
117 | commandBuffer: commandBuffer,
118 | positions: predictedPositions,
119 | collisionCandidates: collisionCandidates,
120 | vertexNeighbors: selfCollisionCandidates
121 | )
122 |
123 | sceneCollisionEngine.reuse(
124 | commandBuffer: commandBuffer,
125 | positions: predictedPositions,
126 | collisionCandidates: collisionCandidates,
127 | vertexNeighbors: selfCollisionCandidates
128 | )
129 |
130 | for j in 0..<3 {
131 | let source = j % 2 == 0 ? predictedPositions : positions
132 | let target = j % 2 == 0 ? positions : predictedPositions
133 |
134 | commandBuffer.compute { solveEncoder in
135 | solveEncoder.setValue(leftHandPosition, at: 0)
136 | solveEncoder.setValue(rightHandPosition, at: 1)
137 | solveEncoder.setBuffer(selfCollisionCandidates.buffer, offset: 0, index: 2)
138 | solveEncoder.setBuffer(source.buffer, offset: 0, index: 3)
139 | solveEncoder.setBuffer(prevPositions.buffer, offset: 0, index: 4)
140 | solveEncoder.setValue(SimulationConstants.maxCollisionCandidates, at: 5)
141 | solveEncoder.setValue(SimulationConstants.particleRadius, at: 9)
142 | solveEncoder.setBuffer(target.buffer, offset: 0, index: 10)
143 | solveEncoder.setValue(UInt32(positions.descriptor.count), at: 11)
144 |
145 | solveEncoder.dispatch1d(state: solveConstraintsPipelineState, exactlyOrCovering: positions.descriptor.count)
146 | }
147 |
148 | sceneCollisionEngine.encode(
149 | commandBuffer: commandBuffer,
150 | positions: target,
151 | prevPositions: prevPositions,
152 | collisionCandidates: collisionCandidates,
153 | frictionCoefficent: 0.5
154 | )
155 | }
156 | }
157 | }
158 | }
159 |
--------------------------------------------------------------------------------
/Examples/Photons/Packages/RealityKitContent/Sources/RealityKitContent/RealityKitContent.rkassets/Materials/GridMaterial.usda:
--------------------------------------------------------------------------------
1 | #usda 1.0
2 | (
3 | defaultPrim = "Root"
4 | metersPerUnit = 1
5 | upAxis = "Y"
6 | )
7 |
8 | def Xform "Root"
9 | {
10 | def Material "GridMaterial"
11 | {
12 | reorder nameChildren = ["", "", "", "", "", "", "", "", "", "", "", "", "", "", "DefaultSurfaceShader", "MaterialXPreviewSurface", "Texcoord", "Add", "Multiply", "Fractional", "LineCounts", "Multiply_1", "Separate2", "Separate2_1", "Ifgreater", "Ifgreater_1", "Max", "Background_Color"]
13 | token outputs:mtlx:surface.connect =
14 | token outputs:realitykit:vertex
15 | token outputs:surface
16 | float2 ui:nodegraph:realitykit:subgraphOutputs:pos = (2222, 300.5)
17 | float2 ui:nodegraph:realitykit:subgraphOutputs:size = (182, 89)
18 | int ui:nodegraph:realitykit:subgraphOutputs:stackingOrder = 749
19 |
20 | def Shader "DefaultSurfaceShader"
21 | {
22 | uniform token info:id = "UsdPreviewSurface"
23 | color3f inputs:diffuseColor = (1, 1, 1)
24 | float inputs:roughness = 0.75
25 | token outputs:surface
26 | }
27 |
28 | def Shader "MaterialXPreviewSurface"
29 | {
30 | uniform token info:id = "ND_UsdPreviewSurface_surfaceshader"
31 | float inputs:clearcoat
32 | float inputs:clearcoatRoughness
33 | color3f inputs:diffuseColor.connect =
34 | color3f inputs:emissiveColor
35 | float inputs:ior
36 | float inputs:metallic = 0.15
37 | float3 inputs:normal
38 | float inputs:occlusion
39 | float inputs:opacity
40 | float inputs:opacityThreshold
41 | float inputs:roughness = 0.5
42 | token outputs:out
43 | float2 ui:nodegraph:node:pos = (1967, 300.5)
44 | float2 ui:nodegraph:node:size = (208, 297)
45 | int ui:nodegraph:node:stackingOrder = 870
46 | string[] ui:nodegraph:realitykit:node:attributesShowingChildren = ["Advanced"]
47 | }
48 |
49 | def Shader "Texcoord"
50 | {
51 | uniform token info:id = "ND_texcoord_vector2"
52 | float2 outputs:out
53 | float2 ui:nodegraph:node:pos = (94.14453, 35.29297)
54 | float2 ui:nodegraph:node:size = (182, 43)
55 | int ui:nodegraph:node:stackingOrder = 1358
56 | }
57 |
58 | def Shader "Multiply"
59 | {
60 | uniform token info:id = "ND_multiply_vector2"
61 | float2 inputs:in1.connect =
62 | float2 inputs:in2 = (32, 15)
63 | float2 inputs:in2.connect =
64 | float2 outputs:out
65 | float2 ui:nodegraph:node:pos = (275.64453, 47.29297)
66 | float2 ui:nodegraph:node:size = (61, 36)
67 | int ui:nodegraph:node:stackingOrder = 1348
68 | string[] ui:nodegraph:realitykit:node:attributesShowingChildren = ["inputs:in2"]
69 | }
70 |
71 | def Shader "Fractional"
72 | {
73 | uniform token info:id = "ND_realitykit_fractional_vector2"
74 | float2 inputs:in.connect =
75 | float2 outputs:out
76 | float2 ui:nodegraph:node:pos = (440.5, 49.5)
77 | float2 ui:nodegraph:node:size = (155, 99)
78 | int ui:nodegraph:node:stackingOrder = 1345
79 | }
80 |
81 | def Shader "BaseColor"
82 | {
83 | uniform token info:id = "ND_constant_color3"
84 | color3f inputs:value = (0.89737034, 0.89737034, 0.89737034) (
85 | colorSpace = "Input - Texture - sRGB - sRGB"
86 | )
87 | color3f inputs:value.connect = None
88 | color3f outputs:out
89 | float2 ui:nodegraph:node:pos = (1537.5977, 363.07812)
90 | float2 ui:nodegraph:node:size = (150, 43)
91 | int ui:nodegraph:node:stackingOrder = 1353
92 | }
93 |
94 | def Shader "LineColor"
95 | {
96 | uniform token info:id = "ND_constant_color3"
97 | color3f inputs:value = (0.55945957, 0.55945957, 0.55945957) (
98 | colorSpace = "Input - Texture - sRGB - sRGB"
99 | )
100 | color3f inputs:value.connect = None
101 | color3f outputs:out
102 | float2 ui:nodegraph:node:pos = (1536.9844, 287.86328)
103 | float2 ui:nodegraph:node:size = (146, 43)
104 | int ui:nodegraph:node:stackingOrder = 1355
105 | }
106 |
107 | def Shader "LineWidths"
108 | {
109 | uniform token info:id = "ND_combine2_vector2"
110 | float inputs:in1 = 0.1
111 | float inputs:in2 = 0.1
112 | float2 outputs:out
113 | float2 ui:nodegraph:node:pos = (443.64453, 233.79297)
114 | float2 ui:nodegraph:node:size = (151, 43)
115 | int ui:nodegraph:node:stackingOrder = 1361
116 | }
117 |
118 | def Shader "LineCounts"
119 | {
120 | uniform token info:id = "ND_combine2_vector2"
121 | float inputs:in1 = 24
122 | float inputs:in2 = 12
123 | float2 outputs:out
124 | float2 ui:nodegraph:node:pos = (94.14453, 138.29297)
125 | float2 ui:nodegraph:node:size = (153, 43)
126 | int ui:nodegraph:node:stackingOrder = 1359
127 | }
128 |
129 | def Shader "Remap"
130 | {
131 | uniform token info:id = "ND_remap_color3"
132 | color3f inputs:in.connect =
133 | color3f inputs:inhigh.connect = None
134 | color3f inputs:inlow.connect = None
135 | color3f inputs:outhigh.connect =
136 | color3f inputs:outlow.connect =
137 | color3f outputs:out
138 | float2 ui:nodegraph:node:pos = (1755.5, 300.5)
139 | float2 ui:nodegraph:node:size = (95, 171)
140 | int ui:nodegraph:node:stackingOrder = 1282
141 | string[] ui:nodegraph:realitykit:node:attributesShowingChildren = ["inputs:outlow"]
142 | }
143 |
144 | def Shader "Separate2"
145 | {
146 | uniform token info:id = "ND_separate2_vector2"
147 | float2 inputs:in.connect =
148 | float outputs:outx
149 | float outputs:outy
150 | float2 ui:nodegraph:node:pos = (1212.6445, 128.91797)
151 | float2 ui:nodegraph:node:size = (116, 117)
152 | int ui:nodegraph:node:stackingOrder = 1363
153 | }
154 |
155 | def Shader "Combine3"
156 | {
157 | uniform token info:id = "ND_combine3_color3"
158 | float inputs:in1.connect =
159 | float inputs:in2.connect =
160 | float inputs:in3.connect =
161 | color3f outputs:out
162 | float2 ui:nodegraph:node:pos = (1578.1445, 128.91797)
163 | float2 ui:nodegraph:node:size = (146, 54)
164 | int ui:nodegraph:node:stackingOrder = 1348
165 | }
166 |
167 | def Shader "Range"
168 | {
169 | uniform token info:id = "ND_range_vector2"
170 | bool inputs:doclamp = 1
171 | float2 inputs:gamma = (2, 2)
172 | float2 inputs:in.connect =
173 | float2 inputs:inhigh.connect =
174 | float2 inputs:inlow = (0.02, 0.02)
175 | float2 inputs:outhigh
176 | float2 inputs:outlow
177 | float2 outputs:out
178 | float2 ui:nodegraph:node:pos = (990.64453, 128.91797)
179 | float2 ui:nodegraph:node:size = (98, 207)
180 | int ui:nodegraph:node:stackingOrder = 1364
181 | }
182 |
183 | def Shader "Subtract"
184 | {
185 | uniform token info:id = "ND_subtract_vector2"
186 | float2 inputs:in1.connect =
187 | float2 inputs:in2.connect =
188 | float2 outputs:out
189 | float2 ui:nodegraph:node:pos = (612.64453, 87.04297)
190 | float2 ui:nodegraph:node:size = (63, 36)
191 | int ui:nodegraph:node:stackingOrder = 1348
192 | }
193 |
194 | def Shader "Absval"
195 | {
196 | uniform token info:id = "ND_absval_vector2"
197 | float2 inputs:in.connect =
198 | float2 outputs:out
199 | float2 ui:nodegraph:node:pos = (765.64453, 87.04297)
200 | float2 ui:nodegraph:node:size = (123, 43)
201 | int ui:nodegraph:node:stackingOrder = 1348
202 | }
203 |
204 | def Shader "Min"
205 | {
206 | uniform token info:id = "ND_min_float"
207 | float inputs:in1.connect =
208 | float inputs:in2.connect =
209 | float outputs:out
210 | float2 ui:nodegraph:node:pos = (1388.1445, 128.91797)
211 | float2 ui:nodegraph:node:size = (114, 36)
212 | int ui:nodegraph:node:stackingOrder = 1363
213 | }
214 | }
215 | }
216 |
217 |
--------------------------------------------------------------------------------
/Examples/Photons/Packages/RealityKitContent/Sources/RealityKitContent/RealityKitContent.rkassets/Immersive.usda:
--------------------------------------------------------------------------------
1 | #usda 1.0
2 | (
3 | defaultPrim = "Root"
4 | metersPerUnit = 1
5 | upAxis = "Y"
6 | )
7 |
8 | def Xform "Root" (
9 | prepend apiSchemas = ["MaterialBindingAPI"]
10 | )
11 | {
12 | reorder nameChildren = ["BillboardMaterial", "SpecialOcclusionMaterial", "Plane"]
13 | rel material:binding = (
14 | bindMaterialAs = "weakerThanDescendants"
15 | )
16 |
17 | def Material "BillboardMaterial"
18 | {
19 | reorder nameChildren = ["PreviewSurface", "Image", "GeometryModifier", "Position", "Multiply_2", "ViewFrame", "ParticleSpacePosition", "Add", "Multiply", "Multiply_1", "Separate2"]
20 | float inputs:cellSize = 0 (
21 | customData = {
22 | dictionary realitykit = {
23 | float2 positionInSubgraph = (2149.7761, 375.67697)
24 | int stackingOrderInSubgraph = 5472
25 | }
26 | }
27 | )
28 | asset inputs:texture (
29 | customData = {
30 | dictionary realitykit = {
31 | float2 positionInSubgraph = (1099.3767, -577.86914)
32 | float2 sizeInSubgraph = (115.5, 53)
33 | int stackingOrderInSubgraph = 5451
34 | }
35 | }
36 | )
37 | float inputs:time = 0 (
38 | customData = {
39 | dictionary realitykit = {
40 | float2 positionInSubgraph = (439.31454, 525.38214)
41 | float2 sizeInSubgraph = (98, 53)
42 | int stackingOrderInSubgraph = 5416
43 | }
44 | }
45 | )
46 | token outputs:mtlx:surface.connect =
47 | token outputs:realitykit:vertex.connect =
48 | float2 ui:nodegraph:realitykit:subgraphOutputs:pos = (3395.3894, 294.2436)
49 | float2 ui:nodegraph:realitykit:subgraphOutputs:size = (181.5, 99)
50 | int ui:nodegraph:realitykit:subgraphOutputs:stackingOrder = 5410
51 |
52 | def Shader "Multiply_2" (
53 | references = None
54 | )
55 | {
56 | uniform token info:id = "ND_multiply_vector3FA"
57 | float3 inputs:in1.connect =
58 | float inputs:in2 = 0.025
59 | float inputs:in2.connect =
60 | float3 outputs:out
61 | float2 ui:nodegraph:node:pos = (2468.3135, 371.76535)
62 | float2 ui:nodegraph:node:size = (60, 36)
63 | int ui:nodegraph:node:stackingOrder = 5469
64 | string[] ui:nodegraph:realitykit:node:attributesShowingChildren = ["outputs:out"]
65 | }
66 |
67 | def NodeGraph "ParticleSpacePosition" (
68 | references = None
69 | )
70 | {
71 | float2 outputs:Position (
72 | customData = {
73 | dictionary realitykit = {
74 | int stackingOrderInSubgraph = 289
75 | }
76 | }
77 | )
78 | float2 outputs:Position.connect =
79 | float2 ui:nodegraph:node:pos = (-13.930693, 871.25244)
80 | float2 ui:nodegraph:node:size = (187.5, 81)
81 | int ui:nodegraph:node:stackingOrder = 4890
82 | string[] ui:nodegraph:realitykit:node:attributesShowingChildren = ["outputs:Position", "outputs:Position", "outputs:Position"]
83 | float2 ui:nodegraph:realitykit:subgraphOutputs:pos = (890.64594, 77.62481)
84 | float2 ui:nodegraph:realitykit:subgraphOutputs:size = (191.0062, 81)
85 | int ui:nodegraph:realitykit:subgraphOutputs:stackingOrder = 588
86 |
87 | def Shader "PositionInParticle" (
88 | references = None
89 | )
90 | {
91 | uniform token info:id = "ND_texcoord_vector2"
92 | int inputs:index = 1
93 | float2 outputs:out
94 | float2 ui:nodegraph:node:pos = (106.57422, -31.613281)
95 | float2 ui:nodegraph:node:size = (193.5, 53)
96 | int ui:nodegraph:node:stackingOrder = 594
97 | }
98 |
99 | def Shader "Subtract" (
100 | references = None
101 | )
102 | {
103 | uniform token info:id = "ND_subtract_vector2"
104 | float2 inputs:in1.connect =
105 | float2 inputs:in2 = (0.5, 0.5)
106 | float2 outputs:out
107 | float2 ui:nodegraph:node:pos = (325.9453, -23.558594)
108 | float2 ui:nodegraph:node:size = (61.5, 36)
109 | int ui:nodegraph:node:stackingOrder = 590
110 | }
111 |
112 | def Shader "Multiply"
113 | {
114 | uniform token info:id = "ND_multiply_vector2FA"
115 | prepend float2 inputs:in1.connect =
116 | float inputs:in2 = 1
117 | float2 outputs:out
118 | float2 ui:nodegraph:node:pos = (523.59125, 155.27226)
119 | int ui:nodegraph:node:stackingOrder = 587
120 | }
121 | }
122 |
123 | def Shader "Multiply"
124 | {
125 | uniform token info:id = "ND_multiply_vector3FA"
126 | float3 inputs:in1.connect =
127 | float inputs:in2.connect =
128 | float3 outputs:out
129 | float2 ui:nodegraph:node:pos = (2235.056, 939.4348)
130 | float2 ui:nodegraph:node:size = (60, 36)
131 | int ui:nodegraph:node:stackingOrder = 5355
132 | }
133 |
134 | def Shader "Multiply_1" (
135 | references = None
136 | )
137 | {
138 | uniform token info:id = "ND_multiply_vector3FA"
139 | float3 inputs:in1.connect =
140 | float inputs:in2.connect =
141 | float3 outputs:out
142 | float2 ui:nodegraph:node:pos = (2206.4163, 1010.0793)
143 | float2 ui:nodegraph:node:size = (60, 36)
144 | int ui:nodegraph:node:stackingOrder = 5357
145 | }
146 |
147 | def Shader "Separate2" (
148 | references = None
149 | )
150 | {
151 | uniform token info:id = "ND_separate2_vector2"
152 | float2 inputs:in.connect =
153 | float outputs:outx
154 | float outputs:outy
155 | float2 ui:nodegraph:node:pos = (1129.5726, 1014.8174)
156 | float2 ui:nodegraph:node:size = (115, 127)
157 | int ui:nodegraph:node:stackingOrder = 5371
158 | string[] ui:nodegraph:realitykit:node:attributesShowingChildren = []
159 | }
160 |
161 | def NodeGraph "ViewFrame" (
162 | references = None
163 | )
164 | {
165 | float3 inputs:viewDirection = (0, 0, 1) (
166 | customData = {
167 | dictionary realitykit = {
168 | float2 positionInSubgraph = (-120.11611, 143.32283)
169 | int stackingOrderInSubgraph = 702
170 | }
171 | }
172 | )
173 | float3 inputs:viewDirection.connect =
174 | float3 outputs:Right (
175 | customData = {
176 | dictionary realitykit = {
177 | int stackingOrderInSubgraph = 290
178 | }
179 | }
180 | )
181 | float3 outputs:Right.connect =
182 | float3 outputs:Up (
183 | customData = {
184 | dictionary realitykit = {
185 | int stackingOrderInSubgraph = 290
186 | }
187 | }
188 | )
189 | float3 outputs:Up.connect =
190 | float2 ui:nodegraph:node:pos = (2018.7109, 1256.9489)
191 | float2 ui:nodegraph:node:size = (121, 99)
192 | int ui:nodegraph:node:stackingOrder = 5311
193 | string[] ui:nodegraph:realitykit:node:attributesShowingChildren = ["outputs:Right"]
194 | float2 ui:nodegraph:realitykit:subgraphOutputs:pos = (1136.9006, -5.6961317)
195 | float2 ui:nodegraph:realitykit:subgraphOutputs:size = (179.01637, 99)
196 | int ui:nodegraph:realitykit:subgraphOutputs:stackingOrder = 661
197 |
198 | def Shader "Right" (
199 | references = None
200 | )
201 | {
202 | uniform token info:id = "ND_normalize_vector3"
203 | float3 inputs:in.connect =
204 | float3 outputs:out
205 | float2 ui:nodegraph:node:pos = (507.14062, 16.460938)
206 | float2 ui:nodegraph:node:size = (132.5, 53)
207 | int ui:nodegraph:node:stackingOrder = 511
208 | }
209 |
210 | def Shader "Right_Unnormalized" (
211 | references = None
212 | )
213 | {
214 | uniform token info:id = "ND_crossproduct_vector3"
215 | float3 inputs:in1.connect =
216 | float3 inputs:in2 = (0, 1, 0)
217 | float3 outputs:out
218 | float2 ui:nodegraph:node:pos = (285.48438, 16.785156)
219 | float2 ui:nodegraph:node:size = (209.5, 53)
220 | int ui:nodegraph:node:stackingOrder = 661
221 | }
222 |
223 | def Shader "Up_Unnormalized" (
224 | references = None
225 | )
226 | {
227 | uniform token info:id = "ND_crossproduct_vector3"
228 | float3 inputs:in1.connect =
229 | float3 inputs:in2.connect =
230 | float3 outputs:out
231 | float2 ui:nodegraph:node:pos = (628.29297, 299.8164)
232 | float2 ui:nodegraph:node:size = (194, 53)
233 | int ui:nodegraph:node:stackingOrder = 698
234 | }
235 |
236 | def Shader "Up" (
237 | references = None
238 | )
239 | {
240 | uniform token info:id = "ND_normalize_vector3"
241 | float3 inputs:in.connect =
242 | float3 outputs:out
243 | float2 ui:nodegraph:node:pos = (870.33984, 308.1875)
244 | float2 ui:nodegraph:node:size = (132.5, 53)
245 | int ui:nodegraph:node:stackingOrder = 698
246 | }
247 |
248 | def Shader "Dot" (
249 | references = None
250 | )
251 | {
252 | uniform token info:id = "ND_dot_vector3"
253 | float3 inputs:in.connect =
254 | float3 outputs:out
255 | float2 ui:nodegraph:node:pos = (389.49548, 193.04463)
256 | float2 ui:nodegraph:node:size = (44, 18)
257 | int ui:nodegraph:node:stackingOrder = 700
258 | }
259 |
260 | def Scope "Group" (
261 | kind = "group"
262 | )
263 | {
264 | string ui:group:annotation = "Compute Left/Right Direction"
265 | string ui:group:annotationDescription = "Each particle is rendered as a plane, and this plane is perpendicular to ViewDirection. The left/right direction is parallel to the plane."
266 | string[] ui:group:members = ["p:Right_Unnormalized", "p:Right"]
267 | }
268 |
269 | def Shader "Dot_1" (
270 | references = None
271 | )
272 | {
273 | uniform token info:id = "ND_dot_vector3"
274 | float3 inputs:in.connect =
275 | float3 outputs:out
276 | float2 ui:nodegraph:node:pos = (45.382812, 11.4140625)
277 | float2 ui:nodegraph:node:size = (44, 18)
278 | int ui:nodegraph:node:stackingOrder = 532
279 | }
280 |
281 | def Scope "Group2" (
282 | kind = "group"
283 | )
284 | {
285 | string ui:group:annotation = "Compute Up/Down Direction"
286 | string ui:group:annotationDescription = "The up/down direction is parallel to the particle's plane and perpendicular to both ViewDirection and the left/right direction."
287 | string[] ui:group:members = ["p:Up", "p:Up_Unnormalized"]
288 | }
289 | }
290 |
291 | def Shader "Image"
292 | {
293 | uniform token info:id = "ND_image_color3"
294 | color3f inputs:default
295 | prepend asset inputs:file.connect =
296 | string inputs:filtertype
297 | float2 inputs:texcoord
298 | string inputs:uaddressmode
299 | string inputs:vaddressmode
300 | color3f outputs:out
301 | float2 ui:nodegraph:node:pos = (1549.6389, -678.7433)
302 | float2 ui:nodegraph:node:size = (148.5, 199)
303 | int ui:nodegraph:node:stackingOrder = 5460
304 | string[] ui:nodegraph:realitykit:node:attributesShowingChildren = ["inputs:file"]
305 | }
306 |
307 | def Shader "Magnitude"
308 | {
309 | uniform token info:id = "ND_magnitude_vector2"
310 | float2 inputs:in.connect =
311 | float outputs:out
312 | float2 ui:nodegraph:node:pos = (1417.497, 13.415811)
313 | float2 ui:nodegraph:node:size = (152, 40)
314 | int ui:nodegraph:node:stackingOrder = 5261
315 | }
316 |
317 | def Shader "SmoothStep_1"
318 | {
319 | uniform token info:id = "ND_smoothstep_float"
320 | float inputs:high = 3
321 | float inputs:in.connect =
322 | float inputs:low = 2
323 | float outputs:out
324 | float2 ui:nodegraph:node:pos = (1163.9985, 238.01328)
325 | float2 ui:nodegraph:node:size = (139.5, 145)
326 | int ui:nodegraph:node:stackingOrder = 5434
327 | }
328 |
329 | def Shader "Mix"
330 | {
331 | uniform token info:id = "ND_mix_vector3"
332 | float3 inputs:bg = (0, 0, 1)
333 | float3 inputs:bg.connect = None
334 | float3 inputs:fg.connect =
335 | float inputs:mix = 0.15
336 | float inputs:mix.connect =
337 | float3 outputs:out
338 | float2 ui:nodegraph:node:pos = (2163.7705, -235.07655)
339 | float2 ui:nodegraph:node:size = (109, 145)
340 | int ui:nodegraph:node:stackingOrder = 5115
341 | string[] ui:nodegraph:realitykit:node:attributesShowingChildren = ["inputs:fg", "inputs:fg", "inputs:bg", "inputs:fg", "inputs:mix"]
342 | }
343 |
344 | def Shader "Mix_2"
345 | {
346 | uniform token info:id = "ND_mix_float"
347 | float inputs:bg = 3
348 | float inputs:fg = 0.5
349 | float inputs:mix.connect =
350 | float outputs:out
351 | float2 ui:nodegraph:node:pos = (1392.2803, 151.47961)
352 | float2 ui:nodegraph:node:size = (109, 145)
353 | int ui:nodegraph:node:stackingOrder = 5431
354 | string[] ui:nodegraph:realitykit:node:attributesShowingChildren = ["inputs:fg", "inputs:fg", "inputs:fg", "inputs:fg", "inputs:bg", "inputs:bg", "inputs:bg", "inputs:fg"]
355 | }
356 |
357 | def Shader "Subtract_1"
358 | {
359 | uniform token info:id = "ND_subtract_float"
360 | float inputs:in1.connect =
361 | float inputs:in2.connect =
362 | float outputs:out
363 | float2 ui:nodegraph:node:pos = (602.3328, 436.18283)
364 | float2 ui:nodegraph:node:size = (61.5, 36)
365 | int ui:nodegraph:node:stackingOrder = 3246
366 | }
367 |
368 | def Shader "Multiply_3"
369 | {
370 | uniform token info:id = "ND_multiply_float"
371 | float inputs:in1.connect =
372 | float inputs:in2 = 1
373 | float outputs:out
374 | float2 ui:nodegraph:node:pos = (854.7252, 468.61627)
375 | float2 ui:nodegraph:node:size = (60, 36)
376 | int ui:nodegraph:node:stackingOrder = 5272
377 | string[] ui:nodegraph:realitykit:node:attributesShowingChildren = ["inputs:in2", "outputs:out"]
378 | }
379 |
380 | def Shader "SmoothStep_2"
381 | {
382 | uniform token info:id = "ND_smoothstep_float"
383 | float inputs:high = 4
384 | float inputs:in.connect =
385 | float inputs:low = 2
386 | float outputs:out
387 | float2 ui:nodegraph:node:pos = (1265.2583, 525.5995)
388 | float2 ui:nodegraph:node:size = (143, 145)
389 | int ui:nodegraph:node:stackingOrder = 5291
390 | }
391 |
392 | def Shader "Multiply_8"
393 | {
394 | uniform token info:id = "ND_multiply_float"
395 | float inputs:in1.connect =
396 | float inputs:in2 = 1
397 | float outputs:out
398 | float2 ui:nodegraph:node:pos = (2383.7788, 81.88629)
399 | float2 ui:nodegraph:node:size = (60, 36)
400 | int ui:nodegraph:node:stackingOrder = 4095
401 | string[] ui:nodegraph:realitykit:node:attributesShowingChildren = ["inputs:in1"]
402 | }
403 |
404 | def Shader "Add" (
405 | references = None
406 | )
407 | {
408 | uniform token info:id = "ND_add_vector3"
409 | float3 inputs:in1.connect =
410 | float3 inputs:in2.connect =
411 | float3 outputs:out
412 | float2 ui:nodegraph:node:pos = (2375.3484, 955.3678)
413 | float2 ui:nodegraph:node:size = (61.5, 36.5)
414 | int ui:nodegraph:node:stackingOrder = 5348
415 | }
416 |
417 | def Shader "SmoothStep"
418 | {
419 | uniform token info:id = "ND_smoothstep_float"
420 | float inputs:high = 0.49
421 | float inputs:high.connect = None
422 | float inputs:in.connect =
423 | float inputs:low = 0.49
424 | float inputs:low.connect =
425 | float outputs:out
426 | float2 ui:nodegraph:node:pos = (1763.4398, -58.636993)
427 | float2 ui:nodegraph:node:size = (127.5, 145)
428 | int ui:nodegraph:node:stackingOrder = 5259
429 | string[] ui:nodegraph:realitykit:node:attributesShowingChildren = ["inputs:low", "inputs:high", "inputs:low", "inputs:in", "inputs:low", "inputs:low", "outputs:out"]
430 | }
431 |
432 | def Shader "ViewDirection"
433 | {
434 | uniform token info:id = "ND_realitykit_viewdirection_vector3"
435 | string inputs:space
436 | float3 outputs:out
437 | float2 ui:nodegraph:node:pos = (1574.1215, 584.7081)
438 | int ui:nodegraph:node:stackingOrder = 5406
439 | }
440 |
441 | def Shader "Mix_4"
442 | {
443 | uniform token info:id = "ND_mix_vector3"
444 | float3 inputs:bg = (0, 0, 1)
445 | float3 inputs:bg.connect = None
446 | float3 inputs:fg = (0, 0, 1)
447 | float3 inputs:fg.connect =
448 | float inputs:mix = 0
449 | float inputs:mix.connect =
450 | float3 outputs:out
451 | float2 ui:nodegraph:node:pos = (1817.2855, 746.1274)
452 | float2 ui:nodegraph:node:size = (109, 145)
453 | int ui:nodegraph:node:stackingOrder = 5402
454 | string[] ui:nodegraph:realitykit:node:attributesShowingChildren = ["inputs:fg", "inputs:fg", "inputs:bg", "inputs:fg", "inputs:mix"]
455 | }
456 |
457 | def Shader "PBRSurface"
458 | {
459 | uniform token info:id = "ND_realitykit_pbr_surfaceshader"
460 | float inputs:ambientOcclusion = 1
461 | float inputs:ambientOcclusion.connect = None
462 | color3f inputs:baseColor = (1, 1, 1) (
463 | colorSpace = "srgb_displayp3"
464 | )
465 | color3f inputs:baseColor.connect =
466 | float inputs:clearcoat = 0.25
467 | float3 inputs:clearcoatNormal.connect =
468 | float inputs:clearcoatRoughness = 0.125
469 | color3f inputs:emissiveColor.connect =
470 | bool inputs:hasPremultipliedAlpha = 1
471 | float inputs:metallic = 0
472 | float3 inputs:normal.connect =
473 | float inputs:opacity.connect =
474 | float inputs:opacityThreshold = 0.2
475 | float inputs:roughness = 0.3
476 | float inputs:specular = 0.05
477 | token outputs:out
478 | float2 ui:nodegraph:node:pos = (3002.358, -396.1155)
479 | int ui:nodegraph:node:stackingOrder = 5476
480 | string[] ui:nodegraph:realitykit:node:attributesShowingChildren = ["inputs:metallic", "inputs:specular", "inputs:ambientOcclusion", "inputs:clearcoatRoughness", "inputs:opacity", "inputs:ambientOcclusion", "inputs:normal", "inputs:ambientOcclusion", "inputs:ambientOcclusion"]
481 | }
482 |
483 | def Shader "GeometryModifier_1"
484 | {
485 | uniform token info:id = "ND_realitykit_geometrymodifier_2_0_vertexshader"
486 | float3 inputs:bitangent.connect =
487 | color4f inputs:color
488 | float3 inputs:modelPositionOffset.connect =
489 | float3 inputs:normal.connect =
490 | float2 inputs:uv0
491 | float2 inputs:uv1
492 | float4 inputs:uv2
493 | float4 inputs:uv3
494 | float4 inputs:uv4.connect = None
495 | float4 inputs:uv5
496 | float4 inputs:uv6
497 | float4 inputs:uv7
498 | token outputs:out
499 | float2 ui:nodegraph:node:pos = (3060.0576, 872.93506)
500 | int ui:nodegraph:node:stackingOrder = 5423
501 | string[] ui:nodegraph:realitykit:node:attributesShowingChildren = ["inputs:modelPositionOffset", "inputs:bitangent"]
502 | }
503 |
504 | def Shader "Subtract"
505 | {
506 | uniform token info:id = "ND_subtract_float"
507 | float inputs:in1 = 0.25
508 | float inputs:in2.connect =
509 | float outputs:out
510 | float2 ui:nodegraph:node:pos = (671, 849.5)
511 | int ui:nodegraph:node:stackingOrder = 4944
512 | }
513 |
514 | def Shader "Sqrt"
515 | {
516 | uniform token info:id = "ND_sqrt_float"
517 | float inputs:in.connect =
518 | float outputs:out
519 | float2 ui:nodegraph:node:pos = (996.5, 849.5)
520 | int ui:nodegraph:node:stackingOrder = 4944
521 | }
522 |
523 | def Shader "Clamp"
524 | {
525 | uniform token info:id = "ND_clamp_float"
526 | float inputs:high.connect = None
527 | float inputs:in.connect =
528 | float inputs:low
529 | float outputs:out
530 | float2 ui:nodegraph:node:pos = (819.6384, 721.6268)
531 | int ui:nodegraph:node:stackingOrder = 4944
532 | }
533 |
534 | def Shader "DotProduct"
535 | {
536 | uniform token info:id = "ND_dotproduct_vector2"
537 | float2 inputs:in1.connect =
538 | float2 inputs:in2.connect =
539 | float outputs:out
540 | float2 ui:nodegraph:node:pos = (363.75, 849.5)
541 | float2 ui:nodegraph:node:size = (153.5, 53)
542 | int ui:nodegraph:node:stackingOrder = 4944
543 | string[] ui:nodegraph:realitykit:node:attributesShowingChildren = ["outputs:out"]
544 | }
545 |
546 | def Shader "Combine3"
547 | {
548 | uniform token info:id = "ND_combine3_vector3"
549 | float inputs:in1.connect =
550 | float inputs:in2.connect =
551 | float inputs:in3 = 1
552 | float inputs:in3.connect =
553 | float3 outputs:out
554 | float2 ui:nodegraph:node:pos = (1198.202, 746.1572)
555 | float2 ui:nodegraph:node:size = (145, 54)
556 | int ui:nodegraph:node:stackingOrder = 5404
557 | }
558 |
559 | def Shader "Time"
560 | {
561 | uniform token info:id = "ND_time_float"
562 | float outputs:out
563 | float2 ui:nodegraph:node:pos = (380.28607, 338.9291)
564 | float2 ui:nodegraph:node:size = (122.5, 53)
565 | int ui:nodegraph:node:stackingOrder = 5414
566 | }
567 |
568 | def Shader "Mix_3"
569 | {
570 | uniform token info:id = "ND_mix_color3"
571 | color3f inputs:bg.connect =
572 | color3f inputs:fg.connect =
573 | prepend float inputs:mix.connect =
574 | color3f outputs:out
575 | float2 ui:nodegraph:node:pos = (1805.707, -407.1063)
576 | float2 ui:nodegraph:node:size = (109, 145)
577 | int ui:nodegraph:node:stackingOrder = 5477
578 | string[] ui:nodegraph:realitykit:node:attributesShowingChildren = ["inputs:fg", "inputs:fg", "inputs:fg", "inputs:fg", "inputs:bg", "inputs:bg", "inputs:bg", "inputs:fg"]
579 | }
580 |
581 | def Shader "Multiply_4"
582 | {
583 | uniform token info:id = "ND_multiply_color3"
584 | color3f inputs:in1.connect =
585 | color3f inputs:in2 = (0.3, 0.3, 0.3) (
586 | colorSpace = "lin_srgb"
587 | )
588 | color3f outputs:out
589 | float2 ui:nodegraph:node:pos = (1669.4453, -497.61078)
590 | int ui:nodegraph:node:stackingOrder = 5478
591 | string[] ui:nodegraph:realitykit:node:attributesShowingChildren = ["outputs:out"]
592 | }
593 |
594 | def Shader "Multiply_5"
595 | {
596 | uniform token info:id = "ND_multiply_float"
597 | float inputs:in1.connect =
598 | float inputs:in2 = 1.05
599 | float outputs:out
600 | float2 ui:nodegraph:node:pos = (2298.4526, 416.6788)
601 | float2 ui:nodegraph:node:size = (60, 36)
602 | int ui:nodegraph:node:stackingOrder = 5475
603 | string[] ui:nodegraph:realitykit:node:attributesShowingChildren = ["outputs:out"]
604 | }
605 |
606 | def Shader "Multiply_6"
607 | {
608 | uniform token info:id = "ND_multiply_color3"
609 | color3f inputs:in1.connect =
610 | color3f inputs:in2 = (0.15, 0.15, 0.15) (
611 | colorSpace = "lin_srgb"
612 | )
613 | color3f outputs:out
614 | float2 ui:nodegraph:node:pos = (1555.8214, -447.86472)
615 | int ui:nodegraph:node:stackingOrder = 5482
616 | string[] ui:nodegraph:realitykit:node:attributesShowingChildren = ["outputs:out"]
617 | }
618 | }
619 |
620 | def "Plane" (
621 | active = true
622 | prepend apiSchemas = ["MaterialBindingAPI"]
623 | customData = {
624 | float3 rotationEulerHint = (-1.5707964, 0, 0)
625 | }
626 | references = @plane.usdc@
627 | )
628 | {
629 | rel material:binding = (
630 | bindMaterialAs = "weakerThanDescendants"
631 | )
632 | quatf xformOp:orient = (0.70710677, -0.70710677, 0, 0)
633 | float3 xformOp:scale = (1, 1, 1)
634 | float3 xformOp:translate = (0, 0, 0)
635 | uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:orient", "xformOp:scale"]
636 | }
637 | }
638 |
639 |
--------------------------------------------------------------------------------
/Examples/Photons/Photons.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 60;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | D00F9AC12C4AD80F00E5DD8D /* SceneCollisionEncoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00F9AC02C4AD80F00E5DD8D /* SceneCollisionEncoder.swift */; };
11 | D00F9AC32C4AD81500E5DD8D /* SceneCollision.metal in Sources */ = {isa = PBXBuildFile; fileRef = D00F9AC22C4AD81500E5DD8D /* SceneCollision.metal */; };
12 | D0326DFC2C4AE73A008879DD /* ParticleMeshBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0326DFB2C4AE73A008879DD /* ParticleMeshBuilder.swift */; };
13 | D0326DFE2C4AE789008879DD /* ParticleMeshUpdater.metal in Sources */ = {isa = PBXBuildFile; fileRef = D0326DFD2C4AE789008879DD /* ParticleMeshUpdater.metal */; };
14 | D03323272C4B04170051640A /* Simulation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03323262C4B04170051640A /* Simulation.swift */; };
15 | D03323292C4B04250051640A /* Simulation.metal in Sources */ = {isa = PBXBuildFile; fileRef = D03323282C4B04250051640A /* Simulation.metal */; };
16 | D046870B2C62C92800BB6557 /* RealityKitContent in Frameworks */ = {isa = PBXBuildFile; productRef = D07E26982C4AD09A00A3770F /* RealityKitContent */; };
17 | D07E269B2C4AD09A00A3770F /* PhotonsApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = D07E269A2C4AD09A00A3770F /* PhotonsApp.swift */; };
18 | D07E269D2C4AD09A00A3770F /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D07E269C2C4AD09A00A3770F /* ContentView.swift */; };
19 | D07E269F2C4AD09A00A3770F /* AppModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D07E269E2C4AD09A00A3770F /* AppModel.swift */; };
20 | D07E26A12C4AD09A00A3770F /* ToggleImmersiveSpaceButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = D07E26A02C4AD09A00A3770F /* ToggleImmersiveSpaceButton.swift */; };
21 | D07E26A32C4AD09A00A3770F /* ImmersiveView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D07E26A22C4AD09A00A3770F /* ImmersiveView.swift */; };
22 | D07E26A52C4AD09B00A3770F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D07E26A42C4AD09B00A3770F /* Assets.xcassets */; };
23 | D07E26A82C4AD09B00A3770F /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D07E26A72C4AD09B00A3770F /* Preview Assets.xcassets */; };
24 | D07E26B72C4AD1C200A3770F /* SceneMeshProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = D07E26B62C4AD1C200A3770F /* SceneMeshProvider.swift */; };
25 | D07E26BA2C4AD1CB00A3770F /* SceneMeshAssembler.metal in Sources */ = {isa = PBXBuildFile; fileRef = D07E26B82C4AD1CB00A3770F /* SceneMeshAssembler.metal */; };
26 | D07E26BB2C4AD1CB00A3770F /* SceneMeshAssembler.swift in Sources */ = {isa = PBXBuildFile; fileRef = D07E26B92C4AD1CB00A3770F /* SceneMeshAssembler.swift */; };
27 | D0831D862C4B749C0047DABA /* ViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0831D852C4B74980047DABA /* ViewModel.swift */; };
28 | D0B05E222C650BE000B0D5A3 /* MetalTools in Frameworks */ = {isa = PBXBuildFile; productRef = D00F9AA12C4AD51600E5DD8D /* MetalTools */; };
29 | D0B05E232C650BE000B0D5A3 /* SimulationTools in Frameworks */ = {isa = PBXBuildFile; productRef = D033232B2C4B04540051640A /* SimulationTools */; };
30 | D0B05E242C650BE000B0D5A3 /* SimulationTools in Frameworks */ = {isa = PBXBuildFile; productRef = D03323312C4B05DE0051640A /* SimulationTools */; };
31 | D0B05E252C650BE000B0D5A3 /* SimulationTools in Frameworks */ = {isa = PBXBuildFile; productRef = D0AB7A302C4C9B5F00A02C5A /* SimulationTools */; };
32 | D0B05E262C650BE000B0D5A3 /* SimulationTools in Frameworks */ = {isa = PBXBuildFile; productRef = D0795EFE2C4EF061003C3EB3 /* SimulationTools */; };
33 | D0B05E272C650BE000B0D5A3 /* SimulationTools in Frameworks */ = {isa = PBXBuildFile; productRef = D027028E2C53042F0024F8D3 /* SimulationTools */; };
34 | D0B05E282C650BE000B0D5A3 /* SimulationTools in Frameworks */ = {isa = PBXBuildFile; productRef = D07A0D842C54256B00FEA45C /* SimulationTools */; };
35 | D0B05E292C650BE000B0D5A3 /* SimulationTools in Frameworks */ = {isa = PBXBuildFile; productRef = D05E23422C62C8EF0065F0CF /* SimulationTools */; };
36 | D0B05E2A2C650BE000B0D5A3 /* SimulationTools in Frameworks */ = {isa = PBXBuildFile; productRef = D0C6EFEB2C647FAD0070BA8A /* SimulationTools */; };
37 | D0D3BD052C650DA900038002 /* SimulationTools in Frameworks */ = {isa = PBXBuildFile; productRef = D0D3BD042C650DA900038002 /* SimulationTools */; };
38 | D0E84AB62C6164BB00A3B7B1 /* SimulationSystem.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E84AB52C6164BB00A3B7B1 /* SimulationSystem.swift */; };
39 | D0E84AB82C6164D900A3B7B1 /* ParticlesUpdateSystem.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E84AB72C6164D900A3B7B1 /* ParticlesUpdateSystem.swift */; };
40 | D0E84ABA2C6164E200A3B7B1 /* SceneUpdateSystem.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E84AB92C6164E200A3B7B1 /* SceneUpdateSystem.swift */; };
41 | D0E84ABC2C62764E00A3B7B1 /* SettingsComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E84ABB2C62764E00A3B7B1 /* SettingsComponent.swift */; };
42 | D0E84ABE2C6285F000A3B7B1 /* SceneMeshBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E84ABD2C6285E900A3B7B1 /* SceneMeshBuilder.swift */; };
43 | /* End PBXBuildFile section */
44 |
45 | /* Begin PBXFileReference section */
46 | D00F9AC02C4AD80F00E5DD8D /* SceneCollisionEncoder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneCollisionEncoder.swift; sourceTree = ""; };
47 | D00F9AC22C4AD81500E5DD8D /* SceneCollision.metal */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.metal; path = SceneCollision.metal; sourceTree = ""; };
48 | D00F9AC82C4AE15100E5DD8D /* Utils.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Utils.h; sourceTree = ""; };
49 | D0326DFB2C4AE73A008879DD /* ParticleMeshBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParticleMeshBuilder.swift; sourceTree = ""; };
50 | D0326DFD2C4AE789008879DD /* ParticleMeshUpdater.metal */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.metal; path = ParticleMeshUpdater.metal; sourceTree = ""; };
51 | D03323262C4B04170051640A /* Simulation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Simulation.swift; sourceTree = ""; };
52 | D03323282C4B04250051640A /* Simulation.metal */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.metal; path = Simulation.metal; sourceTree = ""; };
53 | D07E26932C4AD09900A3770F /* Photons.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Photons.app; sourceTree = BUILT_PRODUCTS_DIR; };
54 | D07E26972C4AD09A00A3770F /* RealityKitContent */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = RealityKitContent; sourceTree = ""; };
55 | D07E269A2C4AD09A00A3770F /* PhotonsApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotonsApp.swift; sourceTree = ""; };
56 | D07E269C2C4AD09A00A3770F /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; };
57 | D07E269E2C4AD09A00A3770F /* AppModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppModel.swift; sourceTree = ""; };
58 | D07E26A02C4AD09A00A3770F /* ToggleImmersiveSpaceButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToggleImmersiveSpaceButton.swift; sourceTree = ""; };
59 | D07E26A22C4AD09A00A3770F /* ImmersiveView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImmersiveView.swift; sourceTree = ""; };
60 | D07E26A42C4AD09B00A3770F /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
61 | D07E26A72C4AD09B00A3770F /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; };
62 | D07E26A92C4AD09B00A3770F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
63 | D07E26B62C4AD1C200A3770F /* SceneMeshProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneMeshProvider.swift; sourceTree = ""; };
64 | D07E26B82C4AD1CB00A3770F /* SceneMeshAssembler.metal */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.metal; path = SceneMeshAssembler.metal; sourceTree = ""; };
65 | D07E26B92C4AD1CB00A3770F /* SceneMeshAssembler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneMeshAssembler.swift; sourceTree = ""; };
66 | D0831D852C4B74980047DABA /* ViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewModel.swift; sourceTree = ""; };
67 | D097B6082C6507950036B5CB /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; };
68 | D0E84AB52C6164BB00A3B7B1 /* SimulationSystem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimulationSystem.swift; sourceTree = ""; };
69 | D0E84AB72C6164D900A3B7B1 /* ParticlesUpdateSystem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParticlesUpdateSystem.swift; sourceTree = ""; };
70 | D0E84AB92C6164E200A3B7B1 /* SceneUpdateSystem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneUpdateSystem.swift; sourceTree = ""; };
71 | D0E84ABB2C62764E00A3B7B1 /* SettingsComponent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsComponent.swift; sourceTree = ""; };
72 | D0E84ABD2C6285E900A3B7B1 /* SceneMeshBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneMeshBuilder.swift; sourceTree = ""; };
73 | /* End PBXFileReference section */
74 |
75 | /* Begin PBXFrameworksBuildPhase section */
76 | D07E26902C4AD09900A3770F /* Frameworks */ = {
77 | isa = PBXFrameworksBuildPhase;
78 | buildActionMask = 2147483647;
79 | files = (
80 | D0B05E2A2C650BE000B0D5A3 /* SimulationTools in Frameworks */,
81 | D0B05E292C650BE000B0D5A3 /* SimulationTools in Frameworks */,
82 | D0B05E282C650BE000B0D5A3 /* SimulationTools in Frameworks */,
83 | D0B05E272C650BE000B0D5A3 /* SimulationTools in Frameworks */,
84 | D0D3BD052C650DA900038002 /* SimulationTools in Frameworks */,
85 | D0B05E262C650BE000B0D5A3 /* SimulationTools in Frameworks */,
86 | D0B05E252C650BE000B0D5A3 /* SimulationTools in Frameworks */,
87 | D0B05E242C650BE000B0D5A3 /* SimulationTools in Frameworks */,
88 | D0B05E232C650BE000B0D5A3 /* SimulationTools in Frameworks */,
89 | D0B05E222C650BE000B0D5A3 /* MetalTools in Frameworks */,
90 | D046870B2C62C92800BB6557 /* RealityKitContent in Frameworks */,
91 | );
92 | runOnlyForDeploymentPostprocessing = 0;
93 | };
94 | /* End PBXFrameworksBuildPhase section */
95 |
96 | /* Begin PBXGroup section */
97 | 54F137842C5AF08500302974 /* Frameworks */ = {
98 | isa = PBXGroup;
99 | children = (
100 | );
101 | name = Frameworks;
102 | sourceTree = "";
103 | };
104 | D07E268A2C4AD09900A3770F = {
105 | isa = PBXGroup;
106 | children = (
107 | D07E26952C4AD09900A3770F /* Photons */,
108 | D07E26962C4AD09A00A3770F /* Packages */,
109 | D07E26942C4AD09900A3770F /* Products */,
110 | 54F137842C5AF08500302974 /* Frameworks */,
111 | D097B6082C6507950036B5CB /* README.md */,
112 | );
113 | sourceTree = "";
114 | };
115 | D07E26942C4AD09900A3770F /* Products */ = {
116 | isa = PBXGroup;
117 | children = (
118 | D07E26932C4AD09900A3770F /* Photons.app */,
119 | );
120 | name = Products;
121 | sourceTree = "";
122 | };
123 | D07E26952C4AD09900A3770F /* Photons */ = {
124 | isa = PBXGroup;
125 | children = (
126 | D0E84AB42C6164A300A3B7B1 /* ECS */,
127 | D0A7A6002C50254500F1F86E /* UI */,
128 | D0A7A5FF2C5024CD00F1F86E /* Scene */,
129 | D0A7A5FE2C5023C300F1F86E /* Particles */,
130 | D0A7A5FD2C5023B300F1F86E /* Simulation */,
131 | D07E269A2C4AD09A00A3770F /* PhotonsApp.swift */,
132 | D00F9AC82C4AE15100E5DD8D /* Utils.h */,
133 | D07E269E2C4AD09A00A3770F /* AppModel.swift */,
134 | D07E26A42C4AD09B00A3770F /* Assets.xcassets */,
135 | D07E26A92C4AD09B00A3770F /* Info.plist */,
136 | D07E26A62C4AD09B00A3770F /* Preview Content */,
137 | );
138 | path = Photons;
139 | sourceTree = "";
140 | };
141 | D07E26962C4AD09A00A3770F /* Packages */ = {
142 | isa = PBXGroup;
143 | children = (
144 | D07E26972C4AD09A00A3770F /* RealityKitContent */,
145 | );
146 | path = Packages;
147 | sourceTree = "";
148 | };
149 | D07E26A62C4AD09B00A3770F /* Preview Content */ = {
150 | isa = PBXGroup;
151 | children = (
152 | D07E26A72C4AD09B00A3770F /* Preview Assets.xcassets */,
153 | );
154 | path = "Preview Content";
155 | sourceTree = "";
156 | };
157 | D0A7A5FD2C5023B300F1F86E /* Simulation */ = {
158 | isa = PBXGroup;
159 | children = (
160 | D03323262C4B04170051640A /* Simulation.swift */,
161 | D03323282C4B04250051640A /* Simulation.metal */,
162 | );
163 | path = Simulation;
164 | sourceTree = "";
165 | };
166 | D0A7A5FE2C5023C300F1F86E /* Particles */ = {
167 | isa = PBXGroup;
168 | children = (
169 | D0326DFD2C4AE789008879DD /* ParticleMeshUpdater.metal */,
170 | D0326DFB2C4AE73A008879DD /* ParticleMeshBuilder.swift */,
171 | );
172 | path = Particles;
173 | sourceTree = "";
174 | };
175 | D0A7A5FF2C5024CD00F1F86E /* Scene */ = {
176 | isa = PBXGroup;
177 | children = (
178 | D00F9AC22C4AD81500E5DD8D /* SceneCollision.metal */,
179 | D00F9AC02C4AD80F00E5DD8D /* SceneCollisionEncoder.swift */,
180 | D07E26B82C4AD1CB00A3770F /* SceneMeshAssembler.metal */,
181 | D07E26B92C4AD1CB00A3770F /* SceneMeshAssembler.swift */,
182 | D0E84ABD2C6285E900A3B7B1 /* SceneMeshBuilder.swift */,
183 | D07E26B62C4AD1C200A3770F /* SceneMeshProvider.swift */,
184 | );
185 | path = Scene;
186 | sourceTree = "";
187 | };
188 | D0A7A6002C50254500F1F86E /* UI */ = {
189 | isa = PBXGroup;
190 | children = (
191 | D07E26A02C4AD09A00A3770F /* ToggleImmersiveSpaceButton.swift */,
192 | D07E26A22C4AD09A00A3770F /* ImmersiveView.swift */,
193 | D0831D852C4B74980047DABA /* ViewModel.swift */,
194 | D07E269C2C4AD09A00A3770F /* ContentView.swift */,
195 | );
196 | path = UI;
197 | sourceTree = "";
198 | };
199 | D0E84AB42C6164A300A3B7B1 /* ECS */ = {
200 | isa = PBXGroup;
201 | children = (
202 | D0E84ABB2C62764E00A3B7B1 /* SettingsComponent.swift */,
203 | D0E84AB92C6164E200A3B7B1 /* SceneUpdateSystem.swift */,
204 | D0E84AB72C6164D900A3B7B1 /* ParticlesUpdateSystem.swift */,
205 | D0E84AB52C6164BB00A3B7B1 /* SimulationSystem.swift */,
206 | );
207 | path = ECS;
208 | sourceTree = "";
209 | };
210 | /* End PBXGroup section */
211 |
212 | /* Begin PBXNativeTarget section */
213 | D07E26922C4AD09900A3770F /* Photons */ = {
214 | isa = PBXNativeTarget;
215 | buildConfigurationList = D07E26AC2C4AD09B00A3770F /* Build configuration list for PBXNativeTarget "Photons" */;
216 | buildPhases = (
217 | D07E268F2C4AD09900A3770F /* Sources */,
218 | D07E26902C4AD09900A3770F /* Frameworks */,
219 | D07E26912C4AD09900A3770F /* Resources */,
220 | );
221 | buildRules = (
222 | );
223 | dependencies = (
224 | );
225 | name = Photons;
226 | packageProductDependencies = (
227 | D07E26982C4AD09A00A3770F /* RealityKitContent */,
228 | D00F9AA12C4AD51600E5DD8D /* MetalTools */,
229 | D033232B2C4B04540051640A /* SimulationTools */,
230 | D03323312C4B05DE0051640A /* SimulationTools */,
231 | D0AB7A302C4C9B5F00A02C5A /* SimulationTools */,
232 | D0795EFE2C4EF061003C3EB3 /* SimulationTools */,
233 | D027028E2C53042F0024F8D3 /* SimulationTools */,
234 | D07A0D842C54256B00FEA45C /* SimulationTools */,
235 | D05E23422C62C8EF0065F0CF /* SimulationTools */,
236 | D0C6EFEB2C647FAD0070BA8A /* SimulationTools */,
237 | D0D3BD042C650DA900038002 /* SimulationTools */,
238 | );
239 | productName = TheSpatialPhoto;
240 | productReference = D07E26932C4AD09900A3770F /* Photons.app */;
241 | productType = "com.apple.product-type.application";
242 | };
243 | /* End PBXNativeTarget section */
244 |
245 | /* Begin PBXProject section */
246 | D07E268B2C4AD09900A3770F /* Project object */ = {
247 | isa = PBXProject;
248 | attributes = {
249 | BuildIndependentTargetsInParallel = 1;
250 | LastSwiftUpdateCheck = 1600;
251 | LastUpgradeCheck = 1600;
252 | TargetAttributes = {
253 | D07E26922C4AD09900A3770F = {
254 | CreatedOnToolsVersion = 16.0;
255 | };
256 | };
257 | };
258 | buildConfigurationList = D07E268E2C4AD09900A3770F /* Build configuration list for PBXProject "Photons" */;
259 | compatibilityVersion = "Xcode 15.0";
260 | developmentRegion = en;
261 | hasScannedForEncodings = 0;
262 | knownRegions = (
263 | en,
264 | Base,
265 | );
266 | mainGroup = D07E268A2C4AD09900A3770F;
267 | packageReferences = (
268 | D0D3BD032C650DA900038002 /* XCRemoteSwiftPackageReference "simulation-tools" */,
269 | );
270 | productRefGroup = D07E26942C4AD09900A3770F /* Products */;
271 | projectDirPath = "";
272 | projectRoot = "";
273 | targets = (
274 | D07E26922C4AD09900A3770F /* Photons */,
275 | );
276 | };
277 | /* End PBXProject section */
278 |
279 | /* Begin PBXResourcesBuildPhase section */
280 | D07E26912C4AD09900A3770F /* Resources */ = {
281 | isa = PBXResourcesBuildPhase;
282 | buildActionMask = 2147483647;
283 | files = (
284 | D07E26A82C4AD09B00A3770F /* Preview Assets.xcassets in Resources */,
285 | D07E26A52C4AD09B00A3770F /* Assets.xcassets in Resources */,
286 | );
287 | runOnlyForDeploymentPostprocessing = 0;
288 | };
289 | /* End PBXResourcesBuildPhase section */
290 |
291 | /* Begin PBXSourcesBuildPhase section */
292 | D07E268F2C4AD09900A3770F /* Sources */ = {
293 | isa = PBXSourcesBuildPhase;
294 | buildActionMask = 2147483647;
295 | files = (
296 | D07E26A12C4AD09A00A3770F /* ToggleImmersiveSpaceButton.swift in Sources */,
297 | D0E84ABE2C6285F000A3B7B1 /* SceneMeshBuilder.swift in Sources */,
298 | D00F9AC32C4AD81500E5DD8D /* SceneCollision.metal in Sources */,
299 | D07E269D2C4AD09A00A3770F /* ContentView.swift in Sources */,
300 | D0326DFE2C4AE789008879DD /* ParticleMeshUpdater.metal in Sources */,
301 | D0E84ABC2C62764E00A3B7B1 /* SettingsComponent.swift in Sources */,
302 | D0E84AB62C6164BB00A3B7B1 /* SimulationSystem.swift in Sources */,
303 | D03323292C4B04250051640A /* Simulation.metal in Sources */,
304 | D07E26BA2C4AD1CB00A3770F /* SceneMeshAssembler.metal in Sources */,
305 | D0E84ABA2C6164E200A3B7B1 /* SceneUpdateSystem.swift in Sources */,
306 | D03323272C4B04170051640A /* Simulation.swift in Sources */,
307 | D0326DFC2C4AE73A008879DD /* ParticleMeshBuilder.swift in Sources */,
308 | D0831D862C4B749C0047DABA /* ViewModel.swift in Sources */,
309 | D07E26BB2C4AD1CB00A3770F /* SceneMeshAssembler.swift in Sources */,
310 | D07E26B72C4AD1C200A3770F /* SceneMeshProvider.swift in Sources */,
311 | D07E26A32C4AD09A00A3770F /* ImmersiveView.swift in Sources */,
312 | D07E269F2C4AD09A00A3770F /* AppModel.swift in Sources */,
313 | D07E269B2C4AD09A00A3770F /* PhotonsApp.swift in Sources */,
314 | D0E84AB82C6164D900A3B7B1 /* ParticlesUpdateSystem.swift in Sources */,
315 | D00F9AC12C4AD80F00E5DD8D /* SceneCollisionEncoder.swift in Sources */,
316 | );
317 | runOnlyForDeploymentPostprocessing = 0;
318 | };
319 | /* End PBXSourcesBuildPhase section */
320 |
321 | /* Begin XCBuildConfiguration section */
322 | D07E26AA2C4AD09B00A3770F /* Debug */ = {
323 | isa = XCBuildConfiguration;
324 | buildSettings = {
325 | ALWAYS_SEARCH_USER_PATHS = NO;
326 | ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
327 | CLANG_ANALYZER_NONNULL = YES;
328 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
329 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
330 | CLANG_ENABLE_MODULES = YES;
331 | CLANG_ENABLE_OBJC_ARC = YES;
332 | CLANG_ENABLE_OBJC_WEAK = YES;
333 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
334 | CLANG_WARN_BOOL_CONVERSION = YES;
335 | CLANG_WARN_COMMA = YES;
336 | CLANG_WARN_CONSTANT_CONVERSION = YES;
337 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
338 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
339 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
340 | CLANG_WARN_EMPTY_BODY = YES;
341 | CLANG_WARN_ENUM_CONVERSION = YES;
342 | CLANG_WARN_INFINITE_RECURSION = YES;
343 | CLANG_WARN_INT_CONVERSION = YES;
344 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
345 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
346 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
347 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
348 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
349 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
350 | CLANG_WARN_STRICT_PROTOTYPES = YES;
351 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
352 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
353 | CLANG_WARN_UNREACHABLE_CODE = YES;
354 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
355 | COPY_PHASE_STRIP = NO;
356 | DEBUG_INFORMATION_FORMAT = dwarf;
357 | ENABLE_STRICT_OBJC_MSGSEND = YES;
358 | ENABLE_TESTABILITY = YES;
359 | ENABLE_USER_SCRIPT_SANDBOXING = YES;
360 | GCC_C_LANGUAGE_STANDARD = gnu17;
361 | GCC_DYNAMIC_NO_PIC = NO;
362 | GCC_NO_COMMON_BLOCKS = YES;
363 | GCC_OPTIMIZATION_LEVEL = 0;
364 | GCC_PREPROCESSOR_DEFINITIONS = (
365 | "DEBUG=1",
366 | "$(inherited)",
367 | );
368 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
369 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
370 | GCC_WARN_UNDECLARED_SELECTOR = YES;
371 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
372 | GCC_WARN_UNUSED_FUNCTION = YES;
373 | GCC_WARN_UNUSED_VARIABLE = YES;
374 | LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
375 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
376 | MTL_FAST_MATH = YES;
377 | ONLY_ACTIVE_ARCH = YES;
378 | SDKROOT = xros;
379 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
380 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
381 | XROS_DEPLOYMENT_TARGET = 2.0;
382 | };
383 | name = Debug;
384 | };
385 | D07E26AB2C4AD09B00A3770F /* Release */ = {
386 | isa = XCBuildConfiguration;
387 | buildSettings = {
388 | ALWAYS_SEARCH_USER_PATHS = NO;
389 | ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
390 | CLANG_ANALYZER_NONNULL = YES;
391 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
392 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
393 | CLANG_ENABLE_MODULES = YES;
394 | CLANG_ENABLE_OBJC_ARC = YES;
395 | CLANG_ENABLE_OBJC_WEAK = YES;
396 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
397 | CLANG_WARN_BOOL_CONVERSION = YES;
398 | CLANG_WARN_COMMA = YES;
399 | CLANG_WARN_CONSTANT_CONVERSION = YES;
400 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
401 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
402 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
403 | CLANG_WARN_EMPTY_BODY = YES;
404 | CLANG_WARN_ENUM_CONVERSION = YES;
405 | CLANG_WARN_INFINITE_RECURSION = YES;
406 | CLANG_WARN_INT_CONVERSION = YES;
407 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
408 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
409 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
410 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
411 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
412 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
413 | CLANG_WARN_STRICT_PROTOTYPES = YES;
414 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
415 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
416 | CLANG_WARN_UNREACHABLE_CODE = YES;
417 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
418 | COPY_PHASE_STRIP = NO;
419 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
420 | ENABLE_NS_ASSERTIONS = NO;
421 | ENABLE_STRICT_OBJC_MSGSEND = YES;
422 | ENABLE_USER_SCRIPT_SANDBOXING = YES;
423 | GCC_C_LANGUAGE_STANDARD = gnu17;
424 | GCC_NO_COMMON_BLOCKS = YES;
425 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
426 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
427 | GCC_WARN_UNDECLARED_SELECTOR = YES;
428 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
429 | GCC_WARN_UNUSED_FUNCTION = YES;
430 | GCC_WARN_UNUSED_VARIABLE = YES;
431 | LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
432 | MTL_ENABLE_DEBUG_INFO = NO;
433 | MTL_FAST_MATH = YES;
434 | SDKROOT = xros;
435 | SWIFT_COMPILATION_MODE = wholemodule;
436 | VALIDATE_PRODUCT = YES;
437 | XROS_DEPLOYMENT_TARGET = 2.0;
438 | };
439 | name = Release;
440 | };
441 | D07E26AD2C4AD09B00A3770F /* Debug */ = {
442 | isa = XCBuildConfiguration;
443 | buildSettings = {
444 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
445 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
446 | CODE_SIGN_IDENTITY = "Apple Development";
447 | CODE_SIGN_STYLE = Automatic;
448 | CURRENT_PROJECT_VERSION = 1;
449 | DEVELOPMENT_ASSET_PATHS = "\"Photons/Preview Content\"";
450 | DEVELOPMENT_TEAM = 7LT752HSAG;
451 | ENABLE_PREVIEWS = YES;
452 | GENERATE_INFOPLIST_FILE = YES;
453 | INFOPLIST_FILE = "$(TARGET_NAME)/Info.plist";
454 | INFOPLIST_KEY_NSPhotoLibraryUsageDescription = "For fun";
455 | LD_RUNPATH_SEARCH_PATHS = (
456 | "$(inherited)",
457 | "@executable_path/Frameworks",
458 | );
459 | MACOSX_DEPLOYMENT_TARGET = 11.0;
460 | MARKETING_VERSION = 1.0;
461 | PRODUCT_BUNDLE_IDENTIFIER = "com.computer-graphics-tools.photons";
462 | PRODUCT_NAME = "$(TARGET_NAME)";
463 | PROVISIONING_PROFILE_SPECIFIER = "";
464 | REGISTER_APP_GROUPS = YES;
465 | SUPPORTED_PLATFORMS = "xros xrsimulator";
466 | SUPPORTS_MACCATALYST = NO;
467 | SWIFT_EMIT_LOC_STRINGS = YES;
468 | SWIFT_VERSION = 5.0;
469 | TARGETED_DEVICE_FAMILY = 7;
470 | XROS_DEPLOYMENT_TARGET = 2.0;
471 | };
472 | name = Debug;
473 | };
474 | D07E26AE2C4AD09B00A3770F /* Release */ = {
475 | isa = XCBuildConfiguration;
476 | buildSettings = {
477 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
478 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
479 | CODE_SIGN_IDENTITY = "Apple Development";
480 | CODE_SIGN_STYLE = Automatic;
481 | CURRENT_PROJECT_VERSION = 1;
482 | DEVELOPMENT_ASSET_PATHS = "\"Photons/Preview Content\"";
483 | DEVELOPMENT_TEAM = 7LT752HSAG;
484 | ENABLE_PREVIEWS = YES;
485 | GENERATE_INFOPLIST_FILE = YES;
486 | INFOPLIST_FILE = "$(TARGET_NAME)/Info.plist";
487 | INFOPLIST_KEY_NSPhotoLibraryUsageDescription = "For fun";
488 | LD_RUNPATH_SEARCH_PATHS = (
489 | "$(inherited)",
490 | "@executable_path/Frameworks",
491 | );
492 | MACOSX_DEPLOYMENT_TARGET = 11.0;
493 | MARKETING_VERSION = 1.0;
494 | PRODUCT_BUNDLE_IDENTIFIER = "com.computer-graphics-tools.photons";
495 | PRODUCT_NAME = "$(TARGET_NAME)";
496 | PROVISIONING_PROFILE_SPECIFIER = "";
497 | REGISTER_APP_GROUPS = YES;
498 | SUPPORTED_PLATFORMS = "xros xrsimulator";
499 | SUPPORTS_MACCATALYST = NO;
500 | SWIFT_EMIT_LOC_STRINGS = YES;
501 | SWIFT_VERSION = 5.0;
502 | TARGETED_DEVICE_FAMILY = 7;
503 | XROS_DEPLOYMENT_TARGET = 2.0;
504 | };
505 | name = Release;
506 | };
507 | /* End XCBuildConfiguration section */
508 |
509 | /* Begin XCConfigurationList section */
510 | D07E268E2C4AD09900A3770F /* Build configuration list for PBXProject "Photons" */ = {
511 | isa = XCConfigurationList;
512 | buildConfigurations = (
513 | D07E26AA2C4AD09B00A3770F /* Debug */,
514 | D07E26AB2C4AD09B00A3770F /* Release */,
515 | );
516 | defaultConfigurationIsVisible = 0;
517 | defaultConfigurationName = Release;
518 | };
519 | D07E26AC2C4AD09B00A3770F /* Build configuration list for PBXNativeTarget "Photons" */ = {
520 | isa = XCConfigurationList;
521 | buildConfigurations = (
522 | D07E26AD2C4AD09B00A3770F /* Debug */,
523 | D07E26AE2C4AD09B00A3770F /* Release */,
524 | );
525 | defaultConfigurationIsVisible = 0;
526 | defaultConfigurationName = Release;
527 | };
528 | /* End XCConfigurationList section */
529 |
530 | /* Begin XCRemoteSwiftPackageReference section */
531 | D0D3BD032C650DA900038002 /* XCRemoteSwiftPackageReference "simulation-tools" */ = {
532 | isa = XCRemoteSwiftPackageReference;
533 | repositoryURL = "https://github.com/computer-graphics-tools/simulation-tools";
534 | requirement = {
535 | branch = main;
536 | kind = branch;
537 | };
538 | };
539 | /* End XCRemoteSwiftPackageReference section */
540 |
541 | /* Begin XCSwiftPackageProductDependency section */
542 | D00F9AA12C4AD51600E5DD8D /* MetalTools */ = {
543 | isa = XCSwiftPackageProductDependency;
544 | productName = MetalTools;
545 | };
546 | D027028E2C53042F0024F8D3 /* SimulationTools */ = {
547 | isa = XCSwiftPackageProductDependency;
548 | productName = SimulationTools;
549 | };
550 | D033232B2C4B04540051640A /* SimulationTools */ = {
551 | isa = XCSwiftPackageProductDependency;
552 | productName = SimulationTools;
553 | };
554 | D03323312C4B05DE0051640A /* SimulationTools */ = {
555 | isa = XCSwiftPackageProductDependency;
556 | productName = SimulationTools;
557 | };
558 | D05E23422C62C8EF0065F0CF /* SimulationTools */ = {
559 | isa = XCSwiftPackageProductDependency;
560 | productName = SimulationTools;
561 | };
562 | D0795EFE2C4EF061003C3EB3 /* SimulationTools */ = {
563 | isa = XCSwiftPackageProductDependency;
564 | productName = SimulationTools;
565 | };
566 | D07A0D842C54256B00FEA45C /* SimulationTools */ = {
567 | isa = XCSwiftPackageProductDependency;
568 | productName = SimulationTools;
569 | };
570 | D07E26982C4AD09A00A3770F /* RealityKitContent */ = {
571 | isa = XCSwiftPackageProductDependency;
572 | productName = RealityKitContent;
573 | };
574 | D0AB7A302C4C9B5F00A02C5A /* SimulationTools */ = {
575 | isa = XCSwiftPackageProductDependency;
576 | productName = SimulationTools;
577 | };
578 | D0C6EFEB2C647FAD0070BA8A /* SimulationTools */ = {
579 | isa = XCSwiftPackageProductDependency;
580 | productName = SimulationTools;
581 | };
582 | D0D3BD042C650DA900038002 /* SimulationTools */ = {
583 | isa = XCSwiftPackageProductDependency;
584 | package = D0D3BD032C650DA900038002 /* XCRemoteSwiftPackageReference "simulation-tools" */;
585 | productName = SimulationTools;
586 | };
587 | /* End XCSwiftPackageProductDependency section */
588 | };
589 | rootObject = D07E268B2C4AD09900A3770F /* Project object */;
590 | }
591 |
--------------------------------------------------------------------------------