为什么我的Open GL Triangle掩盖了我的整个视口

时间:2014-07-09 21:52:15

标签: java android opengl-es

我正在使用Android Open GL教程来了解Open GL,我试图实现我自己的SimpleTriangle绘图,它应该像其他Triangle类一样工作,但它会占用整个屏幕。

public class SimpleTriangle {

private static float x, y;
private static float[] triangleCoords = {

        x, 5.773502692f, 0.0f, // top
        x-(float)5, y-2.886851346f, 0.0f,
        x+(float)5, y-2.886851346f, 0.0f

};

private final String vertexShaderCode =
        // This matrix member variable provides a hook to manipulate
        // the coordinates of the objects that use this vertex shader
        "uniform mat4 uMVPMatrix;" +
                "attribute vec4 vPosition;" +
                "void main() {" +
                // the matrix must be included as a modifier of gl_Position
                // Note that the uMVPMatrix factor *must be first* in order
                // for the matrix multiplication product to be correct.
                "  gl_Position = uMVPMatrix * vPosition;" +
                "}";

private final String fragmentShaderCode =
        "precision mediump float;" +
                "uniform vec4 vColor;" +
                "void main() {" +
                "  gl_FragColor = vColor;" +
                "}";

private final FloatBuffer vertexBuffer;
private final int mProgram;
private int mPositionHandle;
private int mColorHandle;
private int mMVPMatrixHandle;

// number of coordinates per vertex in this array
static final int COORDS_PER_VERTEX = 3;

private final int vertexCount = triangleCoords.length / COORDS_PER_VERTEX;
private final int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertex

float color[] = { 0.63671875f, 0.76953125f, 0.22265625f, 0.0f };

public SimpleTriangle(float xInt, float yInt){

    x = xInt;
    y = yInt;

    // initialize vertex byte buffer for shape coordinates
    ByteBuffer bb = ByteBuffer.allocateDirect(
            // (number of coordinate values * 4 bytes per float)
            triangleCoords.length * 4);
    // use the device hardware's native byte order
    bb.order(ByteOrder.nativeOrder());

    // create a floating point buffer from the ByteBuffer
    vertexBuffer = bb.asFloatBuffer();
    // add the coordinates to the FloatBuffer
    vertexBuffer.put(triangleCoords);
    // set the buffer to read the first coordinate
    vertexBuffer.position(0);

    // prepare shaders and OpenGL program
    int vertexShader = MyGLRenderer.loadShader(
            GLES20.GL_VERTEX_SHADER, vertexShaderCode);
    int fragmentShader = MyGLRenderer.loadShader(
            GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);

    mProgram = GLES20.glCreateProgram();             // create empty OpenGL Program
    GLES20.glAttachShader(mProgram, vertexShader);   // add the vertex shader to program
    GLES20.glAttachShader(mProgram, fragmentShader); // add the fragment shader to program
    GLES20.glLinkProgram(mProgram);                  // create OpenGL program executables
}

public void draw(float[] mvpMatrix) {
    // Add program to OpenGL environment
    GLES20.glUseProgram(mProgram);

    // get handle to vertex shader's vPosition member
    mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");

    // Enable a handle to the triangle vertices
    GLES20.glEnableVertexAttribArray(mPositionHandle);

    // Prepare the triangle coordinate data
    GLES20.glVertexAttribPointer(
            mPositionHandle, COORDS_PER_VERTEX,
            GLES20.GL_FLOAT, false,
            vertexStride, vertexBuffer);

    // get handle to fragment shader's vColor member
    mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");

    // Set color for drawing the triangle
    GLES20.glUniform4fv(mColorHandle, 1, color, 0);

    // get handle to shape's transformation matrix
    mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
    MyGLRenderer.checkGlError("glGetUniformLocation");

    // Apply the projection and view transformation
    GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);
    MyGLRenderer.checkGlError("glUniformMatrix4fv");

    // Draw the triangle
    GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount);

    // Disable vertex array
    GLES20.glDisableVertexAttribArray(mPositionHandle);
}

}

我觉得我的Matrix.setLookAt方法存在问题,因为我并不完全了解如何设置我的观看范围。

