Як визначити, на який об’єкт / поверхню вказує користувач за допомогою lwjgl?


9

Назва майже все це говорить. Я працюю над простим проектом "звикнути до lwjgl", що включає маніпулювання кубиком рубіка, і я не можу зрозуміти, як сказати, на яку сторону / квадрат вказує користувач.


Примітка. Багато двигунів AFAIK роблять це повністю на процесорі, окремо від візуалізації та зовсім не використовуючи OpenGL, оскільки це швидше (але складніше).
користувач253751

Відповіді:


8

Ви хочете використовувати 3D-підбір. Ось код, який я використовую у своїй грі.

Спочатку я кинув промінь від своєї камери. Я використовую мишу, але якщо ви просто використовуєте те, де шукає користувач, ви можете просто скористатися центром вікна. Це той код з мого класу камер:

public Ray GetPickRay() {
    int mouseX = Mouse.getX();
    int mouseY = WORLD.Byte56Game.getHeight() - Mouse.getY();

    float windowWidth = WORLD.Byte56Game.getWidth();
    float windowHeight = WORLD.Byte56Game.getHeight();

    //get the mouse position in screenSpace coords
    double screenSpaceX = ((float) mouseX / (windowWidth / 2) - 1.0f) * aspectRatio;
    double screenSpaceY = (1.0f - (float) mouseY / (windowHeight / 2));

    double viewRatio = Math.tan(((float) Math.PI / (180.f/ViewAngle) / 2.00f)) * zoomFactor;

    screenSpaceX = screenSpaceX * viewRatio;
    screenSpaceY = screenSpaceY * viewRatio;

    //Find the far and near camera spaces
    Vector4f cameraSpaceNear = new Vector4f((float) (screenSpaceX * NearPlane), (float) (screenSpaceY * NearPlane), (float) (-NearPlane), 1);
    Vector4f cameraSpaceFar = new Vector4f((float) (screenSpaceX * FarPlane), (float) (screenSpaceY * FarPlane), (float) (-FarPlane), 1);


    //Unproject the 2D window into 3D to see where in 3D we're actually clicking
    Matrix4f tmpView = Matrix4f(view);
    Matrix4f invView = (Matrix4f) tmpView.invert();
    Vector4f worldSpaceNear = new Vector4f();
    Matrix4f.transform(invView, cameraSpaceNear, worldSpaceNear);

    Vector4f worldSpaceFar = new Vector4f();

    Matrix4f.transform(invView, cameraSpaceFar, worldSpaceFar);

    //calculate the ray position and direction
    Vector3f rayPosition = new Vector3f(worldSpaceNear.x, worldSpaceNear.y, worldSpaceNear.z);
    Vector3f rayDirection = new Vector3f(worldSpaceFar.x - worldSpaceNear.x, worldSpaceFar.y - worldSpaceNear.y, worldSpaceFar.z - worldSpaceNear.z);

    rayDirection.normalise();

    return new Ray(rayPosition, rayDirection);
}

Потім я виймаю промінь, поки він не перетинається з предметом, ви можете це зробити з обмежувальними полями чи чимось подібним, оскільки це специфічно для вашої гри, я дозволю вам це впоратися. Як правило, це робиться, слідуючи за променем (додаючи напрямок променя до його початкової точки знову і знову ', поки не натрапиш на щось).

Далі ви хочете побачити, яке обличчя обрано, ви можете зробити це, повторивши трикутники у вашому кубі, щоб побачити, чи перетинає їх промінь. Наступна функція робить це і повертає відстань до вибраного обличчя, тоді я просто використовую пересічене обличчя, яке є найближчим до камери (так що ти не вибираєш заднє обличчя).

public static float RayIntersectsTriangle(Ray R, Vector3f vertex1, Vector3f vertex2, Vector3f vertex3) {
    // Compute vectors along two edges of the triangle.
    Vector3f edge1 = null, edge2 = null;

    edge1 = Vector3f.sub(vertex2, vertex1, edge1);
    edge2 = Vector3f.sub(vertex3, vertex1, edge2);

    // Compute the determinant.
    Vector3f directionCrossEdge2 = null;
    directionCrossEdge2 = Vector3f.cross(R.Direction, edge2, directionCrossEdge2);


    float determinant = Vector3f.dot(directionCrossEdge2, edge1);
    // If the ray and triangle are parallel, there is no collision.
    if (determinant > -.0000001f && determinant < .0000001f) {
        return Float.MAX_VALUE;
    }

    float inverseDeterminant = 1.0f / determinant;

    // Calculate the U parameter of the intersection point.
    Vector3f distanceVector = null;
    distanceVector = Vector3f.sub(R.Position, vertex1, distanceVector);


    float triangleU = Vector3f.dot(directionCrossEdge2, distanceVector);
    triangleU *= inverseDeterminant;

    // Make sure the U is inside the triangle.
    if (triangleU < 0 || triangleU > 1) {
        return Float.MAX_VALUE;
    }

    // Calculate the V parameter of the intersection point.
    Vector3f distanceCrossEdge1 = null;
    distanceCrossEdge1 = Vector3f.cross(distanceVector, edge1, distanceCrossEdge1);


    float triangleV = Vector3f.dot(R.Direction, distanceCrossEdge1);
    triangleV *= inverseDeterminant;

    // Make sure the V is inside the triangle.
    if (triangleV < 0 || triangleU + triangleV > 1) {
        return Float.MAX_VALUE;
    }

    // Get the distance to the face from our ray origin
    float rayDistance = Vector3f.dot(distanceCrossEdge1, edge2);
    rayDistance *= inverseDeterminant;


    // Is the triangle behind us?
    if (rayDistance < 0) {
        rayDistance *= -1;
        return Float.MAX_VALUE;
    }
    return rayDistance;
}

Трикутник з найкоротшою відстані - вибраний трикутник. Крім того, безсоромна плагін для моєї гри, ви повинні перевірити її, дотримуватися її та голосувати на опитуваннях, які я періодично викладаю. Дякую! http://byte56.com


3

Техніку, яку ви шукаєте, називають "збирання" або "3D-вибір". Існує кілька способів зробити це; одна з найбільш поширених - перетворити 2D точку на екрані в око, використовуючи обернене проекційне перетворення. Це дозволить вам генерувати промінь у просторі перегляду, який ви можете використовувати для тестування на зіткнення з фізичним поданням різних бітів геометрії сцени, щоб визначити, який об’єкт "потрапив" користувач.

Ви також можете використовувати "буфер вибору" (або "буфер вибору"), для якого GL має підтримку. Це в основному передбачає запис деякого унікального ідентифікатора об'єкта в буфер для кожного пікселя, а потім просто тестування цього буфера.

Поширені питання OpenGL мають короткі дискусії щодо обох (він зосереджується більше на буфері вибору, оскільки це цілком функція GL; вибір променів є агностичним API, за винятком, можливо, вилучення активних матриць з конвеєра). Ось більш конкретний приклад техніки вибору променів (для iOS, але вона повинна перекладатися досить легко). На цьому веб-сайті є вихідний код до деяких прикладів Червоної книги OpenGL, перенесених на LWJGL, які включають демонстраційну демонстраційну версію.

Дивіться також це питання на SO.


Також зауважте, що API вибору OpenGL був застарілий у GL3 Core. Він все ще доступний у повному профілі.
недійсна

Хе, знаючи, який термін шукати, має величезне значення :) Однак я просто шукав google для "прикладу вибору lwjgl", і ця тема була одним з найкращих хітів!
Flynn1179
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.