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
为了演示,我做了一个小应用程序,它绘制了三个随机大小和随机位置的正方形。 绘制正方形:
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