无法在OpenGL ES 2.0 for Android中绘制正方形,但可以绘制三角形

时间:2013-07-16 23:36:25

标签: android opengl-es-2.0

所以我从http://www.learnopengles.com/android-lesson-one-getting-started/获取代码并且一直试图绘制一个正方形(同时仍然保留其他所有内容)。无论出于何种原因,它都显示为三角形。我的代码将在下面提供。我知道要更改GLES20.glDrawArrays(GLES20.GL_TRIANGLES,0,4),但我找不到我还缺少的其他内容。

此外,有没有更好的方法来了解如何使用GLES20类中的函数? http://developer.android.com/reference/android/opengl/GLES20.html在提供参数方面做得很好,但没有解释每个参数的作用。

我想我的错误是在我的代码的底部,可能是在drawSquare函数中,但是如果我弄错的话,整个文件将被粘贴在这里。

public class LessonOneRenderer implements GLSurfaceView.Renderer 
{/**
 * Store the model matrix. This matrix is used to move models from object space (where each model can be thought
 * of being located at the center of the universe) to world space.
 */
private float[] mModelMatrix = new float[16];

/**
 * Store the view matrix. This can be thought of as our camera. This matrix transforms world space to eye space;
 * it positions things relative to our eye.
 */
private float[] mViewMatrix = new float[16];

/** Store the projection matrix. This is used to project the scene onto a 2D viewport. */
private float[] mProjectionMatrix = new float[16];

/** Allocate storage for the final combined matrix. This will be passed into the shader program. */
private float[] mMVPMatrix = new float[16];

/** Store our model data in a float buffer. */
private final FloatBuffer mTriangle1Vertices;
private final FloatBuffer mTriangle2Vertices;
private final FloatBuffer mTriangle3Vertices;

private final FloatBuffer mSquare1Vertices;

/** This will be used to pass in the transformation matrix. */
private int mMVPMatrixHandle;

/** This will be used to pass in model position information. */
private int mPositionHandle;

/** This will be used to pass in model color information. */
private int mColorHandle;

/** How many bytes per float. */
private final int mBytesPerFloat = 4;

/** How many elements per vertex. */
private final int mStrideBytes = 7 * mBytesPerFloat;    

/** Offset of the position data. */
private final int mPositionOffset = 0;

/** Size of the position data in elements. */
private final int mPositionDataSize = 3;    

/** Offset of the color data. */
private final int mColorOffset = 3;

/** Size of the color data in elements. */
private final int mColorDataSize = 4;       

/**
 * Initialize the model data.
 */
public LessonOneRenderer()
{   
    // Define points for equilateral triangles.

    // This triangle is red, green, and blue.
    final float[] triangle1VerticesData = {
            // X, Y, Z, 
            // R, G, B, A
            -0.5f, -0.25f, 0.0f, 
            1.0f, 0.0f, 0.0f, 1.0f,

            0.5f, -0.25f, 0.0f,
            0.0f, 0.0f, 1.0f, 1.0f,

            0.0f, 0.559016994f, 0.0f, 
            0.0f, 1.0f, 0.0f, 1.0f};

    // This triangle is yellow, cyan, and magenta.
    final float[] triangle2VerticesData = {
            // X, Y, Z, 
            // R, G, B, A
            -0.5f, -0.25f, 0.0f, 
            1.0f, 1.0f, 0.0f, 1.0f,

            0.5f, -0.25f, 0.0f, 
            0.0f, 1.0f, 1.0f, 1.0f,

            0.0f, 0.559016994f, 0.0f, 
            1.0f, 0.0f, 1.0f, 1.0f};

    // This triangle is white, gray, and black.
    final float[] triangle3VerticesData = {
            // X, Y, Z, 
            // R, G, B, A
            -0.5f, -0.25f, 0.0f, 
            1.0f, 1.0f, 1.0f, 1.0f,

            0.5f, -0.25f, 0.0f, 
            0.5f, 0.5f, 0.5f, 1.0f,

            0.0f, 0.559016994f, 0.0f, 
            0.0f, 0.0f, 0.0f, 1.0f};

    final float[] square1VerticesData = {
            //topleft
            -0.25f, 0.25f, -.5f,
            1.0f, 0.0f, 0.0f, 1.0f,
            //top right
            0.25f,0.25f, -.5f,
            0.0f, 1.0f, 0.0f, 1.0f,
            //bottom left
            -0.25f, -0.25f, -.5f,
            1.0f, 0.0f, 0.0f, 1.0f,
            //right
            0.25f, -0.25f, -.5f,
            1.0f, 0.0f, 0.0f, 1.0f};



    // Initialize the buffers.
    mTriangle1Vertices = ByteBuffer.allocateDirect(triangle1VerticesData.length * mBytesPerFloat)
    .order(ByteOrder.nativeOrder()).asFloatBuffer();
    mTriangle2Vertices = ByteBuffer.allocateDirect(triangle2VerticesData.length * mBytesPerFloat)
    .order(ByteOrder.nativeOrder()).asFloatBuffer();
    mTriangle3Vertices = ByteBuffer.allocateDirect(triangle3VerticesData.length * mBytesPerFloat)
    .order(ByteOrder.nativeOrder()).asFloatBuffer();

    mSquare1Vertices = ByteBuffer.allocateDirect(square1VerticesData.length * mBytesPerFloat)
    .order(ByteOrder.nativeOrder()).asFloatBuffer();

    mTriangle1Vertices.put(triangle1VerticesData).position(0);
    mTriangle2Vertices.put(triangle2VerticesData).position(0);
    mTriangle3Vertices.put(triangle3VerticesData).position(0);
    mSquare1Vertices.put(square1VerticesData).position(0);
}

@Override
public void onSurfaceCreated(GL10 glUnused, EGLConfig config) 
{
    // Set the background clear color to gray.
    GLES20.glClearColor(0.5f, 0.5f, 0.5f, 0.5f);

    // Position the eye behind the origin.
    final float eyeX = 0.0f;
    final float eyeY = 0.0f;
    final float eyeZ = 1.5f;

    // We are looking toward the distance
    final float lookX = 0.0f;
    final float lookY = 0.0f;
    final float lookZ = -5.0f;

    // Set our up vector. This is where our head would be pointing were we holding the camera.
    final float upX = 0.0f;
    final float upY = 1.0f;
    final float upZ = 0.0f;

    // Set the view matrix. This matrix can be said to represent the camera position.
    // NOTE: In OpenGL 1, a ModelView matrix is used, which is a combination of a model and
    // view matrix. In OpenGL 2, we can keep track of these matrices separately if we choose.
    Matrix.setLookAtM(mViewMatrix, 0, eyeX, eyeY, eyeZ, lookX, lookY, lookZ, upX, upY, upZ);

    final String vertexShader =
        "uniform mat4 u_MVPMatrix;      \n"     // A constant representing the combined model/view/projection matrix.

      + "attribute vec4 a_Position;     \n"     // Per-vertex position information we will pass in.
      + "attribute vec4 a_Color;        \n"     // Per-vertex color information we will pass in.              

      + "varying vec4 v_Color;          \n"     // This will be passed into the fragment shader.

      + "void main()                    \n"     // The entry point for our vertex shader.
      + "{                              \n"
      + "   v_Color = a_Color;          \n"     // Pass the color through to the fragment shader. 
                                                // It will be interpolated across the triangle.
      + "   gl_Position = u_MVPMatrix   \n"     // gl_Position is a special variable used to store the final position.
      + "               * a_Position;   \n"     // Multiply the vertex by the matrix to get the final point in                                                                   
      + "}                              \n";    // normalized screen coordinates.

    final String fragmentShader =
        "precision mediump float;       \n"     // Set the default precision to medium. We don't need as high of a 
                                                // precision in the fragment shader.                
      + "varying vec4 v_Color;          \n"     // This is the color from the vertex shader interpolated across the 
                                                // triangle per fragment.             
      + "void main()                    \n"     // The entry point for our fragment shader.
      + "{                              \n"
      + "   gl_FragColor = v_Color;     \n"     // Pass the color directly through the pipeline.          
      + "}                              \n";                                                

    // Load in the vertex shader.
    int vertexShaderHandle = GLES20.glCreateShader(GLES20.GL_VERTEX_SHADER);

    if (vertexShaderHandle != 0) 
    {
        // Pass in the shader source.
        GLES20.glShaderSource(vertexShaderHandle, vertexShader);

        // Compile the shader.
        GLES20.glCompileShader(vertexShaderHandle);

        // Get the compilation status.
        final int[] compileStatus = new int[1];
        GLES20.glGetShaderiv(vertexShaderHandle, GLES20.GL_COMPILE_STATUS, compileStatus, 0);

        // If the compilation failed, delete the shader.
        if (compileStatus[0] == 0) 
        {               
            GLES20.glDeleteShader(vertexShaderHandle);
            vertexShaderHandle = 0;
        }
    }

    if (vertexShaderHandle == 0)
    {
        throw new RuntimeException("Error creating vertex shader.");
    }

    // Load in the fragment shader shader.
    int fragmentShaderHandle = GLES20.glCreateShader(GLES20.GL_FRAGMENT_SHADER);

    if (fragmentShaderHandle != 0) 
    {
        // Pass in the shader source.
        GLES20.glShaderSource(fragmentShaderHandle, fragmentShader);

        // Compile the shader.
        GLES20.glCompileShader(fragmentShaderHandle);

        // Get the compilation status.
        final int[] compileStatus = new int[1];
        GLES20.glGetShaderiv(fragmentShaderHandle, GLES20.GL_COMPILE_STATUS, compileStatus, 0);

        // If the compilation failed, delete the shader.
        if (compileStatus[0] == 0) 
        {               
            GLES20.glDeleteShader(fragmentShaderHandle);
            fragmentShaderHandle = 0;
        }
    }

    if (fragmentShaderHandle == 0)
    {
        throw new RuntimeException("Error creating fragment shader.");
    }

    // Create a program object and store the handle to it.
    int programHandle = GLES20.glCreateProgram();

    if (programHandle != 0) 
    {
        // Bind the vertex shader to the program.
        GLES20.glAttachShader(programHandle, vertexShaderHandle);           

        // Bind the fragment shader to the program.
        GLES20.glAttachShader(programHandle, fragmentShaderHandle);

        // Bind attributes
        GLES20.glBindAttribLocation(programHandle, 0, "a_Position");
        GLES20.glBindAttribLocation(programHandle, 1, "a_Color");

        // Link the two shaders together into a program.
        GLES20.glLinkProgram(programHandle);

        // Get the link status.
        final int[] linkStatus = new int[1];
        GLES20.glGetProgramiv(programHandle, GLES20.GL_LINK_STATUS, linkStatus, 0);

        // If the link failed, delete the program.
        if (linkStatus[0] == 0) 
        {               
            GLES20.glDeleteProgram(programHandle);
            programHandle = 0;
        }
    }

    if (programHandle == 0)
    {
        throw new RuntimeException("Error creating program.");
    }

    // Set program handles. These will later be used to pass in values to the program.
    mMVPMatrixHandle = GLES20.glGetUniformLocation(programHandle, "u_MVPMatrix");        
    mPositionHandle = GLES20.glGetAttribLocation(programHandle, "a_Position");
    mColorHandle = GLES20.glGetAttribLocation(programHandle, "a_Color");        

    // Tell OpenGL to use this program when rendering.
    GLES20.glUseProgram(programHandle);        
}   

@Override
public void onSurfaceChanged(GL10 glUnused, int width, int height) 
{
    // Set the OpenGL viewport to the same size as the surface.
    GLES20.glViewport(0, 0, width, height);

    // Create a new perspective projection matrix. The height will stay the same
    // while the width will vary as per aspect ratio.
    final float ratio = (float) width / height;
    final float left = -ratio;
    final float right = ratio;
    final float bottom = -1.0f;
    final float top = 1.0f;
    final float near = 1.0f;
    final float far = 10.0f;

    Matrix.frustumM(mProjectionMatrix, 0, left, right, bottom, top, near, far);
}   

@Override
public void onDrawFrame(GL10 glUnused) 
{
    GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);                    

