在 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))
}
我尝试在 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))
}