金字塔在android opengl ES2下渲染时失真

时间:2016-09-21 13:10:12

标签: android opengl-es

我设法使用标准的锅炉板opengl ES2编码渲染金字塔,但是在渲染过程中金字塔似乎是扭曲的,绕Y轴旋转。

我相信这与矩阵投影矩阵或摄像机视图有关,希望有人可以通过指出错误来帮助解决。谢谢

Distorted Pyramid

   class MyGLRenderer1 implements GLSurfaceView.Renderer {
        Context context;   // Application's context
        private pyramid1 pyramid;    // (NEW)
        private Circle circle;          // (NEW)

        private int anglePyramid = 0; // Rotational angle in degree for pyramid (NEW)
        private float angleCube = 0;    // Rotational angle in degree for cube (NEW)
        private float speedPyramid = 1.5f; // Rotational speed for pyramid (NEW)
        private float speedCube = -1.5f;   // Rotational speed for cube (NEW)
        private float[] mViewMatrix = new float[16];
        private float[] mProjectionMatrix = new float[16];
        private float[] mModelMatrix = new float[16];
        private final int mBytesPerFloat = 4;
        // ** 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;
        // Constructor with global application context

        private float[] mMVPMatrix = new float[16];

        /**
         * 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;

        private FloatBuffer vertexBuffer;  // Buffer for vertex-array
        private FloatBuffer colorBuffer;   // Buffer for color-array
        private ByteBuffer indexBuffer;    // Buffer for index-array
        private FloatBuffer textureBuffer;
        private float scale_x = 0.5f;
        private float[] vertices = { // 5 vertices of the pyramid in (x,y,z)
                -1.0f * scale_x, -1.0f * scale_x, -1.0f * scale_x,  // 0. left-bottom-back
                1.0f, 0.0f, 0.0f, 1.0f,   // 4. red

                1.0f * scale_x, -1.0f * scale_x, -1.0f * scale_x,  // 1. right-bottom-back
                0.0f, 1.0f, 0.0f, 1.0f,  // 1. green


                1.0f * scale_x, -1.0f * scale_x, 1.0f * scale_x,  // 2. right-bottom-front
                0.0f, 0.0f, 1.0f, 1.0f,  // 2. blue


                -1.0f * scale_x, -1.0f * scale_x, 1.0f * scale_x,  // 3. left-bottom-front
                0.0f, 1.0f, 0.0f, 1.0f,  // 3. green

                0.0f, 0.5f, 0.0f,   // 4. top

                0.0f, 0.0f, 1.0f, 1.0f,  // 0. blue
        };
        private byte[] indices = { // Vertex indices of the 4 Triangles

                0, 3, 4,
                0, 4, 1,
                1, 4, 2,
                2, 3, 4,
                0, 1, 2,
                0, 2, 3


        };




        public MyGLRenderer1() {
            // pyramid = new pyramid1();
            // circle = new Circle();
            this.context = context;


        }

        // Call back when the surface is first created or re-created
        @Override
        public void onSurfaceCreated(GL10 gl, EGLConfig config) {
            GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);  // Set color's clear-value to black
            // 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 // 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 // precision in the fragment shader.
                            + "varying vec4 v_Color; \n" // This is the color from the vertex shader // 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 vertex 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 vertex 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.");
            }

            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);








        }

        // Call back after onSurfaceCreated() or whenever the window's size changes
        @Override
        public void onSurfaceChanged(GL10 gl, int width, int height) {
            if (height == 0) height = 1;   // To prevent divide by zero
            float aspect = (float) width / height;

            // Set the viewport (display area) to cover the entire window
            GLES20.glViewport(0, 0, width, 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 = 5.0f;

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


        }

        // Call back to draw the current frame.
        @Override
        public void onDrawFrame(GL10 gl) {
            // Clear color and depth buffers using clear-value set earlier
            GLES20.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);

            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);
          Matrix.setLookAtM(mViewMatrix, 0, 0, 0, -2f, 0f, 0f, 0f, 0f, 1.0f, 0.0f); 
            // Draw the triangle facing straight on.
            Matrix.setIdentityM(mModelMatrix, 0);
            Matrix.rotateM(mModelMatrix, 0, angleInDegrees, 0.0f, 1.0f, 0.0f);
            drawTriangle();


            anglePyramid += speedPyramid;


            // You OpenGL|ES rendering code here
            // ......
        }

        private void drawTriangle() {
            FloatBuffer aTriangleBuffer;
            vertexBuffer = ByteBuffer.allocateDirect(vertices.length * 4)
                    .order(ByteOrder.nativeOrder()).asFloatBuffer();
            vertexBuffer.put(vertices);         // Copy data into buffer
            vertexBuffer.position(0);


            // Setup index-array buffer. Indices in byte.
            indexBuffer = ByteBuffer.allocateDirect(indices.length);
            indexBuffer.put(indices);
            indexBuffer.position(0);

            aTriangleBuffer = vertexBuffer;
            // 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.glDrawElements(GLES20.GL_TRIANGLES, indices.length, GLES20.GL_UNSIGNED_BYTE,
                    indexBuffer);
            // GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 3);
        }


    }

enter image description here

修订图片

1 个答案:

答案 0 :(得分:0)

你正在失去前角,因为它与近剪裁平面相交,这就是为什么看起来你有6个顶点(5个圆边,1个在彩色区域的中间)而不是实际的5个。

其余的是因为您的面对测试错误或未启用,因此金字塔的底部是可见的,而不是前面可见。