    // Do a complete rotation every 10 seconds.
    long time = SystemClock.uptimeMillis() % 10000L;
    float angleInDegrees = (360.0f / 10000.0f) * ((int) time);

    // Draw the triangle facing straight on.
    Matrix.setIdentityM(mModelMatrix, 0);
    Matrix.rotateM(mModelMatrix, 0, angleInDegrees, 0.0f, 0.0f, 1.0f);        
    drawTriangle(mTriangle1Vertices);

    // Draw one translated a bit down and rotated to be flat on the ground.
    Matrix.setIdentityM(mModelMatrix, 0);
    Matrix.translateM(mModelMatrix, 0, 0.0f, -1.0f, 0.0f);
    Matrix.rotateM(mModelMatrix, 0, 90.0f, 1.0f, 0.0f, 0.0f);
    Matrix.rotateM(mModelMatrix, 0, angleInDegrees, 0.0f, 0.0f, 1.0f);        
    drawTriangle(mTriangle2Vertices);

    // Draw one translated a bit to the right and rotated to be facing to the left.
    Matrix.setIdentityM(mModelMatrix, 0);
    Matrix.translateM(mModelMatrix, 0, 1.0f, 0.0f, 0.0f);
    Matrix.rotateM(mModelMatrix, 0, 90.0f, 0.0f, 1.0f, 0.0f);
    Matrix.rotateM(mModelMatrix, 0, angleInDegrees, 0.0f, 0.0f, 1.0f);
    drawTriangle(mTriangle3Vertices);

