How to move a rotated SCNNode in SceneKit?

喜欢而已 提交于 2019-12-01 04:21:21

So my understanding is that you want to move the Box Node along its own X axis (not it's parents X axis). And because the Box Node is rotated, its X axis is not aligned with its parent's one, so you have the problem to convert the translation between the two coordinate systems.

The node hierarchy is

parentNode
    |
    |----boxNode // rotated around Y (vertical) axis

Using Transformation Matrices

To move boxNode along its own X axis

// First let's get the current boxNode transformation matrix
SCNMatrix4 boxTransform = boxNode.transform;

// Let's make a new matrix for translation +2 along X axis
SCNMatrix4 xTranslation = SCNMatrix4MakeTranslation(2, 0, 0);

// Combine the two matrices, THE ORDER MATTERS !
// if you swap the parameters you will move it in parent's coord system
SCNMatrix4 newTransform = SCNMatrix4Mult(xTranslation, boxTransform);

// Allply the newly generated transform
boxNode.transform = newTransform;

Please Note: The order matters when multiplying matrices

Another option:

Using SCNNode coordinate conversion functions, looks more straight forward to me

// Get the boxNode current position in parent's coord system
SCNVector3 positionInParent = boxNode.position;

// Convert that coordinate to boxNode's own coord system
SCNVector3 positionInSelf = [boxNode convertPosition:positionInParent fromNode:parentNode];

// Translate along own X axis by +2 points
positionInSelf = SCNVector3Make(positionInSelf.x + 2,
                                positionInSelf.y,
                                positionInSelf.z);

// Convert that back to parent's coord system
positionInParent = [parentNode convertPosition: positionInSelf fromNode:boxNode];

// Apply the new position
boxNode.position = positionInParent;

Building on @Sulevus's correct answer, here's an extension to SCNNode that simplifies things by using the convertVector rather than the convertPosition transformation, in Swift.

I've done it as a var returning a unit vector, and supplied an SCNVector3 overload of multiply so you can say things like

let action = SCNAction.move(by: 2 * cameraNode.leftUnitVectorInParent, duration: 1)


public extension SCNNode {
    var leftUnitVectorInParent: SCNVector3 {
        let vectorInSelf = SCNVector3(x: 1, y: 0, z: 0)
        guard let parent = self.parent else { return vectorInSelf }
        // Convert to parent's coord system
        return parent.convertVector(vectorInSelf, from: self)
    }
    var forwardUnitVectorInParent: SCNVector3 {
        let vectorInSelf = SCNVector3(x: 0, y: 0, z: 1)
        guard let parent = self.parent else { return vectorInSelf }
        // Convert to parent's coord system
        return parent.convertVector(vectorInSelf, from: self)
    }

    func *(lhs: SCNVector3, rhs: CGFloat) -> SCNVector3 {
        return SCNVector3(x: lhs.x * rhs, y: lhs.y * rhs, z: lhs.z * rhs)
    }
    func *(lhs: CGFloat, rhs: SCNVector3) -> SCNVector3 {
        return SCNVector3(x: lhs * rhs.x, y: lhs * rhs.y, z: lhs * rhs.z)
    }
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!