আপনি কীভাবে নির্ধারণ করবেন যে কোন বস্তু / পৃষ্ঠার ব্যবহারকারীর নির্দেশকে lwjgl দিয়ে দেখানো হয়েছে?


9

শিরোনাম অনেক সুন্দর সব বলছে। আমি একটি রুবিকের ঘনক্ষেত্রের কারসাজির সাথে জড়িত একটি সাধারণ 'আসুন lwjgl ব্যবহার করতে পারি' প্রজেক্টে কাজ করছি এবং ব্যবহারকারীর পয়েন্টিংটি কোন দিকে / বর্গক্ষেত্রটি বলতে হবে তা আমি বুঝতে পারি না।


দ্রষ্টব্য: আফাইক অনেক ইঞ্জিনগুলি সম্পূর্ণরূপে সিপিইউতে এটি করে, রেন্ডারিং থেকে আলাদা করে এবং ওপেনজিএল ব্যবহার না করে আলাদা করে, কারণ এটি দ্রুত (তবে আরও জটিল)।
ব্যবহারকারী 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

আপনি যে কৌশলটির সন্ধান করছেন তাকে "পিকিং" বা "3 ডি পিকিং" বলা হয়। এটা করতে বিভিন্ন উপায় আছে; প্রজেকশন রূপান্তরটির বিপরীতটি ব্যবহার করে পর্দার একটি 2 ডি পয়েন্টকে চোখের স্পেসে রূপান্তর করা হ'ল আরও সাধারণ বিষয়গুলির মধ্যে একটি। এটি আপনাকে দেখার জায়গাতে একটি রশ্মি তৈরি করার অনুমতি দেবে, যা ব্যবহারকারীর 'হিট' নির্ধারণ করতে আপনার দৃশ্যের জ্যামিতির বিভিন্ন বিটের শারীরিক উপস্থাপনার সাথে সংঘর্ষের জন্য পরীক্ষা করতে পারবেন।

আপনি একটি "পিকিং বাফার" (বা "নির্বাচন বাফার") ব্যবহার করতে পারেন যা জিএল সমর্থন করে। এটিতে প্রতিটি পিক্সেলের জন্য কোনও বাফারে কিছু অনন্য অবজেক্ট শনাক্তকারী লিখতে হয় এবং তারপরে কেবল সেই বাফারটি পরীক্ষা করা হয়।

ওপেনগিএল এফএকিউ উভয়ের বিষয়ে সংক্ষিপ্ত আলোচনা রয়েছে (এটি সিলেকশন বাফারটির দিকে আরও বেশি জোর দেয় যেহেতু এটি সম্পূর্ণরূপে একটি জিএল বৈশিষ্ট্য; রে পিকিংটি সম্ভবত পাইপলাইন থেকে সক্রিয় ম্যাট্রিকগুলি আহরণ ব্যতীত এপিআই অজিনস্টিক)। রশ্মি তোলা কৌশলটির আরও নির্দিষ্ট উদাহরণ এখানে রয়েছে (আইওএসের জন্য, তবে এটি সহজেই যথেষ্ট অনুবাদ করা উচিত)। এই সাইটের কাছে ওপেনজিএল রেড বুকের কয়েকটি উদাহরণ এলডাব্লুজেজিএলকে দেওয়া হয়েছে, যার মধ্যে একটি পিকিং ডেমো অন্তর্ভুক্ত রয়েছে।

এছাড়াও এই প্রশ্নটি দেখুন ।


এছাড়াও নোট করুন যে ওপেনএলএল পিকিং এপিআই জিএল 3 কোরে অবনতি হয়েছে। যদিও এটি এখনও সম্পূর্ণ প্রোফাইলে উপলব্ধ।
অকার্যকর

হেই, কোন শব্দটি অনুসন্ধান করতে হবে তা জানার ফলে একটি বিস্তর পার্থক্য রয়েছে :) তবে, আমি কেবল 'lwjgl বাছাইয়ের উদাহরণ' এর জন্য গুগল অনুসন্ধান করেছি এবং এই থ্রেডটি শীর্ষে অন্যতম হিট হয়েছিল!
ফ্লাইনে 1179
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.