@@ -15,13 +15,15 @@ final class RealityKitViewController: UIViewController, UIGestureRecognizerDeleg
1515 private var orbitPitch : Float = - 0.1
1616 private var orbitDistance : Float = 2
1717 private var orbitTarget = SIMD3 < Float > ( 0 , 0.8 , 0 )
18+ private var currentExpression : RKExpression = . neutral
1819
1920 override func viewDidLoad( ) {
2021 super. viewDidLoad ( )
2122 title = " RealityKit "
2223 view. backgroundColor = . black
2324 setUpARView ( )
24- loadVRM ( )
25+ setUpUI ( )
26+ loadVRM ( model: . alicia)
2527 }
2628
2729 private func setUpARView( ) {
@@ -42,11 +44,51 @@ final class RealityKitViewController: UIViewController, UIGestureRecognizerDeleg
4244 setUpGestures ( )
4345 }
4446
45- private func loadVRM( ) {
47+ private func setUpUI( ) {
48+ let items = VRMExampleModel . allCases. map { $0. displayName }
49+ let segmentedControl = UISegmentedControl ( items: items)
50+ segmentedControl. selectedSegmentIndex = 0
51+ segmentedControl. addTarget ( self , action: #selector( segmentChanged ( _: ) ) , for: . valueChanged)
52+ segmentedControl. translatesAutoresizingMaskIntoConstraints = false
53+ view. addSubview ( segmentedControl)
54+
55+ let expressionItems = RKExpression . allCases. map { $0. displayName }
56+ let expressionSegmentedControl = UISegmentedControl ( items: expressionItems)
57+ expressionSegmentedControl. selectedSegmentIndex = 0
58+ expressionSegmentedControl. addTarget ( self , action: #selector( expressionSegmentChanged ( _: ) ) , for: . valueChanged)
59+ expressionSegmentedControl. translatesAutoresizingMaskIntoConstraints = false
60+ view. addSubview ( expressionSegmentedControl)
61+
62+ NSLayoutConstraint . activate ( [
63+ segmentedControl. centerXAnchor. constraint ( equalTo: view. centerXAnchor) ,
64+ segmentedControl. bottomAnchor. constraint ( equalTo: view. safeAreaLayoutGuide. bottomAnchor, constant: - 50 ) ,
65+ expressionSegmentedControl. centerXAnchor. constraint ( equalTo: view. centerXAnchor) ,
66+ expressionSegmentedControl. bottomAnchor. constraint ( equalTo: segmentedControl. topAnchor, constant: - 20 )
67+ ] )
68+ }
69+
70+ @objc private func segmentChanged( _ sender: UISegmentedControl ) {
71+ let model = VRMExampleModel . allCases [ sender. selectedSegmentIndex]
72+ loadVRM ( model: model)
73+ }
74+
75+ @objc private func expressionSegmentChanged( _ sender: UISegmentedControl ) {
76+ let expression = RKExpression . allCases [ sender. selectedSegmentIndex]
77+ loadedEntity? . setBlendShape ( value: 0.0 , for: . preset( currentExpression. preset) )
78+ currentExpression = expression
79+ loadedEntity? . setBlendShape ( value: 1.0 , for: . preset( currentExpression. preset) )
80+ }
81+
82+ private func loadVRM( model: VRMExampleModel ) {
4683 guard let arView = arView else { return }
4784
85+ if let loadedEntity = loadedEntity {
86+ loadedEntity. entity. removeFromParent ( )
87+ self . loadedEntity = nil
88+ }
89+
4890 do {
49- let loader = try VRMEntityLoader ( named: " AliciaSolid.vrm " )
91+ let loader = try VRMEntityLoader ( named: model . rawValue )
5092 let vrmEntity = try loader. loadEntity ( )
5193
5294 let anchor = AnchorEntity ( world: . zero)
@@ -72,10 +114,12 @@ final class RealityKitViewController: UIViewController, UIGestureRecognizerDeleg
72114 if let rightShoulder {
73115 rightShoulder. transform. rotation = rightShoulder. transform. rotation * shoulderRotation
74116 }
75- vrmEntity. setBlendShape ( value: 1.0 , for: . custom ( " >< " ) )
117+ vrmEntity. setBlendShape ( value: 1.0 , for: . preset ( currentExpression . preset ) )
76118
77119 loadedEntity = vrmEntity
78120
121+ let rotationOffset = model. initialRotation
122+
79123 var time : TimeInterval = 0
80124 updateSubscription = arView. scene. subscribe ( to: SceneEvents . Update. self) { [ weak self] event in
81125 guard let loadedEntity = self ? . loadedEntity else { return }
@@ -92,7 +136,7 @@ final class RealityKitViewController: UIViewController, UIGestureRecognizerDeleg
92136 angle = - 0.5 + 0.5 * progress
93137 }
94138
95- loadedEntity. entity. transform. rotation = simd_quatf ( angle: angle, axis: SIMD3 < Float > ( 0 , 1 , 0 ) )
139+ loadedEntity. entity. transform. rotation = simd_quatf ( angle: rotationOffset + angle, axis: SIMD3 < Float > ( 0 , 1 , 0 ) )
96140
97141 loadedEntity. update ( at: event. deltaTime)
98142 }
@@ -205,3 +249,22 @@ final class RealityKitViewController: UIViewController, UIGestureRecognizerDeleg
205249 return true
206250 }
207251}
252+
253+ @available ( iOS 18 . 0 , * )
254+ private enum RKExpression : String , CaseIterable {
255+ case neutral, joy, angry, sorrow, fun
256+
257+ var preset : BlendShapePreset {
258+ switch self {
259+ case . neutral: return . neutral
260+ case . joy: return . joy
261+ case . angry: return . angry
262+ case . sorrow: return . sorrow
263+ case . fun: return . fun
264+ }
265+ }
266+
267+ var displayName : String {
268+ return rawValue. capitalized
269+ }
270+ }
0 commit comments