8de7b8bc5fa9c7b1a5eff636791ec674
SCNNode 中 convert 方法与基变换的关系

说明

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

那么它们的几何意义是什么?数学计算公式又是什么?和基变换 $A^{-1}MA$ 又有什么区别呢?

基变换

当我们看到 $A^{-1}MA$ 这样的矩阵乘法时,就应该明白这就是基变换。
详细解释推荐看下面的文章和视频:
https://zhuanlan.zhihu.com/p/69069042
https://www.bilibili.com/video/av6731067/?p=13

通俗的讲,基变换的含义就是:换个角度看过程。我们用地图来做个简单说明:

  • 从合肥出发到北京,只需要一路向北就行了;
  • 从合肥出发到上海,只需要一路向东就行了;
  • 现在问题来了:如何从上海的角度,描述合肥到北京的过程?
  • 答:在上海看来,从上海的正西方出发,向上海的西北方向前进;

这就是基变换的含义,合肥就是原始的基,上海是新的基,而从合肥出发到北京的过程,就是待变换的矩阵。

而不管怎么变换,整个过程只是换个角度来描述,开始和结束并没有变化。也可以理解成:基变换就是将 1+1=2 这个公式,从英语翻译成汉语,描述方式变了,但意义没有变。

convert 方法的含义

而 convert 方法的含义与基变换并不相同。同样用地图表示:

  • 从合肥出发到北京,只需要一路向北就行了;
  • 从合肥出发到上海,只需要一路向东就行了;
  • 现在问题来了:如何从上海的角度,描述上海到北京的过程?
  • 答:从上海出发,向上海的西北方向前进;

这就是 convert 方法的含义,最终都是到北京,但转换前是从合肥出发,转换后就成了从上海出发。

需要注意的是,convertVector 方法与 convertPosition 方法不同。苹果官方文档进行了说明,向量的转换会忽略平移:
https://developer.apple.com/documentation/scenekit/scnnode/2881850-simdconvertvector

具体公式

所以 convert 方法的计算公式实际上就是 $A^{-1}M$ 。
我们来写个代码验证一下:
```swift
// 新的原点
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)

top Created with Sketch.