    // Draw square facing strait on
    float smallerAngle =  -angleInDegrees;
    Matrix.setIdentityM(mModelMatrix, 0);
    Matrix.translateM(mModelMatrix, 0, 0, 0, 0.0f);
    Matrix.rotateM(mModelMatrix, 0, smallerAngle, 0.0f, 0.0f, 1.0f);        
    drawSquare(mSquare1Vertices);
}   

/**
 * Draws a triangle from the given vertex data.
 * 
 * @param aTriangleBuffer The buffer containing the vertex data.
 */
private void drawTriangle(final FloatBuffer aTriangleBuffer)
{       
    // Pass in the position information
    aTriangleBuffer.position(mPositionOffset);
    GLES20.glVertexAttribPointer(mPositionHandle, mPositionDataSize, GLES20.GL_FLOAT, false,
            mStrideBytes, aTriangleBuffer);        

    GLES20.glEnableVertexAttribArray(mPositionHandle);        

    // Pass in the color information
    aTriangleBuffer.position(mColorOffset);
    GLES20.glVertexAttribPointer(mColorHandle, mColorDataSize, GLES20.GL_FLOAT, false,
            mStrideBytes, aTriangleBuffer);        

    GLES20.glEnableVertexAttribArray(mColorHandle);

    // This multiplies the view matrix by the model matrix, and stores the result in the MVP matrix
    // (which currently contains model * view).
    Matrix.multiplyMM(mMVPMatrix, 0, mViewMatrix, 0, mModelMatrix, 0);

    // This multiplies the modelview matrix by the projection matrix, and stores the result in the MVP matrix
    // (which now contains model * view * projection).
    Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mMVPMatrix, 0);

    GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mMVPMatrix, 0);
    GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 3);                               
}

