我有一个具有沉浸式空间视图的应用程序,它需要用户在底部有一个按钮,该按钮在用户头部前面有一个固定位置,就像游戏中的仪表板等,但是当用户太靠近任何 3d 时视图中的对象可能会覆盖按钮并使其无法访问,这主要会阻止应用程序获得批准,就像我之前在 SceneKit 上工作的 appstoreconnect 中一样,有一些像相机视图 Znear 和 Zfar 之类的东西决定何时隐藏 3d模型是否太近或太远,我想知道在 realityView / RealityKit 4 中是否有类似的东西。这是我的代码,屏幕截图如下
import SwiftUI
import RealityKit
struct ContentView: View {
@State var myHead: Entity = {
let headAnchor = AnchorEntity(.head)
headAnchor.position = [-0.02, -0.023, -0.24]
return headAnchor
}()
@State var clicked = false
var body: some View {
RealityView { content, attachments in
// create a 3d box
let mainBox = ModelEntity(mesh: .generateBox(size: [0.1, 0.1, 0.1]))
mainBox.position = [0, 1.6, -0.3]
content.add(mainBox)
content.add(myHead)
guard let attachmentEntity = attachments.entity(for: "Dashboard") else {return}
myHead.addChild(attachmentEntity)
}
attachments: {
// SwiftUI Inside Immersivre View
Attachment(id: "Dashboard") {
VStack {
Spacer()
.frame(height: 300)
Button(action: {
goClicked()
}) {
Text(clicked ? "⏸️" : "▶️")
.frame(maxWidth: 48, maxHeight: 48, alignment: .center)
.font(.extraLargeTitle)
}
.buttonStyle(.plain)
}
}
}
}
func goClicked() {
clicked.toggle()
}
}
感谢 Apple Pro Engineer,他们提供了非常有用的答案
目前无法渲染现实视图附件,例如 它总是出现在场景中其他 3D 模型的前面。
但他们也提供了一个有用的解决方法
import SwiftUI
import RealityKit
struct ContentView: View {
@State var myHead: Entity = {
let headAnchor = AnchorEntity(.head)
headAnchor.position = [0, -0.15, -0.4]
return headAnchor
}()
// Use a model entity to act as a "dashboard" instead of an attachment.
@State var dashboardEntity: ModelEntity = {
let dashboardEntity = ModelEntity(mesh: .generateSphere(radius: 0.02), materials: [])
dashboardEntity.generateCollisionShapes(recursive: false)
dashboardEntity.components.set(InputTargetComponent())
return dashboardEntity
}()
@State var clicked = false
var clickedMaterial = SimpleMaterial(color: .green, isMetallic: false)
var unclickedMaterial = SimpleMaterial(color: .red, isMetallic: false)
var body: some View {
RealityView { content in
// create a 3d box
let mainBox = ModelEntity(mesh: .generateBox(size: [0.1, 0.1, 0.1]), materials: [SimpleMaterial()])
mainBox.position = [0, 1.6, -0.3]
content.add(mainBox)
content.add(myHead)
myHead.addChild(dashboardEntity)
// Create a model sort group for both entities.
let group = ModelSortGroup(depthPass: .postPass)
// Sort the box entity so that it is drawn first.
let mainBoxSortComponent = ModelSortGroupComponent(group: group, order: 1)
mainBox.components.set(mainBoxSortComponent)
// Sort the dashboard entity so that it is drawn second, on top of the box.
let dashboardSortComponent = ModelSortGroupComponent(group: group, order: 2)
dashboardEntity.components.set(dashboardSortComponent)
}
update: { content in
// Update the dashboard entity's material when the value of `clicked` changes.
dashboardEntity.model?.materials = clicked ? [clickedMaterial] : [unclickedMaterial]
}
.gesture(
TapGesture()
.targetedToEntity(dashboardEntity)
.onEnded({ value in
// Toggle `clicked` when the dashboard entity is tapped.
clicked.toggle()
})
)
}
}