说明
SCNNode对象中有三组转换方法,不考虑 from 和 to 的区别,分别是:位置、向量和矩阵
// 位置转换(即坐标转换)
open func simdConvertPosition(_ position: simd_float3, to node: SCNNode?) -> simd_float3
open func simdConvertPosition(_ position: simd_float3, from node: SCNNode?) -> simd_float3
// 向量转换(即方向转换)
open func simdConvertVector(_ vector: simd_float3, to node: SCNNode?) -> simd_float3
open func simdConvertVector(_ vector: simd_float3, from node: SCNNode?) -> simd_float3
// 矩阵转换(即位置、方向、缩放都进行转换)
open func simdConvertTransform(_ transform: simd_float4x4, to node: SCNNode?) -> simd_float4x4
open func simdConvertTransform(_ transform: simd_float4x4, from node: SCNNode?) -> simd_float4x4
那么它们的几何意义是什么?数学计算公式又是什么?和基变换 又有什么区别呢?
基变换
当我们看到 这样的矩阵乘法时,就应该明白这就是基变换。
详细解释推荐看下面的文章和视频:
zhuanlan.zhihu.com/p/69069042
www.bilibili.com/video/av673…
通俗的讲,基变换的含义就是:换个角度看过程。我们用地图来做个简单说明:
- 从合肥出发到北京,只需要一路向北就行了;
- 从合肥出发到上海,只需要一路向东就行了;
- 现在问题来了:如何从上海的角度,描述合肥到北京的过程?
- 答:在上海看来,从上海的正西方出发,向上海的西北方向前进;
这就是基变换的含义,合肥就是原始的基,上海是新的基,而从合肥出发到北京的过程,就是待变换的矩阵。
而不管怎么变换,整个过程只是换个角度来描述,开始和结束并没有变化。也可以理解成:基变换就是将 1+1=2 这个公式,从英语翻译成汉语,描述方式变了,但意义没有变。
convert 方法的含义
而 convert 方法的含义与基变换并不相同。同样用地图表示:
- 从合肥出发到北京,只需要一路向北就行了;
- 从合肥出发到上海,只需要一路向东就行了;
- 现在问题来了:如何从上海的角度,描述上海到北京的过程?
- 答:从上海出发,向上海的西北方向前进;
这就是 convert 方法的含义,最终都是到北京,但转换前是从合肥出发,转换后就成了从上海出发。
需要注意的是,convertVector 方法与 convertPosition 方法不同。苹果官方文档进行了说明,向量的转换会忽略平移: developer.apple.com/documentati…
具体公式
所以 convert 方法的计算公式实际上就是 。
我们来写个代码验证一下:
// 新的原点
let newWorldOrigin = SCNNode(geometry: SCNBox(width: 0.1, height: 0.1, length: 0.1, chamferRadius: 0))
newWorldOrigin.simdPosition = simd_float3(repeating: 1)
newWorldOrigin.simdScale = simd_float3(repeating: 2)
newWorldOrigin.geometry?.firstMaterial?.diffuse.contents = UIColor.red
scene.rootNode.addChildNode(newWorldOrigin)
// 要进行变换的目标节点
let target = SCNNode(geometry: SCNBox(width: 0.1, height: 0.1, length: 0.1, chamferRadius: 0))
target.simdPosition = simd_float3(repeating: 3)
target.geometry?.firstMaterial?.diffuse.contents = UIColor.green
scene.rootNode.addChildNode(target)
具体的转换方法如下:
func simdConvertTransform(_ transform: simd_float4x4, to newWorldOrigin: simd_float4x4) -> simd_float4x4 {
return simd_mul(simd_inverse(newWorldOrigin), transform)
}
func simdConvertPosition(_ position: simd_float3, to newWorldOrigin: simd_float4x4) -> simd_float3 {
let newPosition = simd_mul(simd_inverse(newWorldOrigin), simd_float4(position, 1))
return simd_float3(x: newPosition.x, y: newPosition.y, z: newPosition.z)
}
func simdConvertVector(_ vector: simd_float3, to newWorldOrigin: simd_float4x4) -> simd_float3 {
let newVector = simd_mul(simd_inverse(newWorldOrigin), simd_float4(vector, 0))
return simd_float3(x: newVector.x, y: newVector.y, z: newVector.z)
}
func simdConvertTransform(_ transform: simd_float4x4, from newWorldOrigin: simd_float4x4) -> simd_float4x4 {
return simd_mul(newWorldOrigin, transform)
}
func simdConvertPosition(_ position: simd_float3, from newWorldOrigin: simd_float4x4) -> simd_float3 {
let newPosition = simd_mul(newWorldOrigin, simd_float4(position, 1))
return simd_float3(x: newPosition.x, y: newPosition.y, z: newPosition.z)
}
func simdConvertVector(_ vector: simd_float3, from newWorldOrigin: simd_float4x4) -> simd_float3 {
let newVector = simd_mul(newWorldOrigin, simd_float4(vector, 0))
return simd_float3(x: newVector.x, y: newVector.y, z: newVector.z)
}
对比测试方法如下:
// target 的矩阵在 newWorldOrigin 中,是怎样的变换
let tInNewWorld = target.simdConvertTransform(matrix_identity_float4x4, to: newWorldOrigin)
// newWorldOrigin 中的一个变换(假定用target.simdTransform),在真实世界原点中的变换
let tInRealWorld = newWorldOrigin.simdConvertTransform(target.simdTransform, to: nil)
// target 的position在 newWorldOrigin 中,是什么
let pInNewWorld = target.simdConvertPosition(simd_float3(repeating: 0), to: newWorldOrigin)
// newWorldOrigin 中的一个位置(假定用target.simdPosition),在真实世界原点中的位置
let pInRealWorld = newWorldOrigin.simdConvertPosition(target.simdPosition, to: nil)
// target 的 vector 在 newWorldOrigin 中,是什么
let vInNewWorld = target.simdConvertVector(target.simdPosition, to: newWorldOrigin)
// newWorldOrigin 的 vector 在真实世界坐标中,是什么
let vInRealWorld = newWorldOrigin.simdConvertVector(target.simdPosition, to: nil)
// 对比测试
let tInNewWorld_my = simdConvertTransform(target.simdTransform, to: newWorldOrigin.simdTransform)
let tInRealWord_my = simdConvertTransform(target.simdTransform, from: newWorldOrigin.simdTransform)
let pInNewWorld_my = simdConvertPosition(target.simdPosition, to: newWorldOrigin.simdTransform)
let pInRealWord_my = simdConvertPosition(target.simdPosition, from: newWorldOrigin.simdTransform)
let vInNewWorld_my = simdConvertVector(target.simdPosition, to: newWorldOrigin.simdTransform)
let vInRealWord_my = simdConvertVector(target.simdPosition, from: newWorldOrigin.simdTransform)
结果对比是完全一致的,说明我们的理解是正确的,计算过程也是正确的: