🕶️
visionOS Tips: 透明なタップ対象Entity
表示しているEntityではなく、もっと広い範囲をタップ対象領域にしたい時や、Attachmentなど他の表示と被ってしまう際に任意の場所をタップ対象にしたい事があります。
そんな場合のために空間に透明なタップ対象Entityを配置する実装です。
画像
タップ領域が透過していてタップ対象ではないCubeが見えている状態
タップ領域(仮で青く色付け)が非透過でCubeが隠れている状態
実装
import SwiftUI
import RealityKit
struct ImmersiveView: View {
@Environment(AppModel.self) private var appModel
var body: some View {
RealityView { content in
let cube: Entity = {
let entity = Entity()
entity.name = "cubeA"
let model = ModelComponent(mesh: .generateBox(size: 0.2), materials: [SimpleMaterial(color: .orange, isMetallic: false)])
entity.components.set(model)
entity.position = [0.0, 1.2, -1.0]
return entity
}()
content.add(cube)
let tapTarget: Entity = {
let entity = Entity()
entity.name = "tapTarget"
let model = ModelComponent(mesh: .generateSphere(radius: 0.2), materials: [makeMaterial(isTransparent: true)])
entity.components.set(model)
entity.components.set(InputTargetComponent())
entity.components.set(CollisionComponent(shapes: [.generateSphere(radius: 0.2)]))
entity.position = [0.0, 1.2, -1.0]
return entity
}()
content.add(tapTarget)
} update: { content in
if let tapTarget = content.entities.first(where: { $0.name == "tapTarget" }),
var modelComponent = tapTarget.components[ModelComponent.self] {
modelComponent.materials = [makeMaterial(isTransparent: appModel.isTransparent)]
tapTarget.components.set(modelComponent)
}
}
.gesture(
SpatialEventGesture()
.targetedToAnyEntity()
.onEnded { value in
print("Tap called.")
}
)
.padding()
}
private func makeMaterial(isTransparent: Bool) -> UnlitMaterial {
if isTransparent {
var material = UnlitMaterial(color: .clear)
material.blending = .transparent(opacity: PhysicallyBasedMaterial.Opacity(floatLiteral: 1.0))
material.faceCulling = .front
return material
} else {
var material = UnlitMaterial(color: .blue)
material.blending = .opaque
material.faceCulling = .none
return material
}
}
}
Discussion