Рендеринг артефактов на торе - PullRequest
0 голосов
/ 08 мая 2018

Я пытаюсь визуализировать непрозрачный тор в Android, используя OpenGL ES 2.0. Когда я добавил цвет, следуя этому руководству, я заметил артефакт при просмотре тора с определенных точек зрения. У меня связано изображение, которое показывает это, хотя анимация здесь может сделать его более четким.

После некоторого начального прочтения я подумал, что это может быть проблемой буфера глубины, так как кажется, что внутренняя задняя поверхность может быть визуализирована поверх внешней передней поверхности, которая должна быть видна. Тем не менее, изменение точки обзора вблизи / далеко, чтобы попытаться максимизировать расстояние между поверхностями, не помогло.

Я уверен, что вершины сами по себе правильны, начиная с рендеринга с использованием 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 голосов
/ 08 мая 2018

Чтобы тест глубины работал, вы должны включить тест глубины (GLES20.glEnable(GLES20.GL_DEPTH_TEST)) и указать размер буфера глубины.

В GLSurfaceView это можно сделать с помощью 4-го параметра setEGLConfigChooser:

например. размер буфера глубины 16 бит:

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