1

With a RealityView, an entity can be rotated using a gesture detector to the entire view:

RealityView { content in
    let loadedEntity = try await ModelEntity(named: modelName, 
                       in: RealityKitContent.realityKitContentBundle)
    // Add components to entity
    loadedEntity.generateCollisionShapes(recursive: true)
    loadedEntity.components.set(InputTargetComponent())

    loadedEntity.setParent(anchor)

    // Add the anchor which is the parent of the entity
    content.add(anchor)
  } .gesture(
      drag
  )

Question

This works for one model, but what if there are two models in the RealityView and each model should have a different rotation? How do we add a gesture to each model independently? Using Model3D?

This should not include building a scene in RealityComposerPro. We are talking about programmatically spawning objects in and allowing gestures.

Original post on figuring out rotation here

Andy Jazz
  • 49,178
  • 17
  • 136
  • 220
Zach
  • 1
  • 1
  • 9

1 Answers1

1

Rotating entities independently in RealityView

I created two cubes in a Reality Composer Pro scene. And placed them at a distance of 50 cm from each other. If you do not need to build a scene in Reality Composer Pro from scratch, just add two primitives programmatically, or add two USDZ models with try? await Entity(named: String).

enter image description here

I've implemented .gesture() modifier and .targetedToEntity() modifier for each model.

import SwiftUI
import RealityKit
import RealityKitContent

struct ContentView: View {    
    @State var rotationA: Angle = .zero
    @State var rotationB: Angle = .zero
    @State var cubeA = Entity()
    @State var cubeB = Entity()
    
    var body: some View {            
        RealityView { content in
            if let scene = try? await Entity(named: "Scene", 
                                                in: realityKitContentBundle) {
                content.add(scene)
                print(scene)
            }
        } update: { content in
            if let scene = content.entities.first {
                Task {
                    cubeA = scene.findEntity(named: "Cube_A") ?? Entity()
                    cubeA.components.set(InputTargetComponent())
                    cubeA.generateCollisionShapes(recursive: false)

                    cubeB = scene.findEntity(named: "Cube_B") ?? Entity()
                    cubeB.components.set(InputTargetComponent())
                    cubeB.generateCollisionShapes(recursive: false)
                }
            }
        }
        .gesture(
            DragGesture()
                .targetedToEntity(cubeA)
                .onChanged { _ in
                    rotationA.degrees += 5.0
                    let m1 = Transform(pitch: Float(rotationA.radians)).matrix
                    let m2 = Transform(yaw: Float(rotationA.radians)).matrix
                    cubeA.transform.matrix = matrix_multiply(m1, m2)
                    // Keep starting distance between models
                    cubeA.position.x = -0.25
                }
        )
        .gesture(
            DragGesture()
                .targetedToEntity(cubeB)
                .onChanged { _ in
                    rotationB.degrees += 5.0
                    cubeB.transform = Transform(roll: Float(rotationB.radians))
                    // Keep starting distance between models
                    cubeB.position.x = 0.25
                }
        )
    }
}

The scene hierarchy looks like this:

enter image description here

enter image description here

Andy Jazz
  • 49,178
  • 17
  • 136
  • 220
  • 1
    Excellent! This works for me. The missing piece is the targetedToEntity() method. I was able to spawn entities and have independent rotation. I have to generateCollisionShapes for my entities with recursion though. – Zach Aug 03 '23 at 17:49