You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

VisionOS中如何在Compositor Layer内使用手势?

问题翻译

我用Metal渲染场景,将自定义渲染器传入CompositorLayer,想要实现类似这样的手势交互:

.onTapGesture {
    print("test")
}

目前的问题是无法把CompositorLayer包裹在视图中,因此没法使用SwiftUI的手势API。我该如何获取手势API的访问权限?理想情况下,希望场景里的模型/网格能像普通视图一样响应手势。

当前代码示例:

ImmersiveSpace(id: "ImmersiveSpace") {
    CompositorLayer(configuration: ContentStageConfiguration()) { layerRenderer in
        let renderer = Renderer(layerRenderer)
        Context.render.layerRenderer = layerRenderer
        Context.state.scene = GameScene()
        renderer.startRenderLoop()
    }
}.immersionStyle(selection: .constant(.full), in: .full)

我理想的代码结构类似这样:

struct Model {
    onTapGesture() {
        
    }
}

解决方法

方法1:用UIViewRepresentable包装CompositorLayer,接入SwiftUI手势

CompositorLayer本身无法直接添加SwiftUI修饰符,但可以通过UIViewRepresentable将其包装成SwiftUI可识别的视图,从而使用手势API。

示例代码:

struct CompositorLayerView: UIViewRepresentable {
    func makeUIView(context: Context) -> UIView {
        let view = UIView()
        // 初始化CompositorLayer并关联到视图层
        let compositorLayer = CompositorLayer(configuration: ContentStageConfiguration()) { layerRenderer in
            let renderer = Renderer(layerRenderer)
            Context.render.layerRenderer = layerRenderer
            Context.state.scene = GameScene()
            renderer.startRenderLoop()
        }
        view.layer.addSublayer(compositorLayer)
        compositorLayer.frame = view.bounds
        return view
    }
    
    func updateUIView(_ uiView: UIView, context: Context) {
        // 按需添加视图更新逻辑
    }
}

// 在ImmersiveSpace中使用包装后的视图
ImmersiveSpace(id: "ImmersiveSpace") {
    CompositorLayerView()
        .onTapGesture {
            print("触发点击手势")
        }
}.immersionStyle(selection: .constant(.full), in: .full)

方法2:结合Metal射线检测,实现模型级手势响应

如果需要精确到单个模型/网格的手势交互,仅靠视图级手势不够,得结合Metal的射线检测逻辑:

  1. 在SwiftUI中捕获触摸手势的屏幕坐标,传递给Metal渲染器
  2. 在渲染器中将屏幕坐标转换为3D射线
  3. 遍历场景模型,用射线与模型的包围盒/网格做碰撞检测
  4. 检测到碰撞后执行对应逻辑

示例代码片段:

// SwiftUI端捕获手势并传递坐标
CompositorLayerView()
    .onTapGesture(coordinateSpace: .global) { location in
        Context.render.handleTap(at: location)
    }

// Metal渲染器中的处理逻辑
class Renderer {
    func handleTap(at screenLocation: CGPoint) {
        // 将屏幕坐标转换为3D射线(需结合相机的投影、视图矩阵实现)
        let ray = createRay(from: screenLocation)
        
        // 遍历场景模型做碰撞检测
        for model in Context.state.scene.models {
            if ray.intersects(model.boundingBox) {
                model.handleTap()
                break
            }
        }
    }
    
    private func createRay(from screenPoint: CGPoint) -> Ray {
        // 实现屏幕坐标转射线的具体逻辑(根据你的相机设置调整)
        return Ray(origin: ..., direction: ...)
    }
}

// 模型结构体(符合你的理想结构)
struct Model {
    var name: String
    var boundingBox: BoundingBox
    
    // 模型自身的点击处理方法
    func handleTap() {
        print("\(name)被点击")
    }
}

方法3:直接给底层视图添加UIKit手势识别器

在UIViewRepresentable的makeUIView方法中,给承载CompositorLayer的UIView添加UIKit原生手势识别器:

struct CompositorLayerView: UIViewRepresentable {
    func makeUIView(context: Context) -> UIView {
        let view = UIView()
        // 添加UIKit点击手势识别器
        let tapGesture = UITapGestureRecognizer(target: context.coordinator, action: #selector(Coordinator.handleTap))
        view.addGestureRecognizer(tapGesture)
        
        // 初始化CompositorLayer
        let compositorLayer = CompositorLayer(configuration: ContentStageConfiguration()) { layerRenderer in
            let renderer = Renderer(layerRenderer)
            Context.render.layerRenderer = layerRenderer
            Context.state.scene = GameScene()
            renderer.startRenderLoop()
        }
        view.layer.addSublayer(compositorLayer)
        compositorLayer.frame = view.bounds
        return view
    }
    
    func makeCoordinator() -> Coordinator {
        Coordinator()
    }
    
    class Coordinator: NSObject {
        @objc func handleTap() {
            print("UIKit点击手势触发")
            // 可在此通知渲染器处理模型级点击
            Context.render.handleTap()
        }
    }
    
    func updateUIView(_ uiView: UIView, context: Context) {}
}

内容的提问来源于stack exchange,提问作者Luke Xu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 21:04:54