Home > Software engineering >  Android Studio Opengl ES get problem with weird color mixturing
Android Studio Opengl ES get problem with weird color mixturing

Time:10-02

Basically I've created a plane and rotate it 5 times to be a cube. I made cube with different colors of each side. And did some rotation with touch event. Everthing was good so far, but the cube turned out to be like this. My cube first perspective My cube after a rotation

Please help it's been driving me crazy!

My cube code:

public class PhotoCube{
    public ArrayList<FloatBuffer> vertexBufferList = new ArrayList<>();
    public int[][] lists = {
            {0,1,0,0}, //front
            {1,0,0,-90}, //top
            {0,1,0,-90}, //left
            {0,1,0,90}, //
            {1,0,0,90}, //bottom
            {0,1,0,180} //right
    };

    // number of coordinates per vertex in this array
    static final int COORDS_PER_VERTEX = 3;

    static final float[] coords = {   // in counterclockwise order:
            0.5f, 0.5f, 0.5f, // top right
            -0.5f, 0.5f, 0.5f, // top left
            -0.5f, -0.5f, 0.5f, // bottom left
            0.5f, -0.5f, 0.5f  // bottom right
    };
    static final float[][] colorList = {
            {1f,0f,0f,1f},
            {0f,1f,0f,1f},
            {1f,1f,1f,1f},
            {1f,1f,0f,1f},
            {1f,0f,1f,1f},
            {0f,1f,1f,1f}
    };

    public PhotoCube() {
        final int maxVertices = 6;
        for(int[] list:lists){
            float[] currentCoords = coords.clone();
            for(int i=0;i<12;i =3){
                float x = coords[i];
                float y = coords[i 1];
                float z = coords[i 2];
                double angle = Math.toRadians(list[3]);
                currentCoords[i]=(float) ((list[0]==1)?x:(list[1]==1)?x*Math.cos(angle) z*Math.sin(angle):x*Math.cos(angle)-y*Math.sin(angle));
                currentCoords[i 1]=(float) ((list[0]==1)?y*Math.cos(angle)-z*Math.sin(angle):(list[1]==1)?y:x*Math.sin(angle) y*Math.cos(angle));
                currentCoords[i 2]=(float) ((list[0]==1)?z*Math.cos(angle) y*Math.sin(angle):(list[1]==1)?z*Math.cos(angle)-x*Math.sin(angle):z);
            }

            ByteBuffer bb = ByteBuffer.allocateDirect(
                    // (number of coordinate values * 4 bytes per float)
                    currentCoords.length * 4);
            // use the device hardware's native byte order
            bb.order(ByteOrder.nativeOrder());
            // create a floating point buffer from the ByteBuffer
            FloatBuffer vertexBuffer = bb.asFloatBuffer();
            // add the coordinates to the FloatBuffer
            vertexBuffer.put(currentCoords);
            // set the buffer to read the first coordinate
            vertexBuffer.position(0);

            if(vertexBufferList.size()==maxVertices){
                vertexBufferList.remove(0);
            }
            vertexBufferList.add(vertexBuffer);
            ByteBuffer dlb = ByteBuffer.allocateDirect(
                    // (# of coordinate values * 2 bytes per short)
                    drawOrder.length * 2);
            dlb.order(ByteOrder.nativeOrder());
            drawListBuffer = dlb.asShortBuffer();
            drawListBuffer.put(drawOrder);
            drawListBuffer.position(0);

            createProgram();
            GLES20.glLinkProgram(mProgram);
            // creates OpenGL ES program executables
        }
    }

    public void createProgram(){
        // create empty OpenGL ES Program
        mProgram = GLES20.glCreateProgram();
        int vertexShader = MyGLRenderer.loadShader(GLES20.GL_VERTEX_SHADER,
                vertexShaderCode);
        int fragmentShader = MyGLRenderer.loadShader(GLES20.GL_FRAGMENT_SHADER,
                fragmentShaderCode);

        // add the vertex shader to program
        GLES20.glAttachShader(mProgram, vertexShader);

        // add the fragment shader to program
        GLES20.glAttachShader(mProgram, fragmentShader);
    }

