围绕轴旋转SCNVector3

3

这更像是一个线性代数问题,但假设我有一个SCNVector,并且我想要一个新的SCNVector,该向量围绕y轴(或任何轴)以一定角度与原始向量成角,Ideally:

extension SCNVector3 {  
    // assume dot, cross, length, +, - functions are available.
    enum Axis {
        case x, y, z
    }
    func rotatedVector(aroundAxis: Axis, angle: Float) -> SCNVector3 {
        // code from smart person goes here
    }
}

例如:(0,0,-1).rotatedVector(aroundAxis:y,angle:pi / 2)=(1,0,0)

谢谢!

3个回答

4

尝试使用四元数https://developer.apple.com/documentation/accelerate/working_with_quaternions

extension SCNVector3 {
    enum Axis {
        case x, y, z
        
        func getAxisVector() -> simd_float3 {
            switch self {
            case .x:
                return simd_float3(1,0,0)
            case .y:
                return simd_float3(0,1,0)
            case .z:
                return simd_float3(0,0,1)
            }
        }
    }

    func rotatedVector(aroundAxis: Axis, angle: Float) -> SCNVector3 {
        /// create quaternion with angle in radians and your axis
        let q = simd_quatf(angle: angle, axis: aroundAxis.getAxisVector())
        
        /// use ACT method of quaternion
        let simdVector = q.act(simd_float3(self))
        
        return SCNVector3(simdVector)
    }
}

使用:

let a = SCNVector3(5,0,0)

let b = a.rotatedVector(aroundAxis: SCNVector3.Axis.y, angle: -.pi/2)

// SCNVector3(x: 0.0, y: 0.0, z: 5.0)

你还可以围绕任何向量旋转:
let simdVector = q.act(simd_normalize(simd_float3(x: 0.75, y: 0.75, z: -0.2)))

2

一般情况下使用罗德里格旋转公式

罗德里格旋转公式是一个有效的算法,用于在给定旋转轴和旋转角度的情况下旋转空间中的向量。

对于初始向量v,旋转轴单位向量k和角度theta的结果为

vrot = v * cos(theta) + (k x v) * sin(theta) + k * (k.dot.v) * (1 - cos(theta))


这是针对右手还是左手的单元空间? - John Scalo
1
嗯...我总是用逆时针旋转角度θ来处理右手坐标系。似乎这里的左右手规则很重要,因为第二项包含向量积。但它也包含正弦函数,所以我不能确定左右手规则是否会影响结果——这取决于关于角度方向的约定。 - MBo

0

感谢gamedev.net上的评论,我想我已经得到了我需要的东西。虽然它不能适用于任意角度,但事实证明我只需要90°,所以这对我来说是有效的。以下是解决方案:

extension SCNVector3 {
    enum Axis { case x, y, z }
    enum Direction { case clockwise, counterClockwise }
    func orthogonalVector(around axis: Axis, direction: Direction) -> SCNVector3 {
        switch axis {
        case .x: return direction == .clockwise ? SCNVector3(self.x, -self.z, self.y) : SCNVector3(self.x, self.z, -self.y)
        case .y: return direction == .clockwise ? SCNVector3(-self.z, self.y, self.x) : SCNVector3(self.z, self.y, -self.x)
        case .z: return direction == .clockwise ? SCNVector3(self.y, -self.x, self.z) : SCNVector3(-self.y, self.x, self.z)
        }
    }
}

如何使用这个。 - Roshan Bade

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接