आप यह कैसे निर्धारित करते हैं कि उपयोगकर्ता किस वस्तु / सतह को lwjgl के साथ इंगित कर रहा है?


9

शीर्षक बहुत हद तक सब कुछ कह देता हैं। मैं एक साधारण काम कर रहा हूँ 'एक lwjgl के लिए उपयोग करने की अनुमति देता है' परियोजना में एक रूबिक क्यूब के हेरफेर को शामिल किया गया है, और मैं यह नहीं पता कर सकता कि उपयोगकर्ता की ओर इशारा करते हुए किस पक्ष / वर्ग को बताएं।


नोट: AFAIK कई इंजन पूरी तरह से सीपीयू पर करते हैं, अलग-अलग रेंडरिंग से और बिना OpenGL का उपयोग किए, क्योंकि यह तेज (लेकिन अधिक जटिल) है।
user253751 22

जवाबों:


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

जिस तकनीक की आप तलाश कर रहे हैं उसे "पिकिंग" या "3 डी पिकिंग" कहा जाता है। इसे करने के कई तरीके हैं; अधिक आम लोगों में से एक प्रोजेक्शन ट्रांसफॉर्मेशन के व्युत्क्रम का उपयोग करके स्क्रीन पर एक 2 डी बिंदु को आंखों की जगह में बदलना है। यह आपको दृश्य स्थान में एक किरण उत्पन्न करने की अनुमति देगा, जिसका उपयोग आप उपयोगकर्ता के हिट करने के लिए निर्धारित करने के लिए दृश्य ज्यामिति के अपने विभिन्न बिट्स के भौतिक प्रतिनिधित्व के साथ टकराव के लिए परीक्षण करने के लिए कर सकते हैं।

आप "पिकिंग बफर" (या "चयन बफर") का भी उपयोग कर सकते हैं, जिसके लिए जीएल का समर्थन है। इसमें मूल रूप से प्रत्येक पिक्सेल के लिए बफर में कुछ अनोखी वस्तु पहचानकर्ता लिखना और फिर बस उस बफर का परीक्षण करना शामिल है।

OpenGL FAQ में दोनों पर संक्षिप्त चर्चा है (यह चयन बफर पर अधिक ध्यान केंद्रित करता है क्योंकि यह पूरी तरह से एक GL सुविधा है; किरण पिकिंग एपीआई अज्ञेय है सिवाय शायद पाइपलाइन से सक्रिय मैट्रिसेस निकालने के लिए)। यहाँ किरण उठाने की तकनीक का एक और अधिक विशिष्ट उदाहरण है (आईओएस के लिए, लेकिन यह आसानी से पर्याप्त अनुवाद करना चाहिए)। इस साइट में LWJGL में पोर्ट किए गए कुछ OpenGL Red Book के उदाहरणों के कुछ स्रोत कोड हैं, जिनमें एक पिकिंग डेमो शामिल है।

इस सवाल को एसओ पर भी देखें ।


यह भी ध्यान दें कि OpenGL पिकिंग API को GL3 Core में पदावनत किया गया है। हालांकि यह अभी भी पूर्ण प्रोफ़ाइल में उपलब्ध है।
शून्य

हेह, यह जानने के लिए कि किस शब्द को खोजना एक बहुत बड़ा अंतर है :) हालांकि, मैंने सिर्फ 'lwjgl पिकिंग उदाहरण' के लिए Google खोजा, और यह धागा शीर्ष हिट में से एक था!
फ्लाईन 1179
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.