在圆环上渲染人工制品

时间:2018-05-08 18:36:03

标签: android opengl-es depth-buffer

我正在尝试使用OpenGL ES 2.0在Android中呈现不透明的环面。当我按照this指南添加颜色时,我注意到从某些角度观看圆环时的人工制品。虽然动画linked可能会更清晰,但我有here图像显示了这一点。

经过一些初步阅读后,我认为它可能是深度缓冲问题,因为看起来内部后表面可能会在应该看到的外部前表面上呈现。然而,改变视图frustrum near / far限制以尝试并最大化表面之间的分离并没有帮助。

我确定顶点本身是正确的,来自rendering使用GLES20.GL_LINES而不是GLES20.GL_TRIANGLES。什么可能导致这个人工制品的想法?

以下是表面的代码:

public class Miller {

    private FloatBuffer verticesBuffer;
    private ShortBuffer indicesBuffer;

    final int nTheta = 50;     // Number of divisions per 2pi theta.
    final int nPhi = 50;       // And per 2pi phi.
    private int mProgramHandle;

    private final int POSITION_DATA_SIZE_IN_ELEMENTS = 3;  // Number of elements per coordinate per vertex (x,y,z)
    private final int COLOR_DATA_SIZE_IN_ELEMENTS = 4;  // Number of elements per colour per vertex (r,g,b,a)
    private final int BYTES_PER_FLOAT = 4;      // Number of bytes used per float.
    private final int BYTES_PER_SHORT = 2;      // Number of bytes used per short.


    private final int POSITION_DATA_SIZE = POSITION_DATA_SIZE_IN_ELEMENTS * nTheta * nPhi;
    private final int COLOR_DATA_SIZE = COLOR_DATA_SIZE_IN_ELEMENTS * nTheta * nPhi;

    final int STRIDE = (POSITION_DATA_SIZE_IN_ELEMENTS + COLOR_DATA_SIZE_IN_ELEMENTS)* BYTES_PER_FLOAT;

    // Use to access and set the view transformation
    private int mMVPMatrixHandle;

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

    private final String vertexShaderCode =
            "uniform mat4 uMVPMatrix;" +
                    "attribute vec4 aColor;" +  
                    "attribute vec4 aPosition;" +   
                    "varying vec4 vColor;" +    
                    "void main() {" +
                    "   vColor = aColor;" +                  
                    "   gl_Position = uMVPMatrix * aPosition;" +
                    "}";

    private float a;        // Minor radius
    private float R0;       // Major radius

    int nVertices = nTheta*nPhi;  // Number of vertices

    Miller(float minrad, float majrad) {

        this.R0 = majrad/3.0f; // Rescale.
        this.a = minrad/3.0f;

        ByteBuffer buffer1 = ByteBuffer.allocateDirect(nVertices * (POSITION_DATA_SIZE_IN_ELEMENTS + COLOR_DATA_SIZE_IN_ELEMENTS) * BYTES_PER_FLOAT );
        buffer1.order(ByteOrder.nativeOrder());
        verticesBuffer = buffer1.asFloatBuffer();

        for (int iTheta = 0; iTheta < nTheta; iTheta++) {
            float theta = (float) (iTheta * 2 * Math.PI / nTheta);
            for (int iPhi = 0; iPhi < nPhi; iPhi++) {
                float phi = (float) (iPhi * 2 * Math.PI / nPhi);
                // Circular torus vertices
                float x = (float) ((R0 + a * Math.cos(theta)) * Math.cos(phi));
                float y = (float) (a * Math.sin(theta));
                float z = (float) ((R0 + a * Math.cos(theta)) * Math.sin(phi));

                verticesBuffer.put(x);
                verticesBuffer.put(y);
                verticesBuffer.put(z);

                float mod = (float)Math.sqrt(x*x + y*y + z*z); // Distance from origin to point

                float cx = (float)Math.pow(Math.sin(phi),2);
                float cy = (float)Math.pow(Math.sin(phi),2);
                float cz = (float)Math.pow(Math.cos(phi),2);   // colours 

                // Add colours according to position
                verticesBuffer.put(cx);
                verticesBuffer.put(cy);
                verticesBuffer.put(cz);
                verticesBuffer.put(1.0f);   // Opaque

            }
        }
        verticesBuffer.position(0);

        // Create buffer for indices                                2 bytes per short per coord per vertex
        ByteBuffer buffer2 = ByteBuffer.allocateDirect(nPhi *nTheta * POSITION_DATA_SIZE_IN_ELEMENTS * BYTES_PER_SHORT * 2);
        buffer2.order(ByteOrder.nativeOrder());
        indicesBuffer = buffer2.asShortBuffer();

        for (int iTheta = 0; iTheta < nTheta; iTheta++) {
            for (int iPhi = 0; iPhi < nPhi; iPhi++) {
                int f = iTheta* nPhi + iPhi;        // First vertex
                int s,fp1,sp1;                              // Initialise second, first plus 1, second plus 1.
                if (iTheta != nTheta-1) {  // Triangles that link back to theta=0
                    s = f + nPhi;
                } else {
                    s = iPhi;
                }

                if (iPhi != nPhi-1) { // Triangles that link back to phi = 0
                    fp1 = f+1;
                    sp1 = s+1;
                } else {
                    fp1 = f-iPhi;
                    sp1 = s-iPhi;
                }

                indicesBuffer.put((short)f); // First triangle
                indicesBuffer.put((short)fp1);
                indicesBuffer.put((short)s);

                indicesBuffer.put((short)s); // Second triangle
                indicesBuffer.put((short)fp1);
                indicesBuffer.put((short)sp1);

            }
        }
        indicesBuffer.position(0);

        int vertexShaderHandle = TokGLRenderer.loadShader(GLES20.GL_VERTEX_SHADER,    // Load vertex shader - acquire handle.
                vertexShaderCode);
        int fragmentShaderHandle = TokGLRenderer.loadShader(GLES20.GL_FRAGMENT_SHADER,    // And fragment shader handle.
                fragmentShaderCode);

        // create empty OpenGL ES Program
        mProgramHandle = GLES20.glCreateProgram();

        // add the vertex shader to program
        GLES20.glAttachShader(mProgramHandle, vertexShaderHandle);

        // add the fragment shader to program
        GLES20.glAttachShader(mProgramHandle, fragmentShaderHandle);

        // Bind attributes
        GLES20.glBindAttribLocation(mProgramHandle, 0, "aPosition");
        GLES20.glBindAttribLocation(mProgramHandle, 1, "aColor");

        // creates OpenGL ES program executables
        GLES20.glLinkProgram(mProgramHandle);

    }

