坐标系错误,opengl es系统转屏android
Coordinate system error, opengl es system to screen android
我正在尝试将 opengl es 坐标系转换为屏幕坐标系。这将使我能够在屏幕上找到顶点位置,并使碰撞检测更容易。到目前为止,我已经找到顶点并将它们乘以模型视图投影矩阵,然后使用 android 屏幕的高度和宽度(以像素为单位),我将顶点转换为正确的范围。我必须进行转换,因为 opengl es 坐标系的原点位于屏幕的中心并且从 -1 变为 1。虽然屏幕的原点来自屏幕的左下角,并且当设备处于横向模式时我'我们发现尺寸为 800x480 像素。
这就是问题所在,当我在屏幕上查看一个顶点可以具有的值范围时,它的范围大约为 147 - 640 宽度和 185 - 480 高度。它的范围应为 0-800 宽度和 0-480 高度。
我的代码有什么问题?是模型视图投影矩阵,还是我使用了错误的屏幕测量值,或者是我从 opengl es 范围转换为屏幕像素范围的方式。
这会找到形状顶点,将其乘以 mvp 矩阵并转换值的范围,以便它们具有像素屏幕尺寸。我只检查其中一个形状顶点。
dimension[0] = MyGLSurfaceView.width;
dimension[1] = MyGLSurfaceView.height;
float starW;
float starH;
for (int i = 0; i < star.vertices.length; i += star.vertices.length) {//only checking one vertex
Matrix.multiplyMM(starVerts, 0, mMVPMatrix, 0, star.vertices, 0);//vertices multiplied by model view projection matrix
//starVerts[i] is in the range .433 to -.466 should be 1 to -1
//starVert[i+1] is in the range .973 to -.246 should be 1 to -1
starW = (starVerts[i] * (dimension[0] / 2)) + (dimension[0] / 2);//should be range 0-800 // instead 147 - 640
starH = (starVerts[i + 1] * (dimension[1] / 2)) + (dimension[1] / 2);//should be range 0-480 // instead 185 - 480
这就是我找到 mvp 矩阵的方式
@Override
public void onSurfaceChanged(GL10 unused, int width, int height) {
GLES20.glViewport(0, 0, width, height);// Sets the current view port to the new size.
float RATIO = (float) width / height;
Matrix.frustumM(mProjectionMatrix, 0, -RATIO, RATIO, -1, 1, 3, 7);// this projection matrix is applied to object coordinates in the onDrawFrame() method
}
@Override
public void onDrawFrame(GL10 unused) {
Matrix.setLookAtM(mViewMatrix, 0, 0, 0, -3, 0f, 0f, 0f, 0f, 1.0f, 0.0f);// Set the camera position (View matrix)
Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0);// Calculate the projection and view transformation
这就是我找到 android 屏幕尺寸的方法(以像素为单位)
Display display = ((WindowManager)
context.getSystemService(Context.WINDOW_SERVICE))
.getDefaultDisplay();
Point size = new Point();
display.getSize(size);
height = size.y;
width = size.x;
自 derhass 回答后更新
starVerts[i] = starVerts[i]/starVerts[i+3]; //clip.x divided by clip.w
starVerts[i+1] = starVerts[i+1]/starVerts[i+3];//clip.y divided by clip.w
你错过了关键的一步。当您将 ModelViewProjection 矩阵乘以某个向量时,您将此向量从对象 space 转换为剪辑 space.
GL 下一步要做的是转换为规范化设备坐标,其中查看体积是所有 3 个维度的单位立方体 [-1,1]。要从剪辑 space 到标准化设备 space,剪辑 space x
、y
和 z
值除以剪辑 space w
值(这最终创建了透视效果,转换链中的所有其他操作都只是线性的)。这是你忘记的步骤。
但是,仅添加它可能无法完全解决您的问题(取决于场景)。问题是 GL 在从剪辑 space 到 NDC 之前会做一些其他事情:clipping,这与图元相交(并且此操作适用于整个图元,而不是显然)将顶点与查看体积分开(此时只是 [-w
,w
]^3,只是这个 w
每个顶点都不同)。
如果只想处理单点,可以检查关系是否-w
<= x
,y
,z
<= w
很满意。如果没有,您可以丢弃该点。但如果你处理直线或三角形,事情就会变得更加复杂。你基本上必须实现完整的裁剪,否则如果你绘制的图元至少有一个顶点在相机前面并且至少在后面[=的顶点上,你将得到无意义的数据34=] 相机(或恰好在相机平面上,这将产生 w=0
和除以零)。如果您不处理裁剪,则生成的实际片段可能位于通过投影图元的所有原始顶点跨越的 2D 边界框 外部 。
我正在尝试将 opengl es 坐标系转换为屏幕坐标系。这将使我能够在屏幕上找到顶点位置,并使碰撞检测更容易。到目前为止,我已经找到顶点并将它们乘以模型视图投影矩阵,然后使用 android 屏幕的高度和宽度(以像素为单位),我将顶点转换为正确的范围。我必须进行转换,因为 opengl es 坐标系的原点位于屏幕的中心并且从 -1 变为 1。虽然屏幕的原点来自屏幕的左下角,并且当设备处于横向模式时我'我们发现尺寸为 800x480 像素。
这就是问题所在,当我在屏幕上查看一个顶点可以具有的值范围时,它的范围大约为 147 - 640 宽度和 185 - 480 高度。它的范围应为 0-800 宽度和 0-480 高度。
我的代码有什么问题?是模型视图投影矩阵,还是我使用了错误的屏幕测量值,或者是我从 opengl es 范围转换为屏幕像素范围的方式。
这会找到形状顶点,将其乘以 mvp 矩阵并转换值的范围,以便它们具有像素屏幕尺寸。我只检查其中一个形状顶点。
dimension[0] = MyGLSurfaceView.width;
dimension[1] = MyGLSurfaceView.height;
float starW;
float starH;
for (int i = 0; i < star.vertices.length; i += star.vertices.length) {//only checking one vertex
Matrix.multiplyMM(starVerts, 0, mMVPMatrix, 0, star.vertices, 0);//vertices multiplied by model view projection matrix
//starVerts[i] is in the range .433 to -.466 should be 1 to -1
//starVert[i+1] is in the range .973 to -.246 should be 1 to -1
starW = (starVerts[i] * (dimension[0] / 2)) + (dimension[0] / 2);//should be range 0-800 // instead 147 - 640
starH = (starVerts[i + 1] * (dimension[1] / 2)) + (dimension[1] / 2);//should be range 0-480 // instead 185 - 480
这就是我找到 mvp 矩阵的方式
@Override
public void onSurfaceChanged(GL10 unused, int width, int height) {
GLES20.glViewport(0, 0, width, height);// Sets the current view port to the new size.
float RATIO = (float) width / height;
Matrix.frustumM(mProjectionMatrix, 0, -RATIO, RATIO, -1, 1, 3, 7);// this projection matrix is applied to object coordinates in the onDrawFrame() method
}
@Override
public void onDrawFrame(GL10 unused) {
Matrix.setLookAtM(mViewMatrix, 0, 0, 0, -3, 0f, 0f, 0f, 0f, 1.0f, 0.0f);// Set the camera position (View matrix)
Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0);// Calculate the projection and view transformation
这就是我找到 android 屏幕尺寸的方法(以像素为单位)
Display display = ((WindowManager)
context.getSystemService(Context.WINDOW_SERVICE))
.getDefaultDisplay();
Point size = new Point();
display.getSize(size);
height = size.y;
width = size.x;
自 derhass 回答后更新
starVerts[i] = starVerts[i]/starVerts[i+3]; //clip.x divided by clip.w
starVerts[i+1] = starVerts[i+1]/starVerts[i+3];//clip.y divided by clip.w
你错过了关键的一步。当您将 ModelViewProjection 矩阵乘以某个向量时,您将此向量从对象 space 转换为剪辑 space.
GL 下一步要做的是转换为规范化设备坐标,其中查看体积是所有 3 个维度的单位立方体 [-1,1]。要从剪辑 space 到标准化设备 space,剪辑 space x
、y
和 z
值除以剪辑 space w
值(这最终创建了透视效果,转换链中的所有其他操作都只是线性的)。这是你忘记的步骤。
但是,仅添加它可能无法完全解决您的问题(取决于场景)。问题是 GL 在从剪辑 space 到 NDC 之前会做一些其他事情:clipping,这与图元相交(并且此操作适用于整个图元,而不是显然)将顶点与查看体积分开(此时只是 [-w
,w
]^3,只是这个 w
每个顶点都不同)。
如果只想处理单点,可以检查关系是否-w
<= x
,y
,z
<= w
很满意。如果没有,您可以丢弃该点。但如果你处理直线或三角形,事情就会变得更加复杂。你基本上必须实现完整的裁剪,否则如果你绘制的图元至少有一个顶点在相机前面并且至少在后面[=的顶点上,你将得到无意义的数据34=] 相机(或恰好在相机平面上,这将产生 w=0
和除以零)。如果您不处理裁剪,则生成的实际片段可能位于通过投影图元的所有原始顶点跨越的 2D 边界框 外部 。