Kullanıcının lwjgl ile hangi nesneyi / yüzeyi gösterdiğini nasıl belirlersiniz?


9

Başlık hemen hemen her şeyi söylüyor. Bir rubik küpünün manipülasyonunu içeren basit bir 'lwjgl'ye alışalım' projesi üzerinde çalışıyorum ve kullanıcının hangi tarafa / kareye işaret ettiğini nasıl anlayacağımı anlayamıyorum.


Not: AFAIK birçok motor bunu tamamen CPU'da, ayrı olarak ve OpenGL kullanmadan yapar, çünkü daha hızlıdır (ancak daha karmaşıktır).
user253751

Yanıtlar:


8

3D seçimini kullanmak isteyeceksiniz. İşte oyunumda kullandığım bazı kodlar.

Önce kameramdan bir ışın aldım. Fareyi kullanıyorum, ancak yalnızca kullanıcının aradığı yeri kullanıyorsanız, pencerenin merkezini kullanabilirsiniz. Bu kamera sınıfımdaki kod:

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);
}

Sonra bir nesneyle kesişene kadar ışını takip ediyorum, bunu sınırlayıcı kutularla veya benzer bir şeyle yapabilirsiniz, çünkü bu oyununuza özgüdür, bunu halletmenize izin vereceğim. Genellikle bu, ışını takip ederek yapılır (bir şeye çarpana kadar ışının yönünü başlangıç ​​noktasına tekrar tekrar ekleyerek).

Daha sonra hangi yüzün seçildiğini görmek istiyorsanız, ışının kesişip kesişmediğini görmek için küpünüzdeki üçgenleri yineleyerek bunu yapabilirsiniz. Aşağıdaki işlev bunu yapar ve çekilen yüze olan mesafeyi döndürür, sonra sadece kameraya en yakın olan kesişen yüzü kullanırım (böylece arka yüzü seçmezsiniz).

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;
}

En kısa mesafeli üçgen seçilen üçgendir. Ayrıca, oyunum için utanmaz fiş, kontrol etmeli, takip etmeli ve ara sıra koyduğum sandıklarda oy kullanmalısın. Teşekkürler! http://byte56.com


3

Aradığınız tekniğe "toplama" veya "3D toplama" denir. Bunu yapmanın birkaç yolu vardır; daha yaygın olanlardan biri, projeksiyon dönüşümünün tersini kullanarak ekrandaki bir 2D noktayı göz boşluğuna dönüştürmektir. Bu, kullanıcının hangi nesneyi 'vurduğunu' belirlemek için çeşitli sahne geometrisi parçalarınızın fiziksel temsili ile çarpışmayı test etmek için kullanabileceğiniz bir görüntüleme alanında bir ışın oluşturmanıza olanak tanır.

GL'nin desteklediği bir "toplama tamponu" (veya "seçim tamponu") da kullanabilirsiniz. Bu temelde her piksel için bir tampon içine bazı benzersiz nesne tanımlayıcıları yazmayı ve daha sonra sadece bu tamponu test etmeyi içerir.

OpenGL SSS'nin ikisinde de kısa tartışmalar var (bu tamamen bir GL özelliği olduğu için seçim arabelleğine daha fazla odaklanıyor; ışın toplama, belki de aktif matrisleri boru hattından çıkarmak dışında API agnostiktir). Işın toplama tekniğinin daha spesifik bir örneği (iOS için, ancak yeterince kolay tercüme edilmelidir). Bu site , bir toplama demosu içeren LWJGL'ye taşınan OpenGL Red Book örneklerinden bazılarına kaynak kodu içermektedir.

Ayrıca SO ile ilgili bu soruya bakın .


Ayrıca OpenGL toplama API'sının GL3 Core'da kullanımdan kaldırıldığını unutmayın. Yine de tam profilde kullanılabilir.
geçersiz

Heh, hangi terimi arayacağını bilmek çok büyük bir fark yaratıyor :) Ancak, ben sadece 'lwjgl toplama örneği' için google aradım ve bu konu en iyi hitlerden biriydi!
Flynn1179
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.