Machineboy空
RealityKit - CollisionGroup과 Collision Filter를 알아보자! 본문
오늘의 구현

모드에 따라 제스처가 가능한 레이어를 구분하고 싶다!
즉, 큐브모드에서는 큐브에만 제스처가 적용이 되고, 구를 눌러도 아무런 제스처를 취할 수 없으며
구 모드에서는 구에만 제스처가 적용이 되게 하고 싶다.
arView.installGestures([.all], for: cubeModel)
arView.installGestures([], for: cubeModel)
단순히 installGestures에 빈배열을 할당하는 것으로 제스처가 해제되지 않더라.
Unity의 LayerMask와 같은 개념이 RealityKit의 CollisionFilter인듯한데 한번 살펴보자!
CollisionFilter

A set of masks that determine whether entities can collide during simulations
실행 중에 엔티티가 서로 충돌할 수 있는지 결정하는 mask.
Use Collision filters in combination with collision groups to define which entities collide with which other entities in a scene.
collision Group과 함께 쓰여 서로 충돌할 수 있는 그룹인지 결정한다.
Group과 mask
- group: 엔티티가 속한 그룹
- mask: 엔티티가 충돌할 수 있는 그룹, 어떤 객체와 충돌할지 정의
//예시 1. A는 C와 충돌하지만 B와는 충돌하지 않는다.
let groupA = CollisionGroup(rawValue: 1 << 0)
let groupB = CollisionGroup(rawValue: 1 << 1)
let groupC = CollisionGroup(rawValue: 1 << 2)
let theFilter = CollisionFilter(group: groupA, mask: groupA.union(groupC))
// 예시 2. 모든 그룹과 충돌하되 groupB와는 충돌하지 않는다
let notGroupB = CollisionGroup.all.subtracting(groupB)
https://developer.apple.com/documentation/realitykit/collisionfilter
CollisionFilter | Apple Developer Documentation
A set of masks that determine whether entities can collide during simulations.
developer.apple.com
CollisionGroup