private void drawSquare(final FloatBuffer aSquareBuffer) {
    // Pass in the position information
    aSquareBuffer.position(mPositionOffset);
    GLES20.glVertexAttribPointer(mPositionHandle, mPositionDataSize, GLES20.GL_FLOAT, false,
            mStrideBytes, aSquareBuffer);        

    GLES20.glEnableVertexAttribArray(mPositionHandle);        

    // Pass in the color information
    aSquareBuffer.position(mColorOffset);
    GLES20.glVertexAttribPointer(mColorHandle, mColorDataSize, GLES20.GL_FLOAT, false,
            mStrideBytes, aSquareBuffer);        

    GLES20.glEnableVertexAttribArray(mColorHandle);

    // This multiplies the view matrix by the model matrix, and stores the result in the MVP matrix
    // (which currently contains model * view).
    Matrix.multiplyMM(mMVPMatrix, 0, mViewMatrix, 0, mModelMatrix, 0);

    // This multiplies the modelview matrix by the projection matrix, and stores the result in the MVP matrix
    // (which now contains model * view * projection).
    Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mMVPMatrix, 0);

    GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mMVPMatrix, 0);
    GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 4);                             
}
}

2 个答案:

答案 0 :(得分:2)

我假设你是OpenGL ES 2.0编程的新手。因此,在开始使用3.D转换矩阵(例如,用于建模,查看或投影)之前,请先尝试这个基本示例(渲染矩形) -

