0

何らかの理由で完全に正しく機能しない3Dピッキングを実行するためのコードをいくつか作成しました。(ご存知のとおり、LWJGLを使用しています。)

コードは次のようになります。

if(Mouse.getEventButton() == 1) {
  if (!Mouse.getEventButtonState()) {
    Camera.get().generateViewMatrix();

    float screenSpaceX = ((Mouse.getX()/800f/2f)-1.0f)*Camera.get().getAspectRatio();
    float screenSpaceY = 1.0f-(2*((600-Mouse.getY())/600f));
    float displacementRate = (float)Math.tan(Camera.get().getFovy()/2);

    screenSpaceX *= displacementRate;
    screenSpaceY *= displacementRate;

    Vector4f cameraSpaceNear = new Vector4f((float) (screenSpaceX * Camera.get().getNear()), (float) (screenSpaceY * Camera.get().getNear()), (float) (-Camera.get().getNear()), 1);
    Vector4f cameraSpaceFar = new Vector4f((float) (screenSpaceX * Camera.get().getFar()), (float) (screenSpaceY * Camera.get().getFar()), (float) (-Camera.get().getFar()), 1);

    Matrix4f tmpView = new Matrix4f();
    Camera.get().getViewMatrix().transpose(tmpView);
    Matrix4f invertedViewMatrix = (Matrix4f)tmpView.invert();

    Vector4f worldSpaceNear = new Vector4f();
    Matrix4f.transform(invertedViewMatrix, cameraSpaceNear, worldSpaceNear);

    Vector4f worldSpaceFar = new Vector4f();
    Matrix4f.transform(invertedViewMatrix, cameraSpaceFar, worldSpaceFar);


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

    Ray clickRay = new Ray(rayPosition, rayDirection);

    Vector tMin = new Vector(), tMax = new Vector(), tempPoint;
    float largestEnteringValue, smallestExitingValue, temp, closestEnteringValue = Camera.get().getFar()+0.1f;
    Drawable closestDrawableHit = null;
    for(Drawable d : this.worldModel.getDrawableThings()) {
        // Calcualte AABB for each object... needs to be moved later...
        firstVertex = true;
        for(Surface surface : d.getSurfaces()) {
            for(Vertex v : surface.getVertices()) {
                worldPosition.x = (v.x+d.getPosition().x)*d.getScale().x;
                worldPosition.y = (v.y+d.getPosition().y)*d.getScale().y;
                worldPosition.z = (v.z+d.getPosition().z)*d.getScale().z;
                worldPosition = worldPosition.rotate(d.getRotation());
                if (firstVertex) {
                    maxX = worldPosition.x; maxY = worldPosition.y; maxZ = worldPosition.z;
                    minX = worldPosition.x; minY = worldPosition.y; minZ = worldPosition.z;
                    firstVertex = false;
                } else {
                    if (worldPosition.x > maxX) {
                        maxX = worldPosition.x;
                    }
                    if (worldPosition.x < minX) {
                        minX = worldPosition.x;
                    }
                    if (worldPosition.y > maxY) {
                        maxY = worldPosition.y;
                    }
                    if (worldPosition.y < minY) {
                        minY = worldPosition.y;
                    }
                    if (worldPosition.z > maxZ) {
                        maxZ = worldPosition.z;
                    }
                    if (worldPosition.z < minZ) {
                        minZ = worldPosition.z;
                    }
                }
            }
        }

        // ray/slabs intersection test...


        // clickRay.getOrigin().x + clickRay.getDirection().x * f = minX
        // clickRay.getOrigin().x - minX = -clickRay.getDirection().x * f
        // clickRay.getOrigin().x/-clickRay.getDirection().x - minX/-clickRay.getDirection().x = f
        // -clickRay.getOrigin().x/clickRay.getDirection().x + minX/clickRay.getDirection().x = f


        largestEnteringValue = -clickRay.getOrigin().x/clickRay.getDirection().x + minX/clickRay.getDirection().x;
        temp = -clickRay.getOrigin().y/clickRay.getDirection().y + minY/clickRay.getDirection().y;
        if(largestEnteringValue < temp) {
            largestEnteringValue = temp;
        }
        temp = -clickRay.getOrigin().z/clickRay.getDirection().z + minZ/clickRay.getDirection().z;
        if(largestEnteringValue < temp) {
            largestEnteringValue = temp;
        }

        smallestExitingValue = -clickRay.getOrigin().x/clickRay.getDirection().x + maxX/clickRay.getDirection().x;
        temp = -clickRay.getOrigin().y/clickRay.getDirection().y + maxY/clickRay.getDirection().y;
        if(smallestExitingValue > temp) {
            smallestExitingValue = temp;
        }
        temp = -clickRay.getOrigin().z/clickRay.getDirection().z + maxZ/clickRay.getDirection().z;
        if(smallestExitingValue < temp) {
            smallestExitingValue = temp;
        }


            if(largestEnteringValue > smallestExitingValue) {
                //System.out.println("Miss!");
            } else {
                if (largestEnteringValue < closestEnteringValue) {
                    closestEnteringValue = largestEnteringValue;
                    closestDrawableHit = d;
                }
            }

    }
    if(closestDrawableHit != null) {
        System.out.println("Hit at: (" + clickRay.setDistance(closestEnteringValue).x + ", " + clickRay.getCurrentPosition().y + ", " + clickRay.getCurrentPosition().z);
        this.worldModel.removeDrawableThing(closestDrawableHit);    
    }
  }
}

