【问题标题】:Android OpenGL ES 2, Drawing squaresAndroid OpenGL ES 2,绘制方块
【发布时间】:2012-08-02 03:35:27
【问题描述】:

编辑:问题已解决! 因此,我一直在阅读适用于 Android 的官方 OpenGL ES 2 教程,并且已经了解了涉及绘制形状的部分,但我似乎无法使用正方形。它改为绘制直角三角形。

我已经包含了用于定义和绘制形状的代码,该代码几乎完全从教程中复制而来。 Renderer 类只是创建这个形状的一个实例并调用 draw 方法。

由于某种原因,本教程没有给出 vertexStride 和 vertexCount 的值/声明,所以我在其中的那些是有根据的猜测。我已经为 vertexCount 尝试了几个值(1 到 12),但都没有工作。

提前致谢。

            public class Square {

                private FloatBuffer vertexBuffer;
                private ShortBuffer drawListBuffer;

                // number of coordinates per vertex in this array
                static final int COORDS_PER_VERTEX = 3;
                static float squareCoords[] = { -0.5f,  0.5f, 0.0f,   // top left
                                                -0.5f, -0.5f, 0.0f,   // bottom left
                                                 0.5f, -0.5f, 0.0f,   // bottom right
                                                 0.5f,  0.5f, 0.0f }; // top right

                private short drawOrder[] = { 0, 1, 2, 0, 2, 3 }; // order to draw vertices
                float color[] = { 0.63671875f, 0.76953125f, 0.22265625f, 1.0f };


                private final String vertexShaderCode =
                        "attribute vec4 vPosition;" +
                        "void main() {" +
                        "  gl_Position = vPosition;" +
                        "}";

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

                int mProgram;

                static final int vertexStride = COORDS_PER_VERTEX * 4;
                static final int vertexCount = 4;

                public Square() {
                    // initialize vertex byte buffer for shape coordinates
                    ByteBuffer bb = ByteBuffer.allocateDirect(squareCoords.length * 4); // (# of coordinate values * 4 bytes per float)
                    bb.order(ByteOrder.nativeOrder());
                    vertexBuffer = bb.asFloatBuffer();
                    vertexBuffer.put(squareCoords);
                    vertexBuffer.position(0);

                    // initialize byte buffer for the draw list
                    ByteBuffer dlb = ByteBuffer.allocateDirect(drawOrder.length * 2); // (# of coordinate values * 2 bytes per short)
                    dlb.order(ByteOrder.nativeOrder());
                    drawListBuffer = dlb.asShortBuffer();
                    drawListBuffer.put(drawOrder);
                    drawListBuffer.position(0);


                    int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode);
                    int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);

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

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

                    // create a vertex shader type (GLES20.GL_VERTEX_SHADER)
                    // or a fragment shader type (GLES20.GL_FRAGMENT_SHADER)
                    int shader = GLES20.glCreateShader(type);

                    // add the source code to the shader and compile it
                    GLES20.glShaderSource(shader, shaderCode);
                    GLES20.glCompileShader(shader);

                    return shader;
                }

                public void draw() {
                    // Add program to OpenGL ES environment
                    GLES20.glUseProgram(mProgram);

                    // get handle to vertex shader's vPosition member
                    int 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
                    int mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");

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

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

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

【问题讨论】:

  • 实际上,我发现只需使用 GL_TRANGLE_FAN 代替 GL_TRIANGLES 作为 glDrawArrays() 的参数即可解决问题。问题解决了!尽管如果有人能向我指出一个 API 可以真正解释所有方法和值,而不是像 Android 那样仅仅列出它们,那就太好了。

标签: android opengl-es-2.0


【解决方案1】:

本教程缺少一些步骤:the final code for the square is here

该示例旨在使用glDrawElements 而不是glDrawArrays,这由以下行表示:private short drawOrder[] = { 0, 1, 2, 0, 2, 3 }; // order to draw vertices

此数组指定 2 个三角形的所需顶点。第一个是 0、1 和 2。然后是第二个 0、2 和 3。 GL_TRANGLE_FAN 恰好可以工作,因为它将使用缓冲区中的第一个顶点、前一个三角形中使用的最后一个顶点和下一个顶点来绘制下一个三角形。对于第二个三角形,这是 0、2 和 3。然后是 0、3 和 4,等等。如果顶点 2 为 5、5,顶点 3 为 -5、5,则生成的扇形不会是正方形。

替换这些行:

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

这些:

// Draw the square
GLES20.glDrawElements(
    GLES20.GL_TRIANGLES, drawOrder.length,
    GLES20.GL_UNSIGNED_SHORT, drawListBuffer);

【讨论】:

    【解决方案2】:
    vertexCount = squareCoords.length/COORDS_PER_VERTEX; //Vertex count is the array divided by the size of the vertex ex. (x,y) or (x,y,z) 
    vertexStride = COORDS_PER_VERTEX * 4;                //4 are how many bytes in a float
    

    如果这对你有用,请告诉我,祝你好运。

    我认为您还缺少用于将 3D 空间转换为 2D 屏幕空间的 ModelViewProjection 矩阵。 mvpMatrix 应该由draw函数传入draw(float[] mvpMatrix) 忘了提到你也应该使用DrawElements(...)(在示例中使用)如果你不需要计数或步幅,只需要一个 idicies 数组的长度和一个绘图缓冲区。

        // Get handle to shape's transformation matrix
        mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
    
        // Apply the projection and view transformation
        GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);
    
        // Draw the square
        GLES20.glDrawElements(GLES20.GL_TRIANGLES, drawOrder.length,
                              GLES20.GL_UNSIGNED_SHORT, drawListBuffer);
    

    【讨论】:

    • 我认为这个答案值得一个绿色复选标记。部分原因是它清楚地解释了vertexCountvertexStride 问题,还因为它指向GLES20.glDrawElements(...) 函数(在这种情况下应该替换GLES20.glDrawArray(...) 函数)。根据我的经验,ModelViewProjection 不是必需的,除非您在绘制正方形之前不转换世界坐标(这里似乎不是这种情况)。
    • @dbm 谢谢!我试图保持简短和简单,所以我可能会错过任何其他批评?我使用 ModelViewProjection 主要是因为这就是我使用的,但也因为我改变了在绘制之前转换世界坐标的方式。
    • 似乎也缺少 vertexShaderCode 中的 mMVPMatrix ("uniform mat4 uMVPMatrix;" +)
    【解决方案3】:
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多