public class GLES20Renderer implements Renderer {
    private int _rectangleProgram;
    private int _rectangleAPositionLocation;
    private FloatBuffer _rectangleVFB;

    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        gl.glClearColor(0.0f, 0.0f, 0.0f, 1);
        initShapes();
        int _rectangleVertexShader = loadShader(GLES20.GL_VERTEX_SHADER, _rectangleVertexShaderCode);
        int _rectangleFragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, _rectangleFragmentShaderCode);
        _rectangleProgram = GLES20.glCreateProgram();
        GLES20.glAttachShader(_rectangleProgram, _rectangleVertexShader);
        GLES20.glAttachShader(_rectangleProgram, _rectangleFragmentShader);
        GLES20.glLinkProgram(_rectangleProgram);
        _rectangleAPositionLocation = GLES20.glGetAttribLocation(_rectangleProgram, "aPosition");
    }

    public void onSurfaceChanged(GL10 gl, int width, int height) {
        gl.glViewport(0, 0, width, height);
    }

    public void onDrawFrame(GL10 gl) {
        gl.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);

        GLES20.glUseProgram(_rectangleProgram);
        GLES20.glVertexAttribPointer(_rectangleAPositionLocation, 3, GLES20.GL_FLOAT, false, 12, _rectangleVFB);
        GLES20.glEnableVertexAttribArray(_rectangleAPositionLocation);
        GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 6);
    }

    private void initShapes()  {
        float rectangleVFA[] = {
                    0,      0,      0,
                    0,      0.5f,   0,
                    0.75f,  0.5f,   0,
                    0.75f,  0.5f,   0,
                    0.75f,  0,      0,
                    0,      0,      0,
                };
        ByteBuffer rectangleVBB = ByteBuffer.allocateDirect(rectangleVFA.length * 4);
        rectangleVBB.order(ByteOrder.nativeOrder());
        _rectangleVFB = rectangleVBB.asFloatBuffer();
        _rectangleVFB.put(rectangleVFA);
        _rectangleVFB.position(0);
    }

    private final String _rectangleVertexShaderCode = 
            "attribute vec4 aPosition;              \n"
        +   "void main() {                          \n"
        +   " gl_Position = aPosition;              \n"
        +   "}                                      \n";

    private final String _rectangleFragmentShaderCode = 
            "void main() {                          \n"
        +   " gl_FragColor = vec4(1,1,1,1);         \n"
        +   "}                                      \n";

    private int loadShader(int type, String source)  {
        int shader = GLES20.glCreateShader(type);
        GLES20.glShaderSource(shader, source);
        GLES20.glCompileShader(shader);
        return shader;
    }

}

更多这些 - http://www.apress.com/9781430250531

答案 1 :(得分:0)

将您的方块定义为两个三角形。我是这样做的(我给你一个没有颜色数据的例子,只有顶点):

    final float[] squareCoords = { 
           //first triangle
           -1.0f, 1.0f, 0.0f, 
           -1.0f, -1.0f, 0.0f,
           1.0f, 1.0f, 0.0f, 
           //second triangle
           -1.0f, -1.0f, 0.0f, 
           1.0f, -1.0f, 0.0f, 
           1.0f, 1.0f, 0.0f 
    };

然后,在drawSquare()中使用

      GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 6);  

它将用方形坐标绘制两个三角形。