public class MyGLRenderer implements GLSurfaceView.Renderer {

private static final String TAG = "MyGLRenderer";
private SimpleTriangle firstTriangle;
private final float[] mMVPMatrix = new float[16];
private final float[] mProjectionMatrix = new float[16];
private final float[] mViewMatrix = new float[16];
private final float[] mRotationMatrix = new float[16];

private float mAngle;

@Override
public void onSurfaceCreated(GL10 unused, EGLConfig config) {
    GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    firstTriangle = new SimpleTriangle(0f, 0f);
}

@Override
public void onDrawFrame(GL10 unused) {
    float[] scratch = new float[16];
    GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
    Matrix.setLookAtM(mViewMatrix, 0, 0, 0, -3, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
    Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0);
    Matrix.setRotateM(mRotationMatrix, 0, mAngle, 0, 0, 1.0f);
    Matrix.multiplyMM(scratch, 0, mMVPMatrix, 0, mRotationMatrix, 0);

    firstTriangle.draw(scratch);
}

@Override
public void onSurfaceChanged(GL10 unused, int width, int height) {

    GLES20.glViewport(0, 0, width, height);

    float ratio = (float) width / height;

    Matrix.frustumM(mProjectionMatrix, 0, -ratio, ratio, -1, 1, 3, 7);

}

public static int loadShader(int type, String shaderCode){

    int shader = GLES20.glCreateShader(type);

    GLES20.glShaderSource(shader, shaderCode);
    GLES20.glCompileShader(shader);

    return shader;
}

public static void checkGlError(String glOperation) {
    int error;
    while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
        Log.e(TAG, glOperation + ": glError " + error);
        throw new RuntimeException(glOperation + ": glError " + error);
    }
}

}

为了澄清,这是这里的确切教程:http://developer.android.com/training/graphics/opengl/index.html 我只是想明确说明我想要一个三角形。

那么为什么我的三角形占据了我的整个视口?

2 个答案:

答案 0 :(得分:0)

您传递给SimpleTriangle.draw(float[])的临时矩阵对我来说似乎不正确。

据我所知,您可以使用mViewMatrixmProjectionMatrix获得正确的MVP矩阵。 mRotationMatrix在哪里设置?您可以按mAngle进行旋转,但如果矩阵全部为零,则表示不会发生变化。如果mRotationMatrix实际上全为零,则当您将其乘以mMVPMatrix时,这将产生一个全零的矩阵。

我会尝试评论Matrix.multiplyMM(scratch, 0, mMVPMatrix, 0, mRotationMatrix, 0);行,看看是否有用。

答案 1 :(得分:0)

查看您的坐标和变换,您的三角形将覆盖整个窗口是有道理的。

您的三角形位于z = 0.0平面内。将坐标四舍五入为下一整数以便于阅读,3个顶点的(x, y)坐标为:

(0, 6)
(-5, -3)
(5, -3)

因此,三角形宽约10个单位,高9个单位,以原点为中心。

现在走过变革。 mRotationMatrix是一个单位矩阵,因为它旋转0度,所以它不起作用。

然后来mViewMatrix,在此处设置:

Matrix.setLookAtM(mViewMatrix, 0, 0, 0, -3, 0f, 0f, 0f, 0f, 1.0f, 0.0f);

基于这些论点,您的观点是(0, 0, -3),看(0, 0, 0)。由于你的三角形在z = 0平面上,因此眼点距离三角形有3个单位,从头看它。

最后,应用投影矩阵,在此处设置:

Matrix.frustumM(mProjectionMatrix, 0, -ratio, ratio, -1, 1, 3, 7);

Android文档没有详细记录参数,但参数似乎与传统OpenGL glFrustum()doc)调用的参数相匹配。因此,左/右/底部/顶部值是在近平面距离处测量的。

如前所述,三角形距眼点为3个单位,与近平面距离(frustum的第7个参数)相同。所以三角形恰好在近平面上。在近平面上,平截头体内坐标的范围由第3到第6个参数给出,对于x坐标是(-ratio, ratio),对于y坐标是(-1, 1)

由于你的三角形比那个距离的平截头体的(-ratio, ratio) x (-1, 1)尺寸大得多,它覆盖整个窗口,然后覆盖整个窗口。除非宽高比非常大。

如果你想让你的三角形显得更小,你可能想要增加眼距(setLookAtM()的第五个参数,并调整近/远平面距离({{的第7和第8个参数)相应的。一组典型的值会使你的眼距在近距离和远距离之间的中间位置。