协调系统错误,操作系统到屏幕android

时间:2015-04-19 13:37:22

标签: android opengl-es coordinates

我试图采用opengl es坐标系并将其转换为屏幕坐标系。这将使我能够在屏幕上找到顶点位置,并使碰撞检测更容易。到目前为止,我已经找到顶点并将它们乘以模型视图投影矩阵,然后使用android屏幕的高度和宽度(以像素为单位),我将顶点转换为正确的范围。我必须转换,因为opengl es坐标系的原点位于屏幕的中心,从-1到1.而屏幕的原点是从屏幕的左下角开始,当设备处于横向模式时我和# 39; ve发现尺寸为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

1 个答案:

答案 0 :(得分:1)

你错过了至关重要的一步。将ModelViewProjection矩阵乘以某个向量时,可以将此向量从对象空间转换为剪辑空间。

GL正在进行的下一步是转换为标准化设备坐标,其中观察体积是所有3维中的单位立方体[-1,1]。要从剪辑空间到规范化设备空间,剪辑空间xyz值除以剪辑空间w值(这最终会创建透视效果) ,转型链中的所有其他操作都只是线性的。这是你忘记的一步。

但是,添加此功能可能无法完全解决您的问题(具体取决于场景)。问题是GL在从剪辑空间到NDC之前会做其他的事情:剪切,它与图元相交(并且此操作适用于整个图元,而不是单独的顶点,显然)查看音量(此时只有[ - ww] ^ 3,只是每个顶点的w变化。)

如果您只想处理单点,可以检查关系 - w&lt; = xyz&lt; = {{ 1}}很满意。如果没有,你可以放弃这一点。但是如果你处理线条或三角形,这些东西就会变得更加复杂。您基本上必须实现完全裁剪,否则如果您正在绘制的图元至少有一个位于摄像机前面的顶点并且至少位于后面的顶点,您将获得无意义的数据相机(或完全在相机平面上,将产生w并除以零)。如果不处理剪裁,则生成的实际片段可能位于通过投影基元的所有原始顶点而跨越的2D边界框的