คุณจะกำหนดวัตถุ / พื้นผิวของผู้ใช้ที่ชี้ด้วย lwjgl ได้อย่างไร


9

ชื่อเรื่องสวยมากพูดทุกอย่าง ฉันกำลังทำงานกับโครงการ 'ให้คุ้นเคยกับ lwjgl' อย่างง่ายเกี่ยวกับการจัดการกับลูกบาศก์ของรูบิคและฉันไม่สามารถหาวิธีที่จะบอกว่าด้านใด / สี่เหลี่ยมของผู้ใช้ที่ชี้ไปที่


หมายเหตุ: AFAIK เอ็นจิ้นจำนวนมากทำสิ่งนี้ทั้งหมดบน CPU แยกจากการเรนเดอร์และไม่ใช้ 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 Red Book บางตัวอย่างที่ย้ายไปยัง LWJGL ซึ่งรวมถึงตัวอย่างการหยิบสินค้า

ดูคำถามนี้ด้วยดังนั้น


นอกจากนี้โปรดทราบว่า OpenGL การเลือก API ได้ถูกคัดค้านใน GL3 Core มันยังคงมีอยู่ในโปรไฟล์เต็มแม้ว่า
โมฆะ

เฮ้, การรู้ว่าคำใดที่ใช้ในการค้นหาสร้างความแตกต่างอย่างมาก :) อย่างไรก็ตาม, ฉันเพิ่งค้นหา google สำหรับ 'ตัวอย่างการเลือก lwjgl', และหัวข้อนี้เป็นหนึ่งในเพลงยอดนิยม!
Flynn1179
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.