How to move a rotated SCNNode in SceneKit?

前端 未结 2 1982
野性不改
野性不改 2021-01-12 14:32

The image below shows a rotated box that should be moved horizontally on the X and Z axes. Y should stay unaffected to simplify the scenario. The box could also be the SCNNo

相关标签:
2条回答
  • 2021-01-12 14:38

    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)
        }
    }
    
    0 讨论(0)
  • 2021-01-12 14:43

    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;
    
    0 讨论(0)
提交回复
热议问题