何が悪いのかわかりません。光線が発射され、削除されたものをヒットしますが、光線の結果は非常に奇妙で、クリックしたものが削除されることもあれば、近くにないものが削除されることもあります。をクリックすると、何も削除されない場合があります。

編集:

さて、私はエラーを探し続け、光線をデバッグすることによって(それが通過する場所に小さな点を描くことによって)、私が送信している光線に明らかに何かが間違っていることを知ることができます...それは世界の中心近くに起源がありますカメラをどこに向けても、常に同じ位置に撮影します。

私の最初の考えは、viewMatrixの計算方法にエラーがある可能性があるということです(lwjglのglulookatメソッドからviewmatrixを取得することはできないため、自分で作成する必要があり、問題がどこにあるかを推測します) ..。。

Edit2:

これは私が現在それを計算する方法です:

private double[][] viewMatrixDouble = {{0,0,0,0}, {0,0,0,0}, {0,0,0,0}, {0,0,0,1}};

public Vector getCameraDirectionVector() {
    Vector actualEye = this.getActualEyePosition();
    return new Vector(lookAt.x-actualEye.x, lookAt.y-actualEye.y, lookAt.z-actualEye.z);
}

public Vector getActualEyePosition() {
    return eye.rotate(this.getRotation());
}

public void generateViewMatrix() {

    Vector cameraDirectionVector = getCameraDirectionVector().normalize();
    Vector side = Vector.cross(cameraDirectionVector, this.upVector).normalize();
    Vector up = Vector.cross(side, cameraDirectionVector);

    viewMatrixDouble[0][0] = side.x;                    viewMatrixDouble[0][1] = up.x;                  viewMatrixDouble[0][2] = -cameraDirectionVector.x;                 
    viewMatrixDouble[1][0] = side.y;                    viewMatrixDouble[1][1] = up.y;                  viewMatrixDouble[1][2] = -cameraDirectionVector.y;                 
    viewMatrixDouble[2][0] = side.z;                    viewMatrixDouble[2][1] = up.z;                  viewMatrixDouble[2][2] = -cameraDirectionVector.z;                 


    /*
    Vector actualEyePosition = this.getActualEyePosition();
    Vector zaxis = new Vector(this.lookAt.x - actualEyePosition.x, this.lookAt.y - actualEyePosition.y, this.lookAt.z - actualEyePosition.z).normalize();
    Vector xaxis = Vector.cross(upVector, zaxis).normalize();
    Vector yaxis = Vector.cross(zaxis, xaxis);
    viewMatrixDouble[0][0] = xaxis.x;                   viewMatrixDouble[0][1] = yaxis.x;                   viewMatrixDouble[0][2] = zaxis.x;                  
    viewMatrixDouble[1][0] = xaxis.y;                   viewMatrixDouble[1][1] = yaxis.y;                   viewMatrixDouble[1][2] = zaxis.y;                  
    viewMatrixDouble[2][0] = xaxis.z;                   viewMatrixDouble[2][1] = yaxis.z;                   viewMatrixDouble[2][2] = zaxis.z;                  
    viewMatrixDouble[3][0] = -Vector.dot(xaxis, actualEyePosition); viewMatrixDouble[3][1] =-Vector.dot(yaxis, actualEyePosition);  viewMatrixDouble[3][2] = -Vector.dot(zaxis, actualEyePosition);
    */
    viewMatrix = new Matrix4f();
    viewMatrix.load(getViewMatrixAsFloatBuffer());
}

誰かがこれが間違っているか正しいか、そしてそれが間違っているかどうかを確認できれば、非常に素晴らしいでしょう。それを行う正しい方法を私に提供してください...私はこれに関する多くのスレッドとドキュメントを読みましたが、頭を包むために継ぎ合わせることができません...

4

2 に答える 2

0

何が悪いのかわからない。光線が発射されて、除去されたものをヒットするが、画面を押すと物事が消えない。

OpenGLはシーングラフではなく、描画ライブラリです。したがって、内部表現から何かを削除した後、シーンを再描画する必要があります。また、コードには、再描画をトリガーする関数への呼び出しがありません。

于 2012-01-03T17:33:14.803 に答える
0

さて、私はgamedevの人と友人の助けを借りて最終的にそれを解決しました、ここに私がコードを投稿した答えへのリンクがあります!

于 2012-01-06T00:32:53.570 に答える