【问题标题】:3D picking lwjgl3D采摘lwjgl
【发布时间】:2012-01-03 17:15:10
【问题描述】:

我已经编写了一些代码来执行 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;我必须自己构建它,我猜这就是问题所在是在)...

编辑2:

这是我目前的计算方式:

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

如果有人能验证这是对还是错,以及是否错了,那就太好了;为我提供正确的方法... 我已经阅读了很多关于此的线程和文档,但我无法将我的头包裹起来......

【问题讨论】:

    标签: opengl 3d lwjgl picking


    【解决方案1】:

    我只是不明白出了什么问题,射线正在射击,我确实击中了被移除的东西,但在我按下屏幕的地方并没有消失。

    OpenGL 不是场景图,它是一个绘图库。因此,从内部表示中删除某些内容后,您必须重新绘制场景。而且您的代码缺少对触发重绘的函数的调用。

    【讨论】:

    • 感谢您的回复!如果我有点不清楚,我很抱歉,但这不是我的整个程序,只是处理 3D Picking 的部分(位于世界控制器中)。场景的渲染是在程序的一个单独部分中完成的(在世界视图中)。我可以查看被删除对象的结果,但由于某种原因它删除了错误的对象。
    【解决方案2】:

    好的,所以我最终在 gamedev 的人和朋友的帮助下解决了这个问题,这是我发布代码的 answer 的链接!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-30
      • 2012-12-07
      • 1970-01-01
      相关资源
      最近更新 更多