Deep dive into visionOS 30Days -Day 5

Coaspe
4 min readAug 31, 2023

--

Original source — satoshi0212

Day5App

import SwiftUI

@main
struct Day5App: App {
var body: some Scene {
WindowGroup {
ContentView()
}
ImmersiveSpace(id: "ImmersiveSpace") {
ImmersiveView()
}
}
}s

Entry point of this app. It has two Scenes, WindowGroup and ImmersiveSpace. ImmersiveSpace is a new type of Scene gives more deeper 3D experience. With it’s id(“ImmersiveSpace”), we can display ImmersiveSpace on Simulator.

Day5ViewModel

import SwiftUI
import RealityKit

@MainActor class Day5ViewModel: ObservableObject {

private var contentEntity = Entity()

func setupContentEntity() -> Entity {
return contentEntity
}

func addCube() {
guard
let texture1 = try? TextureResource.load(named: "Number_1"),
let texture2 = try? TextureResource.load(named: "Number_2"),
let texture3 = try? TextureResource.load(named: "Number_3"),
let texture4 = try? TextureResource.load(named: "Number_4"),
let texture5 = try? TextureResource.load(named: "Number_5"),
let texture6 = try? TextureResource.load(named: "Number_6")
else {
fatalError("Unable to load texture.")
}

let entity = Entity()

var material1 = SimpleMaterial()
var material2 = SimpleMaterial()
var material3 = SimpleMaterial()
var material4 = SimpleMaterial()
var material5 = SimpleMaterial()
var material6 = SimpleMaterial()

material1.color = .init(texture: .init(texture1))
material2.color = .init(texture: .init(texture2))
material3.color = .init(texture: .init(texture3))
material4.color = .init(texture: .init(texture4))
material5.color = .init(texture: .init(texture5))
material6.color = .init(texture: .init(texture6))

entity.components.set(ModelComponent(
mesh: .generateBox(width: 0.5, height: 0.5, depth: 0.5, splitFaces: true),
materials: [material1, material2, material3, material4, material5, material6])
)

entity.position = SIMD3(x: 0, y: 1, z: -2)

contentEntity.addChild(entity)
}
}

ViewModel that manage contentEntity and creates 3D cube.

Entity

An element of a RealityKit scene to which you attach components that provide appearance and behavior characteristics for the entity.

@MainActor @preconcurrency
class Entity

Entity is a container object. In order for Entity to do or render something, it must have components. You create and configure entities to embody objects that you want to place in the real world in an AR app. You do this by adding Entity instances to the Scene instance associated with an ARView. Entity can have multiple entities.

Component

A representation of a geometry or a behavior that you apply to an entity.

protocol Component

Components allow each entity to perform a specific behavior. Entity can have multiple components.

TextureResource

An object used to specify the intended usage of a texture.

@MainActor @preconcurrency
class TextureResource

This object specifies the intended use of the texture by an individual property.

SimpleMaterial

A basic material that you can apply to meshes.

struct SimpleMaterial

ModelComponent

A collection of resources that create the visual appearance of an entity.

struct ModelComponent

SIMD3

A vector of three scalar values.

@frozen
struct SIMD3<Scalar> where Scalar : SIMDScalar

ContentView

import SwiftUI
import RealityKit

struct ContentView: View {

@State var showImmersiveSpace = false

@Environment(\.openImmersiveSpace) var openImmersiveSpace
@Environment(\.dismissImmersiveSpace) var dismissImmersiveSpace

var body: some View {
NavigationStack {
VStack {
Toggle("Show ImmersiveSpace", isOn: $showImmersiveSpace)
.toggleStyle(.button)
}
.padding()
}
.onChange(of: showImmersiveSpace) { _, newValue in
Task {
if newValue {
await openImmersiveSpace(id: "ImmersiveSpace")
} else {
await dismissImmersiveSpace()
}
}
}
}
}

Window with toggle button. The value of the showImmersiveSpace toggles the Immersive space. Opening and dismissing immersive space are asynchronous.

@Environment(\.openImmersiveSpace)

An action that presents an immersive space.

var openImmersiveSpace: OpenImmersiveSpaceAction { get }

@Environment(\.dismissImmersiveSpace)

An immersive space dismissal action stored in a view’s environment.

var dismissImmersiveSpace: DismissImmersiveSpaceAction { get }

ImmersiveView

import SwiftUI
import RealityKit

struct ImmersiveView: View {

@StateObject var model = Day5ViewModel()

private var contentEntity = Entity()
private var location: CGPoint = .zero
private var location3D: Point3D = .zero

var body: some View {
RealityView { content in
content.add(model.setupContentEntity())
model.addCube()
}
.gesture(
SpatialTapGesture()
.targetedToAnyEntity()
.onEnded { value in
print(value)
}
)
}
}

ImmersiveSpace display this View. Add entity to SwiftUI View with RealityView.

CGPoint

A structure that contains a point in a two-dimensional coordinate system.

struct CGPoint

Point3D

A point in a 3D coordinate system.

struct Point3D

RealityView

A SwiftUI view for displaying RealityKit content on visionOS.

struct RealityView<Content> where Content : View

Use RealityView to display rich 3D content using RealityKit in your visionOS app, including RealityKit content authored in Reality Composer Pro. RealityView passes a structure that conforms to RealityViewContentProtocol to its make and update closures, which you can use to add and remove RealityKit entities to your view.

SpatialTapGesture

A gesture that recognizes one or more taps and reports their location.

struct SpatialTapGesture

With .targetedToAnyEntity() modifier, we can detect targeted entity in RealityView.

--

--