Создать луч из координат мыши для 3D-пикировки

Мой вопрос

Может кто-нибудь связать хорошую статью / учебник / что-нибудь или, может быть, даже объяснить, как правильно отбрасывать луч из координат мыши для выбора объектов в 3D?
У меня уже есть Луч и пересечение, теперь мне нужно только создать луч щелчком мыши.

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


Состояние прямо сейчас

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

Теперь я хотел бы иметь возможность 3D-выбора с помощью мыши, а не движения камеры.
Я прочитал так много других вопросов об этом, 2 урока и особенно столько разных математических вещей, так как я действительно не очень силен в этом.
Но это мне не очень помогло, потому что люди там часто используют некоторые «непроектные» функции, которые кажутся устаревшими, и я понятия не имею, как их использовать, а также не имею доступа к ним.

Прямо сейчас я устанавливаю начало луча в положение камеры, а затем пытаюсь получить направление луча из вычислений в это руководство.
И это работает немного, то есть выделение работает, когда камера направлена ​​на объект, а также иногда по всей оси y -axis, я понятия не имею, что происходит.

Если кто-то хочет прямо сейчас взглянуть на мой код:

public Ray2(Camera cam, float mouseX, float mouseY) {
    origin = cam.getEye();
    float height = 600;
    float width = 600;
    float aspect = (float) width / (float) height;


    float x = (2.0f * mouseX) / width - 1.0f;
    float y = 1.0f - (2.0f * mouseX) / height;
    float z = 1.0f;
    Vector ray_nds = vecmath.vector(x, y, z);

    Vector4f clip = new Vector4f(ray_nds.x(), ray_nds.y(), -1.0f, 1.0f);
    Matrix proj = vecmath.perspectiveMatrix(60f, aspect, 0.1f, 100f);
    proj = proj.invertRigid();
    float tempX = proj.get(0, 0) * clip.x + proj.get(1, 0) * clip.y
            + proj.get(2, 0) * clip.z + proj.get(3, 0) * clip.w;
    float tempY = proj.get(0, 1) * clip.x + proj.get(1, 1) * clip.y
            + proj.get(2, 1) * clip.z + proj.get(3, 1) * clip.w;
    float tempZ = proj.get(0, 2) * clip.x + proj.get(1, 2) * clip.y
            + proj.get(2, 2) * clip.z + proj.get(3, 2) * clip.w;
    float tempW = proj.get(0, 3) * clip.x + proj.get(1, 3) * clip.y
            + proj.get(2, 3) * clip.z + proj.get(3, 3) * clip.w;


    Vector4f ray_eye = new Vector4f(tempX, tempY, tempZ, tempW);
    ray_eye = new Vector4f(ray_eye.x, ray_eye.y, -1.0f, 0.0f);

    Matrix view = cam.getTransformation();
    view = view.invertRigid();

    tempX = view.get(0, 0) * ray_eye.x + view.get(1, 0) * ray_eye.y
            + view.get(2, 0) * ray_eye.z + view.get(3, 0) * ray_eye.w;
    tempY = view.get(0, 1) * ray_eye.x + view.get(1, 1) * ray_eye.y
            + view.get(2, 1) * ray_eye.z + view.get(3, 1) * ray_eye.w;
    tempZ = view.get(0, 2) * ray_eye.x + view.get(1, 2) * ray_eye.y
            + view.get(2, 2) * ray_eye.z + view.get(3, 2) * ray_eye.w;
    tempW = view.get(0, 3) * ray_eye.x + view.get(1, 3) * ray_eye.y
            + view.get(2, 3) * ray_eye.z + view.get(3, 3) * ray_eye.w;

    Vector ray_wor = vecmath.vector(tempX, tempY, tempZ);
    // don't forget to normalise the vector at some point
    ray_wor = ray_wor.normalize();
    direction = ray_wor;
}

person Big_Chair    schedule 18.09.2014    source источник


Ответы (1)


Во-первых, лучше всего использовать метод unproject (). Он не является устаревшим. Его можно найти в математическая библиотека GLM, например. Вот моя реализация 3D-выбора на основе Ray:

    // let's check if this renderable's AABB is clicked:
    const glm::ivec2& mCoords = _inputManager->GetMouseCoords();

    int mouseY = _viewportHeight - mCoords.y;

    //unproject twice to build a ray from near to far plane"
    glm::vec3 v0 = glm::unProject(glm::vec3(float(mCoords.x), float(mouseY), 0.0f),_camera->Transform().GetView(),_camera->Transform().GetProjection(), _viewport);
    glm::vec3 v1 = glm::unProject(glm::vec3(float(mCoords.x), float(mouseY), 1.0f),_camera->Transform().GetView(),_camera->Transform().GetProjection(), _viewport);

    glm::vec3 dir  = (v1 - v0); 

    Ray r(_camera->Transform().GetPosition(),dir);

    float ishit ;

     //construct AABB:
    glm::mat4 aabbMatr = glm::translate(glm::mat4(1.0),renderable->Transform().GetPosition());

    aabbMatr = glm::scale(aabbMatr,renderable->Transform().GetScale());

    //transforms AABB vertices(need it if the origianl bbox is not axis aligned as in this case)
    renderable->GetBoundBox()->RecalcVertices(aabbMatr);

     //this method makes typical Ray-AABB intersection test:
    if(r.CheckIntersectAABB(*renderable->GetBoundBox().get(),&ishit)){

        printf("HIT!\n");

    }

Но я бы посоветовал вам также взглянуть на выборку 3D на основе цвета который идеально подходит для пикселей и даже проще в реализации.

person Michael IV    schedule 18.09.2014
comment
Хорошо, спасибо, что разъяснили это, но я действительно хотел бы придерживаться лучевого литья. Кроме того, у вас есть что-нибудь еще, как я могу это сделать без дополнительной математической библиотеки? Или вы думаете, что это единственный хороший способ сделать это? - person Big_Chair; 19.09.2014
comment
lool извините, я не понял, что glu включен в LWJGL, поэтому я собираюсь попробовать использовать gluunproject - person Big_Chair; 19.09.2014