有一个名为SCNNode
的{{1}}类别,它声明了一些属性,如SCNNode(SIMD)
,simdPosition
等。看起来这些是原始/普通属性simdRotation
和position
的重复属性。
rotation
@property(nonatomic) simd_float3 simdPosition API_AVAILABLE(macos(10.13), ios(11.0), tvos(11.0), watchos(4.0));
@property(nonatomic) simd_float4 simdRotation API_AVAILABLE(macos(10.13), ios(11.0), tvos(11.0), watchos(4.0));
和position
之间有什么区别?前缀“simd”究竟是什么意思?
答案 0 :(得分:48)
SIMD说明允许您在同时对多个值执行相同的操作。
让我们看一个例子
我们有这4个Int32值
let x0: Int32 = 10
let y0: Int32 = 20
let x1: Int32 = 30
let y1: Int32 = 40
现在我们想要将2 x
和2 y
值相加,所以我们写了
let sumX = x0 + x1 // 40
let sumY = y0 + y1 // 60
为了执行前一个sums
,CPU需要
- 在内存中加载x0和x1并添加它们
- 在内存中加载y0和y1并添加它们
醇>
所以结果是通过2次操作获得的。
我创建了一些图片来更好地向您展示这个想法
第1步
第2步
现在让我们看看SIMD是如何工作的。 首先,我们需要以正确的SIMD格式存储输入值
let x = simd_int2(10, 20)
let y = simd_int2(30, 40)
您可以看到之前的x
和y
是向量。事实上,x
和y
都包含2个组件。
现在我们可以写
let sum = x + y
让我们看看CPU为执行前面的操作所做的工作
- 在内存中加载x和y并添加它们
醇>
就是这样!
x
的两个组成部分和y
的两个组成部分同时处理。
我们不谈论并发编程,而是真正的并行编程。
正如您在某些操作中可以想象的那样,SIMD方法比串行方法快得多。
现在让我们看一下SceneKit中的一个例子
我们希望将10
添加到场景节点的所有直接后代的x
,y
和z
组件中。
使用经典的连续方法,我们可以写
for node in scene.rootNode.childNodes {
node.position.x += 10
node.position.y += 10
node.position.z += 10
}
这里执行了总共
childNodes.count * 3
个操作。
现在让我们看看我们如何在SIMD指令中转换以前的代码
let delta = simd_float3(10)
for node in scene.rootNode.childNodes {
node.simdPosition += delta
}
此代码比前一代码快得多。我不确定2倍或3倍的速度,但相信我,它会更好。
如果您需要对不同的值执行多次相同的操作,只需使用SIMD属性:)
答案 1 :(得分:7)
SIMD是一个建立在vector types之上的小型库,您可以从<simd/simd.h>
导入。它允许更具表现力和更高性能的代码。
例如,使用SIMD,您可以写
simd_float3 result = a + 2.0 * b;
而不是
SCNVector3 result = SCNVector3Make(a.x + 2.0 * b.x, a.y + 2.0 * b.y, a.z + 2.0 * b.z);
在Objective-C中,您不能重载方法。那就是你不能同时拥有两者
@property(nonatomic) SCNVector3 position;
@property(nonatomic) simd_float3 position API_AVAILABLE(macos(10.13), ios(11.0), tvos(11.0), watchos(4.0));
新的基于SIMD的API需要一个不同的名称,这就是SceneKit公开simdPosition
的原因。