在Swift-Scene Kit中开始识别触摸立方体的面部

Nis*_*ula 4 hittest scenekit

我想用Scene套件创建一个应用来解决Rubix Cube.我有自己的dae文件用于多维数据集.接触开始后,我有被击中的物体

  func tapGesture(sender: UITapGestureRecognizer){

    // check what nodes are tapped
    var p = sender.locationInView(sceneView)
    var hitResults = sceneView.hitTest(p, options: nil)
    if hitResults.count > 0
    {

        var hitnode = (hitResults.first)!.node
        print("\nName of node hit is \(hitnode.name)")

        //var indexvalue = hitResults.first?.faceIndex
        //print(indexvalue)
    }
  }
Run Code Online (Sandbox Code Playgroud)

如何确切地找到立方体的哪个面?

ric*_*ter 8

faceIndex看起来很有希望,但实际上并没有得到你认为有用的东西.由该属性计算的"面"是网格的细分,因此立方体不是六个四边形的集合,它将是十二个三角形.(或者更多:在某些情况下,即使是平面的立方体也会被镶嵌,每边有多个四边形/两个三角形.如果你使用的SCNBox话,你可以控制它们widthSegmentCount等等)

相反 - 特别是如果您的多维数据集是SCNBox- 最简单的解决方案可能是利用该类的这种有趣的行为:

您最多可以SCNMaterial为一个盒子分配六个实例,每个实例都有一个materials属性.的SCNBox类自动创建SCNGeometryElement作为需要处理的材料的数量的对象.

所以,如果你分配了六种材料,你会得到一面:

let front = SCNMaterial()
let right = SCNMaterial()
let back = SCNMaterial()
let left = SCNMaterial()
let top = SCNMaterial()
let bottom = SCNMaterial()
cube.materials = [ front, right, back, left, top, bottom ]
Run Code Online (Sandbox Code Playgroud)

在这样做时,您SCNBox将拥有六个几何元素 - 每个材质一个,对应于每一个一个.

现在,您可以使用命中测试来找出单击的几何元素:

if let result = hitResults.first {
    let node = result.node

    // Find the material for the clicked element
    // (Indices match between the geometryElements and materials arrays)
    let material = node.geometry!.materials[result.geometryIndex]

    // Do something with that material, for example:
    let highlight = CABasicAnimation(keyPath: "diffuse.contents")
    highlight.toValue = NSColor.redColor()
    highlight.duration = 1.0
    highlight.autoreverses = true
    highlight.removedOnCompletion = true
    material.addAnimation(highlight, forKey: nil)
}
Run Code Online (Sandbox Code Playgroud)

或者,如果你没有突出显示并想要使用面部索引进行逻辑,那么这里可以使用以下内容的开头:

enum CubeFace: Int {
    case Front, Right, Back, Left, Top, Bottom
}

// when processing hit test result:
print("hit face: \(CubeFace(rawValue: result.geometryIndex))")
Run Code Online (Sandbox Code Playgroud)


Cra*_*lot 5

我们使用此函数根据 中的localNormal值来确定面部命中SCNHitResult

如果轴的大小为 1,则此函数得出结论,面已被击中。

它假设只有一个轴的大小等于 1。否则代码将会崩溃。它还假定 SCNBox 几何形状。

在测试中,这似乎有效(对于 SCNBox 几何形状)。唯一的复杂之处是该localNormal值并不总是返回干净的 0 值。有时它会返回类似 -5.96046448e-08 的值,因此我们使用该round函数是为了安全,以防同样的情况适用于接近 1 但不完全是 1 的值。

一般来说,我们对 SceneKit 和 3D 还很陌生,因此代码可能存在缺陷。如果您发现问题或潜在的优化,请发表评论。

private func getHitFaceFromNormal(normal: SCNVector3) {
    if round(normal.x) == -1 {
        // Left face hit
    } else if round(normal.x) == 1 {
        // Right face hit
    } else if round(normal.y) == -1 {
        // Bottom face hit
    } else if round(normal.y) == 1 {
        // Top face hit
    } else if round(normal.z) == -1 {
        // Back face hit
    } else if round(normal.z) == 1 {
        // Front face hit
    } else {
        // Error, no face detected
    }
}
Run Code Online (Sandbox Code Playgroud)