在 SceneKit 中计算 reflection/re-bounce 向量 Swift

Calc reflection/re-bounce Vector in SceneKit Swift

我尝试在 AR 会话中的 3D SceneKit space 中的特定交叉点 point/surface 计算到给定方向的反弹矢量或反射矢量。

为此,我从屏幕正中央直接发出了一个 hittest。有 i.Ex 个立方体位于我面前 2 米处。现在我想在逻辑 re-bounce/reflection 方向继续这个 hittest,就像镜子上的光线一样。当然,hittest 在其交点处结束,但我想从那里画一条线或又小又长的 SCNTube 节点,以可视化如果它被立方体的一个面反射,则该 hittest 将继续的方向.从任何特定方向来看。

比方说,我有发送命中率的方向向量。我也有最命中结果给出的交点。我在交点处有表面的法线。

关于我在线性代数论坛上找到的有关此问题的一些答案:

https://math.stackexchange.com/questions/2235997/reflecting-ray-on-triangle-in-3d-space https://math.stackexchange.com/questions/13261/how-to-get-a-reflection-vector

应该使用以下公式,而且是 3D space: (它应该给我 re-bounce/reflection 向量)

r = d − 2(d⋅n)n

(其中d⋅n是点积,n必须归一化。r是反射向量。)

我试图对它进行某种 Swift 的实现,结果是胡说八道。这是我的代码:

let location: CGPoint = screenCenter

let hits = self.sceneView.hitTest(location, options: [SCNHitTestOption.categoryBitMask: NodeCategory.catCube.rawValue, SCNHitTestOption.searchMode: SCNHitTestSearchMode.any.rawValue as NSNumber])

if !hits.isEmpty {

    print("we have a hittest")

    let d = currentDirection
    let p = hits.first?.worldCoordinates // Hit Location
    let n = hits.first?.worldNormal      // Normal of Hit Location

    print("D = \(d)")
    print("P = \(p)")
    print("N = \(n)")

    // r = d - 2*(d*n).normalized // the Formula
    let r : SCNVector3 = d - (d.crossProduct(n!).crossProduct(d.crossProduct(n!))).normalized

    // let r : SCNVector3 = d - (2 * d.crossProduct(n!).normalized) // I also tried this, but that gives me errors in Xcode

    print("R = \(r)")

    // This Function should setup then the node aligned to that new vector
    setupRay(position: p!, euler: r)


}

这一切都是废话。我得到以下控制台输出:

we are in gesture TAP recognizer
we have a hittest
D = SCNVector3(x: -0.29870644, y: 0.5494926, z: -0.7802771)
P = Optional(__C.SCNVector3(x: -0.111141175, y: 0.034069262, z: -0.62390435))
N = Optional(__C.SCNVector3(x: 2.672451e-08, y: 1.0, z: 5.3277716e-08))
R = SCNVector3(x: nan, y: nan, z: nan)
My Euler Angle: SCNVector3(x: nan, y: nan, z: nan)

(D是hittest的方向,P是交点,N是交点的法线,R应该是反射向量但总是只是nan,不是数字)

我还尝试了扩展 dotProduct 而不是 crossProduct,但是 dotProduct 给了我一个 Float 值,我无法用 SCNVector3 计算它

我如何计算这个重新反弹向量并对齐一个面向该方向的 SCNNode(在起始点的枢轴,与 hittest 的交点)

我做错了什么?任何人都可以向我展示该计算的有效 Swift 实现吗?

任何帮助都会很有帮助。 (线性代数不属于我)

PS:我使用 GitHub

提供的标准 SCNVector 3 数学扩展

SIMD library 对这样的事情非常有用:

if let hitResult = hitResults.first {
    let direction = normalize(scnView.pointOfView!.simdPosition - hitResult.simdWorldCoordinates)
    let reflectedDirection = reflect(direction, n: hitResult.simdWorldNormal)
    print(reflectedDirection)
}

最后,就我所说的 iOS 12(已成功测试)而言,此解决方案应该有效。它为您提供来自任何表面和任何视角的反射矢量。

let location: CGPoint = screenCenter

let hits = self.sceneView.hitTest(location, options: [SCNHitTestOption.categoryBitMask: NodeCategory.catCube.rawValue, SCNHitTestOption.searchMode: SCNHitTestSearchMode.any.rawValue as NSNumber])

if let hitResult = hits.first {
    let direction = normalize(double3(sceneView.pointOfView!.worldFront))
    // let reflectedDirection = reflect(direction, n: double3(hitResult.worldNormal))
    let reflectedDirection = simd_reflect(direction, double3(hitResult.worldNormal))
    print(reflectedDirection)

    // Use the Result for whatever purpose
    setupRay(position: hitResult.worldCoordinates, reflectDirection: SCNVector3(reflectedDirection))
}