You use collision groups along with `CollisionFilter` to define custom collision properties for entities in your scene and controlling which entities collide wit which other entities.
CollisionGroup은 CollisionFilter와 함께 사용되어, 장면 내 엔티티들 간의 충돌 규칙을 정의할 수 있다. 이를 통해 어떤 엔티티가 다른 엔티티와 충돌할지 제어할 수 있다.
// 예시: Red팀 player가 같은 red팀과는 충돌하지 않게 하기 위한 설정
let redGroup = CollisionGroup(rawValue: 1<< 0)
let allButRedGroup = CollisionGroup.all.subtracting(redGroup)
let allButRedFilter = CollisionFilter(group: redGroup, mask: allButRedGroup)
redTeamPlayer1.collision?.filter = allButRedFilter
https://developer.apple.com/documentation/realitykit/collisiongroup
CollisionGroup | Apple Developer Documentation
A bitmask used to define the collision group to which an entity belongs.
developer.apple.com
// sphereModel은 sphereGroup이라는 CollisionGroup에 속하고, 모든 것과 충돌 가능하다.
sphereModel.collision?.filter = CollisionFilter(group: sphereGroup, mask: .all)
// cubeModel은 cubeGroup이라는 CollisionGroup에 속하고, 그 아무 것도 충돌 불가능하다.
cubeModel.collision?.filter = CollisionFilter(group: boxGroup, mask: [])
내가 만든 샘플코드
import SwiftUI
import ARKit
import RealityKit
// CollisionGroup
let boxGroup = CollisionGroup(rawValue: 1 << 0)
let sphereGroup = CollisionGroup(rawValue: 1 << 1)
struct CollisionFilterTest: View {
@State var currentItem: String = "cube"
var body: some View {
ZStack {
ARCollisionViewContainer(currentItem: $currentItem)
.ignoresSafeArea()
VStack {
Spacer()
HStack(spacing: 30) {
Button(action: {
currentItem = "cube"
}) {
Image(systemName: "cube.fill")
.resizable()
.frame(width: 70, height: 70)
.foregroundColor(currentItem == "cube" ? .orange : .gray)
}
Button(action: {
currentItem = "sphere"
}) {
Image(systemName: "tennisball.fill")
.resizable()
.frame(width: 70, height: 70)
.foregroundColor(currentItem == "sphere" ? .blue : .gray)
}
}
.padding()
}
}
}
}
struct ARCollisionViewContainer: UIViewRepresentable {
@Binding var currentItem: String
func makeUIView(context: Context) -> ARView {
let arView = ARView(frame: .zero, cameraMode: .nonAR, automaticallyConfigureSession: false)
arView.environment.background = .color(.white)
// MARK: Cube
let cubeMaterial = SimpleMaterial(color: .orange, isMetallic: false)
let cubeMesh = MeshResource.generateBox(size: 1)
let cubeModel = ModelEntity(mesh: cubeMesh, materials: [cubeMaterial])
cubeModel.generateCollisionShapes(recursive: true)
let cubeAnchor = AnchorEntity(world: [-1, 0, 0])
cubeAnchor.addChild(cubeModel)
arView.scene.anchors.append(cubeAnchor)
// MARK: Sphere
let sphereMaterial = SimpleMaterial(color: .blue, isMetallic: false)
let sphereMesh = MeshResource.generateSphere(radius: 0.5)
let sphereModel = ModelEntity(mesh: sphereMesh, materials: [sphereMaterial])
sphereModel.generateCollisionShapes(recursive: true)
let sphereAnchor = AnchorEntity(world: [1, 0, 0])
sphereAnchor.addChild(sphereModel)
arView.scene.anchors.append(sphereAnchor)
context.coordinator.cubeModel = cubeModel
context.coordinator.sphereModel = sphereModel
// MARK: Camera
let camera = PerspectiveCamera()
camera.position = [0, 7, 7]
camera.look(at: [0, 0, 0], from: camera.position, relativeTo: nil)
let cameraAnchor = AnchorEntity(world: [0, 0, 0])
cameraAnchor.addChild(camera)
arView.scene.addAnchor(cameraAnchor)
// Install initial gestures
arView.installGestures([.all], for: cubeModel)
arView.installGestures([], for: sphereModel)
context.coordinator.arView = arView
return arView
}
func updateUIView(_ arView: ARView, context: Context) {
context.coordinator.updateGestures(for: currentItem)
}
func makeCoordinator() -> Coordinator {
Coordinator()
}
class Coordinator {
var cubeModel: ModelEntity?
var sphereModel: ModelEntity?
var arView: ARView?
func updateGestures(for currentItem: String) {
guard let arView = arView, let cubeModel = cubeModel, let sphereModel = sphereModel else { return }
switch currentItem {
case "cube":
arView.installGestures([.all], for: cubeModel)
cubeModel.collision?.filter = CollisionFilter(group: boxGroup, mask: .all)
sphereModel.collision?.filter = CollisionFilter(group: sphereGroup, mask: [])
case "sphere":
arView.installGestures([.all], for: sphereModel)
sphereModel.collision?.filter = CollisionFilter(group: sphereGroup, mask: .all)
cubeModel.collision?.filter = CollisionFilter(group: boxGroup, mask: [])
default:
break
}
}
}
}
#Preview {
CollisionFilterTest()
}
'언어 > iOS' 카테고리의 다른 글
ARView 스냅샷, 캡처 함수 (0) | 2024.12.17 |
---|---|
RealityKit - Plane에 벡터이미지 texture 적용하기, UnlitMaterial, opacityThreshold (1) | 2024.11.12 |
RealityKit - TextField에 입력한 글자를 3D Entity로 출력하기! (0) | 2024.11.11 |
RealityKit의 Gesture를 살펴보자 - Pan, Rotate (0) | 2024.11.11 |
RealityKit의 Gesture를 살펴보자 - Pinch, Scale (0) | 2024.11.11 |