    public void draw(int order) {
        final int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertex

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

        // get handle to vertex shader's vPosition member
        int positionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");

        // Enable a handle to the triangle vertices
        GLES20.glEnableVertexAttribArray(positionHandle);
        // Prepare the triangle coordinate data
        GLES20.glVertexAttribPointer(positionHandle, COORDS_PER_VERTEX,
                GLES20.GL_FLOAT, true,
                vertexStride, vertexBufferList.get(order));

        // get handle to fragment shader's vColor member
        int colorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");
        // Set color for drawing the triangle
        GLES20.glUniform4fv(colorHandle, 1, colorList[order], 0);

        GLES20.glDrawElements(
                GLES20.GL_TRIANGLES,
                drawOrder.length,
                GL_UNSIGNED_SHORT,
                drawListBuffer);

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

My Renderer code:

public class MyGLRenderer implements GLSurfaceView.Renderer {
    private PhotoCube mPhotoCube;
        public final float[] vPMatrix = new float[16];
        private final float[] projectionMatrix = new float[16];
        private final float[] viewMatrix = new float[16];
        private int vPMatrixHandle = -1;
        private volatile float mAngleX = 0;
        private volatile float mAngleY = 0;
        private float[] rotationMX = new float[16];
        private float[] rotationMY = new float[16];
        private float[] scratch = new float[16];
    
        public MyGLRenderer(Context context){
        }
    
        public static int loadShader(int type, String shaderCode) {
            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 onSurfaceCreated(GL10 unused, EGLConfig config) {
            // Set the background frame color
            GLES20.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
            mPhotoCube = new PhotoCube();
            vPMatrixHandle = GLES20.glGetUniformLocation(mPhotoCube.mProgram, "uVPMatrix");
            onDrawFrame(unused);
        }
    
        public void onDrawFrame(GL10 unused) {
            // Redraw background color
            GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
            GLES20.glEnable(GLES20.GL_BLEND);
            GLES20.glBlendFuncSeparate(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA, GLES20.GL_ZERO, GLES20.GL_ONE);
    
            Matrix.setRotateM(rotationMX, 0, -mAngleX, 0, 1, 0);
            Matrix.setLookAtM(viewMatrix, 0, 0, 0, 5, 0f, 0f, -5f, 0f, 1.0f, 0f);
    
            // Calculate the projection and view transformation
            Matrix.multiplyMM(vPMatrix, 0, projectionMatrix, 0, viewMatrix, 0);
            Matrix.multiplyMM(scratch, 0, vPMatrix, 0, rotationMX, 0);
            Matrix.setRotateM(rotationMY, 0, -mAngleY, scratch[0], scratch[4], scratch[8]);
            Matrix.multiplyMM(scratch, 0, scratch, 0, rotationMY, 0);
    
            vPMatrixHandle = GLES20.glGetUniformLocation(mPhotoCube.mProgram, "uMVPMatrix");
            GLES20.glUniformMatrix4fv(vPMatrixHandle, 1, false, scratch, 0);
            for(int i=0;i<mPhotoCube.lists.length;i  ){
                mPhotoCube.draw(i);
            }
        }
    
        public void onSurfaceChanged(GL10 unused, 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
            Matrix.frustumM(projectionMatrix, 0, -ratio, ratio, -1, 1, 3, 7);
        }
    }

Here's my shader code

final String vertexShaderCode =
    "uniform mat4 uMVPMatrix;"  
    "attribute vec4 vPosition;"  
        "void main() {"  
        "  gl_Position = uMVPMatrix * vPosition;"  
    "}";
final String fragmentShaderCode =
    "precision mediump float;"  
    "uniform vec4 vColor;"  
    "void main() {"  
    "  gl_FragColor = vColor;"  
    "}";

Thank you in advance.

CodePudding user response:

You have to enable the Depth Test Depth test ensures that fragments that lie behind other fragments are discarded:

GLES20.glEnable(GLES20.GL_DEPTH_TEST);

When you enable the depth test you must also clear the depth buffer:

GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);

However, if you have transparent objects and want to use Blending, the depth test must be disabled and you must draw the triangles of the meshes in sorted order from back to front. Also see OpenGL depth sorting

  • Related