opengl ray picking/tracing 与硬纸板 (GVR)

opengl ray picking/tracing with cardboard (GVR)

为了演示,我做了一个小应用程序,它绘制了三个随机大小和随机位置的正方形。 绘制正方形:

private void renderObject(float[] modelViewProjection, FloatBuffer vertexCoordsBuf, int i) {
        GLES20.glUseProgram(mProgram);
        GLES20.glEnableVertexAttribArray(mPositionHandle);
        GLES20.glVertexAttribPointer(
                mPositionHandle, 3,
                GLES20.GL_FLOAT, false,
                12, vertexCoordsBuf);


        GLES20.glUniform4fv(mColorHandle,
                1, colors, i * 4);

        GLES20.glUniformMatrix4fv(mMVPMatrixHandle,
                1, false, modelViewProjection, 0);

        // Draw the square
        GLES20.glDrawElements(
                GLES20.GL_TRIANGLES, 6,
                GLES20.GL_UNSIGNED_SHORT, indexesBuffer);
        // Disable vertex array
        GLES20.glDisableVertexAttribArray(mPositionHandle);
}

我也使用正交投影在屏幕中央显示光标(白色小方块):

private void renderCursor(Eye eye) {
        GLES20.glDepthFunc(GLES20.GL_ALWAYS);
        GLES20.glDepthMask(false);

        GLES20.glUseProgram(mProgram);
        GLES20.glEnableVertexAttribArray(mPositionHandle);
        GLES20.glVertexAttribPointer(
                mPositionHandle, 3,
                GLES20.GL_FLOAT, false,
                12, cursorVertexCoordsBuf);


        GLES20.glUniform4fv(mColorHandle,
                1, colors, 12);

        float[] perspectiveMatrix = eye.getPerspective(Z_NEAR, Z_FAR);
        float[] orthoViewMatrix = new float[16];
        float[] modelViewMatrix = new float[16];
        Matrix.orthoM(orthoViewMatrix, 0, -1, 1, -1, 1, Z_NEAR, Z_FAR);
        Matrix.multiplyMM(modelViewMatrix, 0, perspectiveMatrix, 0, orthoViewMatrix, 0);

        GLES20.glUniformMatrix4fv(mMVPMatrixHandle,
                1, false, modelViewMatrix, 0);


        // Draw the square
        GLES20.glDrawElements(
                GLES20.GL_TRIANGLES, 6,
                GLES20.GL_UNSIGNED_SHORT, indexesBuffer);
        // Disable vertex array
        GLES20.glDisableVertexAttribArray(mPositionHandle);
        GLES20.glDepthFunc(GLES20.GL_LEQUAL);
        GLES20.glDepthMask(true);
    }

为了在立体模式的可见区域中心清晰可见,我画了红点。查看光标如何偏离屏幕中心。

立体模式下的效果。如何看到白色光标从屏幕中心移开:

如果我禁用了立体声模式,那么一切正常。我使用一种方法来确定屏幕中心的哪个对象正在为 screenWidth/2 和 screenHeight/2 坐标生成光线跟踪:

public boolean rayPicking(int viewWidth, int viewHeight, float rx, float ry,
                              float[] viewMatrix, float[] projMatrix, float[] modelViewMatrix,
                              float[] objectCoords, short[] objectIndexes) {
        float[] near_xyz = unProject(rx, ry, 0, viewMatrix, projMatrix, viewWidth, viewHeight);
        float[] far_xyz = unProject(rx, ry, 1, viewMatrix, projMatrix, viewWidth, viewHeight);
        int coordCount = objectCoords.length;
        float[] convertedSquare = new float[coordCount];
        float[] resultVector = new float[4];
        float[] inputVector = new float[4];
        for (int i = 0; i < coordCount; i = i + 3) {
            inputVector[0] = objectCoords[i];
            inputVector[1] = objectCoords[i + 1];
            inputVector[2] = objectCoords[i + 2];
            inputVector[3] = 1;
            Matrix.multiplyMV(resultVector, 0, modelViewMatrix, 0, inputVector, 0);
            convertedSquare[i] = resultVector[0] / resultVector[3];
            convertedSquare[i + 1] = resultVector[1] / resultVector[3];
            convertedSquare[i + 2] = resultVector[2] / resultVector[3];
        }


        ArrayList<Triangle> triangles = new ArrayList<>();
        for (int i = 0; i < objectIndexes.length; i = i + 3) {
            int i1 = objectIndexes[i] * 3;
            int i2 = objectIndexes[i + 1] * 3;
            int i3 = objectIndexes[i + 2] * 3;
            triangles.add(
                    new Triangle(
                            new float[]{
                                    convertedSquare[i1],
                                    convertedSquare[i1 + 1],
                                    convertedSquare[i1 + 2]
                            },
                            new float[]{
                                    convertedSquare[i2],
                                    convertedSquare[i2 + 1],
                                    convertedSquare[i2 + 2]
                            },
                            new float[]{
                                    convertedSquare[i3],
                                    convertedSquare[i3 + 1],
                                    convertedSquare[i3 + 2]
                            }
                    )
            );
        }

        for (Triangle t : triangles) {
            float[] point = new float[3];
            int intersects = Triangle.intersectRayAndTriangle(near_xyz, far_xyz, t, point);
            if (intersects == 1 || intersects == 2) {
                return true;
            }
        }
        return false;
}

但是如果我打开立体声模式,光标不会显示在屏幕中央。而对于左眼,则从左眼可见区域的中心向左移动,对于右眼,则适当向右移动。 在这种情况下,我不明白如何获得光标的真实屏幕坐标,以便它可以产生光线追踪? 我会很高兴收到任何提示 ;)

您可以从 github 获得完整的示例: https://github.com/Anton111111/AndroidGVRRayPickingSample

并且全部放在一个文件中以便于阅读: https://github.com/Anton111111/AndroidGVRRayPickingSample/blob/master/app/src/main/java/com/anton111111/ray_picking/MainActivity.java

P.s。请,如果你想为我的问题设置减号,请简单添加评论来解释我的问题有什么问题。

我修好了。现在我的光线拾取在立体模式下效果很好。 我添加了 calculateCursorScreenCoords 方法来获取光标的屏幕坐标。 https://github.com/Anton111111/AndroidGVRRayPickingSample/blob/master/app/src/main/java/com/anton111111/ray_picking/MainActivity.java#L196