将多次旋转应用于ARKit SCNNode

时间:2019-01-08 20:36:00

标签: swift scenekit linear-algebra arkit

我正在使用一个AR应用程序,该应用程序使用Apple的Focus Square来指导用户在垂直和水平表面上的交互。但是,它仅设计为在水平表面上工作。我已经修改了更新正方形旋转以反映垂直表面的方法。但是,使用他们一次只旋转一圈的方法,而为了使正方形正确定位在水平面上,我需要进行两次旋转(一个旋转用于应用原始偏航校正,另一个旋转用于垂直调整正方形)。

相关代码在下面,但是我所做的具体更改仅在开始和结束处。

// MARK: - Appearence

func update(for position: float3, planeAnchor: ARPlaneAnchor?, camera: ARCamera?) {
    lastPosition = position

    let thisAlignment = planeAnchor?.alignment ?? .horizontal
    if thisAlignment != lastAlignment {
        lastAlignment = thisAlignment
        print("alignmentChanged")
        recentFocusSquarePositions = []
    }

    if let anchor = planeAnchor {
        close(flash: !anchorsOfVisitedPlanes.contains(anchor))
        lastPositionOnPlane = position
        anchorsOfVisitedPlanes.insert(anchor)
    } else {
        open()
    }
    updateTransform(for: position, alignment: thisAlignment, camera: camera)
}

private func updateTransform(for position: float3, alignment: ARPlaneAnchor.Alignment, camera: ARCamera?) {
    // add to list of recent positions
    recentFocusSquarePositions.append(position)

    // remove anything older than the last 8
    recentFocusSquarePositions.keepLast(8)

    // move to average of recent positions to avoid jitter
    if let average = recentFocusSquarePositions.average {
        self.simdPosition = average
        self.setUniformScale(scaleBasedOnDistance(camera: camera))
    }

    // Correct y rotation of camera square
    if let camera = camera {
        let tilt = abs(camera.eulerAngles.x)
        let threshold1: Float = .pi / 2 * 0.65
        let threshold2: Float = .pi / 2 * 0.75
        let yaw = atan2f(camera.transform.columns.0.x, camera.transform.columns.1.x)
        var angle: Float = 0

        switch tilt {
        case 0..<threshold1:
            angle = camera.eulerAngles.y
        case threshold1..<threshold2:
            let relativeInRange = abs((tilt - threshold1) / (threshold2 - threshold1))
            let normalizedY = normalize(camera.eulerAngles.y, forMinimalRotationTo: yaw)
            angle = normalizedY * (1 - relativeInRange) + yaw * relativeInRange
        default:
            angle = yaw
        }

        if alignment == .vertical{
            self.rotation = SCNVector4(0, 1, 1, Float.pi)
        } else {
            self.rotation = SCNVector4(0, 1, 0, angle)
        }
    }
}

我的目标是在对象的最后执行控制语句中的两个旋转。如果删除else语句,则仅应用该旋转,并且正方形保持水平。我尝试直接使用SCNMatrix4MakeRotation(_:_:_:_:)对转换进行两种修改,但这导致正方形不断旋转并错误地定位自身。我也尝试过调整节点的Pivot,但这没有导致对象的可见更改。

0 个答案:

没有答案