    private int mPositionHandle;
    private int mNormalHandle;
    private int mColorHandle;

    public void draw(float[] mvpMatrix) {

        // Add program to OpenGL ES environment
        GLES20.glUseProgram(mProgramHandle);

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

        // get handle to fragment shader's vColor member
        mColorHandle = GLES20.glGetAttribLocation(mProgramHandle, "aColor"); // USED TO BE vColor

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

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

        // Prepare the coordinate data
        GLES20.glVertexAttribPointer(mPositionHandle, 3, GLES20.GL_FLOAT, false, STRIDE, verticesBuffer);

        // Pass in the position information
        verticesBuffer.position(0);
        GLES20.glVertexAttribPointer(mPositionHandle, POSITION_DATA_SIZE_IN_ELEMENTS, GLES20.GL_FLOAT, false, STRIDE, verticesBuffer);
        GLES20.glEnableVertexAttribArray(mPositionHandle);  // Enable handle to position of vertices

        // Pass in the colour information
        verticesBuffer.position(POSITION_DATA_SIZE_IN_ELEMENTS);
        GLES20.glVertexAttribPointer(mColorHandle, COLOR_DATA_SIZE_IN_ELEMENTS, GLES20.GL_FLOAT, false, STRIDE, verticesBuffer);
        GLES20.glEnableVertexAttribArray(mColorHandle);         // Enable handle to colour of vertices

        // Pass the projection and view transformation to the shader
        GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);

        // Draw vertices linked by triangles.
        GLES20.glDrawElements(GLES20.GL_TRIANGLES, 6*nTheta*nPhi, GLES20.GL_UNSIGNED_SHORT, indicesBuffer);

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

}

和渲染器:

public class TokGLRenderer implements GLSurfaceView.Renderer {

    // mMVPMatrix is an abbreviation for "Model View Projection Matrix"
    private final float[] mMVPMatrix = new float[16];
    private final float[] mProjectionMatrix = new float[16];
    private final float[] mViewMatrix = new float[16];
    private Miller surf;

    public void onSurfaceCreated(GL10 unused) {
        surf = new Miller(0.96f, 3.1439243f);
    }


    public void onSurfaceChanged(GL10 gl10, int width, int height) {
        GLES20.glViewport(0,0, width, height);

        float ratio = (float) width / height;

        // this projection matrix is applied to object coordinates
        // in the onDrawFrame() method
        float zoom = 0.9f;
        Matrix.frustumM(mProjectionMatrix, 0, -ratio/zoom, ratio/zoom, -1f/zoom, 1f/zoom, 7f, 11f);
    }

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

    public void onDrawFrame(GL10 unused) {    
        // Redraw background color
        GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);

        // Set the camera position (View matrix)
        Matrix.setLookAtM(mViewMatrix, 0, 5f, 5f, 5f, 0f, 0f, 0f, 0f, 1.0f, 0.0f);

        // Calculate the projection and view transformation
        Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0);
        surf.draw(mMVPMatrix);
    }

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

}

1 个答案:

答案 0 :(得分:0)

要进行深度测试,您必须启用深度测试(GLES20.glEnable(GLES20.GL_DEPTH_TEST)),并且必须指定深度缓冲区的大小。

GLSurfaceView中,这可以通过setEGLConfigChooser的第4个参数来完成:

e.g。深度缓冲区大小为16位:

setEGLConfigChooser(8, 8, 8, 8, 16, 0)