Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rotate SCNVector3 around an axis

This is probably more of a linear algebra question, but say I have a SCNVector and I want a new SCNVector that's at an angle to the original around the y axis (or any axis for that matter). So 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
    }
}

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

Thanks!

like image 990
John Scalo Avatar asked Oct 26 '25 08:10

John Scalo


2 Answers

Try to use quaternions 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)
    }
}

Use:

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)

Also you can rotate around any vector:

let simdVector = q.act(simd_normalize(simd_float3(x: 0.75, y: 0.75, z: -0.2)))
like image 93
OLEKSII DEV Avatar answered Oct 29 '25 06:10

OLEKSII DEV


In general case use Rodrigues' rotation formula.

Rodrigues' rotation formula is an efficient algorithm for rotating a vector in space, given an axis and angle of rotation

For initial vector v, rotation axis unit vector k and angle theta result is

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

like image 21
MBo Avatar answered Oct 29 '25 06:10

MBo



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!