Как рассчитать угол между двумя точками относительно ориентации камеры в трехмерном пространстве - PullRequest
0 голосов
/ 04 марта 2019

В настоящее время я сталкиваюсь с проблемой, заключающейся в том, что я хочу вычислить угол в радианах от положения камеры до целевого положения.Однако этот расчет должен учитывать и направление камеры.

Например, когда камера направлена ​​в сторону от объекта, функция должна возвращать π.Пока что функция, которую я написал, работает большую часть времени.Однако, когда пользователь приближается к осям X и Z, стрелка больше не указывает на цель, скорее она слегка указывает влево или вправо, в зависимости от того, находятся ли вы в положительном или отрицательном положении X и z.

В настоящее время я не уверен, почему моя функция не работает.Единственное объяснение такого поведения - фиксация карданного подвеса.Однако я не совсем уверен, как реализовать ту же функцию с помощью кватернионов.

Я также приложил несколько фотографий к этому сообщению, что проблема немного яснее.

Вот функцияЯ использую прямо сейчас:

 func getAngle() -> Float {
    guard let pointOfView = self.sceneView.session.currentFrame else { return 0.0  }
    let cameraPosition =  pointOfView.camera.transform.columns.3

    let heading =  getUserVector()
    let distance = SCNVector3Make(TargetPosition.x - cameraPosition.x ,TargetPosition.y - cameraPosition.y - TargetPosition.y,TargetPosition.z - cameraPosition.z)

    let heading_scalar = sqrtf(heading.x * heading.x + heading.z * heading.z)
    let distance_scalar = sqrtf(distance.z * distance.z + distance.z * distance.z)

    let x = ((heading.x * distance.x) + (heading.z * distance.z) / (heading_scalar * distance_scalar))

    let theta = acos(max(min(x, 1), -1))

    if theta < 0.35 {
        return 0
    }

    if (heading.x * (distance.z / distance_scalar) - heading.z * (distance.x/distance_scalar)) > 0{
        return theta
    }
    else{
        return -theta
    }

}


func getUserVector() -> (SCNVector3) { // (direction)
    if let frame = self.sceneView.session.currentFrame {
        let mat = SCNMatrix4(frame.camera.transform) // 4x4 transform matrix describing camera in world space
        let dir = SCNVector3(-1 * mat.m31, -1 * mat.m32, -1 * mat.m33) // orientation of camera in world space
         print(mat)
        return dir

    }
    return SCNVector3(0, 0, -1)
}

Рассмотрим следующее изображение в качестве примера.Стрелка в верхнем правом углу должна указывать прямо вверх, чтобы следовать линии к центру объекта, но вместо этого она указывает немного налево.Поскольку я выровнен по оси Z, то же поведение происходит при выравнивании по оси X.

enter image description here

1 Ответ

0 голосов
/ 13 марта 2019

Я разобрался с ответом на мою проблему, и решением было преобразовать объект в перспективу камеры, а затем просто взять atan2, чтобы получить угол между камерой и объектом, надеюсь, что этот пост поможет будущим читателям!

func getAngle() -> Float {
    guard let pointOfView = self.sceneView.session.currentFrame else { return 0.0  }
    let cameraPosition =  pointOfView.camera.transform
    let targetPosition = simd_float4x4(targetNode.transform)
    let newTransform =  simd_mul(cameraPosition.inverse, targetPosition).columns.3
    let theta = atan2(newTransform.z, newTransform.y)
    return theta + (Float.pi / 2)

}
...