Как правильно проверить точку в 3D-конусе? - PullRequest
0 голосов
/ 17 июня 2019

Итак, это смущает, похоже, что все мои математические навыки в старшей школе испортились.

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

    glm::vec3 cameraDirection = glm::normalize(camera->lookat - camera->position);
    glm::vec3 cameraViewAxis = camera->position + (cameraDirection * (camera->farPlaneDistance) );          

    for(const auto & obj : scene->objects){
        glm::vec3 point = obj.position;

        glm::vec3 objDirection = glm::normalize(point - camera->position);
        float cosAlpha = glm::dot(objDirection, cameraDirection);

        float distance = glm::distance(camera->position, point);
        float distanceOnViewAxis = distance * cosAlpha;

        glm::vec3 pointOnViewAxis = camera->position + (cameraDirection * distanceOnViewAxis);

        float distanceFromViewAxis = glm::distance(pointOnViewAxis, point);
        float viewRadius = getViewRadius(distanceOnViewAxis); // based on FOV/aspect ratio

        if(distanceFromViewAxis < viewRadius){
            // might be visible
        }
    }

У меня появляется ноющее чувство, что есть лучший способ сделать это, мне нужны только distanceOnViewAxis и distanceFromViewAxis, которые в тригонометрических терминах - это смежные и противоположные стороны прямоугольного треугольника, я знаю углы и гипотенузу.

Я посмотрел несколько похожих вопросов, но они мне не очень помогли.

1 Ответ

1 голос
/ 17 июня 2019

Вот более краткое решение, использующее как точечное произведение, так и перекрестное произведение.

bool is_in_cone(const glm::vec3& camera_pos, const glm::vec3& camera_direction, const glm::vec3& object_pos) {
    auto normalized_dir = glm::normalize(camera_direction);
    auto obj_vector = object_pos - camera_pos;
    auto dis_on_view_axis = glm::dot(obj_vector, normalized_dir);
    if (dis_on_view_axis < 0.0f) return false;
    return glm::length(glm::cross(obj_vector, normalized_dir)) <= getViewRadius(dis_on_view_axis);
}

Я нарисовал график, чтобы показать, что за этим стоит математика (обратите внимание, что на графике я рассмотрел предел высоты конуса, но вам это, похоже, не нужно) The equation in the bottom-right corner is for a point inside the cone to satisfy.

...