OPENGL_ES20 立方體、球型繪製

繪製流程跟2維圖形繪製一致,只是座標需要自己去計算。

圓柱體、圓錐、球型,其實就是繪製一個一個的圓形,將他們無限分割就是一個一個的圓

//立方體
public class Cube extends Shape {

    private FloatBuffer vertexBuffer;
    private FloatBuffer colorBuffer;

    private ShortBuffer indexBuffer;

    private final String vertexShaderCode =
            // This matrix member variable provides a hook to manipulate
            // the coordinates of the objects that use this vertex shader
            "uniform mat4 uMVPMatrix;" +
                    "attribute vec4 vPosition;" +
                    "varying vec4 vColor;" +
                    "attribute vec4 aColor;" +
                    "void main() {" +
                    // the matrix must be included as a modifier of gl_Position
                    // Note that the uMVPMatrix factor *must be first* in order
                    // for the matrix multiplication product to be correct.
                    "  gl_Position = uMVPMatrix * vPosition;" +
                    "vColor = aColor;" +
                    "}";
    private final String fragmentShaderCode =
            "precision mediump float;" +
                    "varying vec4 vColor;" +
                    "void main() {" +
                    "  gl_FragColor = vColor;" +
                    "}";

    final float cubePositions[] = {
            -1.0f, 1.0f, 1.0f,    //正面左上0
            -1.0f, -1.0f, 1.0f,   //正面左下1
            1.0f, -1.0f, 1.0f,    //正面右下2
            1.0f, 1.0f, 1.0f,     //正面右上3
            -1.0f, 1.0f, -1.0f,    //反面左上4
            -1.0f, -1.0f, -1.0f,   //反面左下5
            1.0f, -1.0f, -1.0f,    //反面右下6
            1.0f, 1.0f, -1.0f,     //反面右上7
    };

    final short index[] = {
            6, 7, 4, 6, 4, 5,    //後面
            6, 3, 7, 6, 2, 3,    //右面
            6, 5, 1, 6, 1, 2,    //下面
            0, 3, 2, 0, 2, 1,    //正面
            0, 1, 5, 0, 5, 4,    //左面
            0, 7, 3, 0, 4, 7,    //上面
    };

    float color[] = {
            0f, 1f, 0f, 1f,
            0f, 1f, 0f, 1f,
            0f, 1f, 0f, 1f,
            0f, 1f, 0f, 1f,
            1f, 0f, 0f, 1f,
            1f, 0f, 0f, 1f,
            1f, 0f, 0f, 1f,
            1f, 0f, 0f, 1f,
    };

    static final int COORDS_PER_VERTEX = 3;
    static final int BYTES_PER_FLOAT = 4;


    int vertexStride = COORDS_PER_VERTEX * BYTES_PER_FLOAT;

    private int program;

    private int vPMatrixHandle;
    private int positionHandle;
    private int colorHandle;

    public Cube() {
        ByteBuffer bb = ByteBuffer.allocateDirect(cubePositions.length * BYTES_PER_FLOAT);
        bb.order(ByteOrder.nativeOrder());
        vertexBuffer = bb.asFloatBuffer();
        vertexBuffer.put(cubePositions);
        vertexBuffer.position(0);

        ByteBuffer colBuffer = ByteBuffer.allocateDirect(color.length * BYTES_PER_FLOAT);
        colBuffer.order(ByteOrder.nativeOrder());
        colorBuffer = colBuffer.asFloatBuffer();
        colorBuffer.put(color);
        colorBuffer.position(0);

        ByteBuffer dexBuffer = ByteBuffer.allocateDirect(index.length * 2);
        dexBuffer.order(ByteOrder.nativeOrder());
        indexBuffer = dexBuffer.asShortBuffer();
        indexBuffer.put(index);
        indexBuffer.position(0);

        int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode);
        int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);

        program = GLES20.glCreateProgram();

        GLES20.glAttachShader(program, vertexShader);
        GLES20.glAttachShader(program, fragmentShader);

        GLES20.glLinkProgram(program);
    }


    public void draw(float[] vPMatrix) {
        GLES20.glUseProgram(program);

        vPMatrixHandle = GLES20.glGetUniformLocation(program, "uMVPMatrix");
        GLES20.glUniformMatrix4fv(vPMatrixHandle, 1, false, vPMatrix, 0);

        positionHandle = GLES20.glGetAttribLocation(program, "vPosition");
        GLES20.glEnableVertexAttribArray(positionHandle);
        GLES20.glVertexAttribPointer(positionHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, vertexStride, vertexBuffer);

        colorHandle = GLES20.glGetAttribLocation(program, "aColor");
        GLES20.glEnableVertexAttribArray(colorHandle);
        GLES20.glVertexAttribPointer(colorHandle, 4, GLES20.GL_FLOAT, false, 0, colorBuffer);

        GLES20.glDrawElements(GLES20.GL_TRIANGLES, index.length, GLES20.GL_UNSIGNED_SHORT, indexBuffer);

        GLES20.glDisableVertexAttribArray(positionHandle);
    }


}
public class Cone extends Shape {

    //圓錐就是把圓心的z座標改成設置的height  從x,y軸看去是三角形,從z軸方向看是圓形


    private FloatBuffer vertexBuffer;

    static final int COORDS_PER_VERTEX = 3;
    static final int BYTES_PER_FLOAT = 4;
    int vertexStride = COORDS_PER_VERTEX * BYTES_PER_FLOAT;
    private float radius;
    private float height;

    //將圓形切割成40個三角形
    private final int count = 40;
    float color[] = {0.63671875f, 0.76953125f, 0.22265625f, 1.0f};
    private final String vertexShaderCode =
            // This matrix member variable provides a hook to manipulate
            // the coordinates of the objects that use this vertex shader
            "uniform mat4 uMVPMatrix;" +
                    "attribute vec4 vPosition;" +
                    "void main() {" +
                    // the matrix must be included as a modifier of gl_Position
                    // Note that the uMVPMatrix factor *must be first* in order
                    // for the matrix multiplication product to be correct.
                    "  gl_Position = uMVPMatrix * vPosition;" +
                    "}";
    private final String fragmentShaderCode =
            "precision mediump float;" +
                    "uniform vec4 vColor;" +
                    "void main() {" +
                    "  gl_FragColor = vColor;" +
                    "}";

    private int program;

    private int vPMatrixHandle;
    private int positionHandle;
    private int colorHandle;

    public Cone(float radius, float height) {
        this.radius = radius;
        this.height = height;
        float[] coords = circleCoords(radius);
        ByteBuffer bb = ByteBuffer.allocateDirect(coords.length * BYTES_PER_FLOAT);
        bb.order(ByteOrder.nativeOrder());
        vertexBuffer = bb.asFloatBuffer();
        vertexBuffer.put(coords);
        vertexBuffer.position(0);

        program = GLES20.glCreateProgram();

        int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode);
        int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);

        GLES20.glAttachShader(program, vertexShader);
        GLES20.glAttachShader(program, fragmentShader);

        GLES20.glLinkProgram(program);
    }

    private float[] circleCoords(float radius) {
        float[] coords = new float[(count + 2) * COORDS_PER_VERTEX];
        int offset = 0;
        coords[offset++] = 0;
        coords[offset++] = 0;
        coords[offset++] = height;
        for (int i = 0; i < count + 1; i++) {
            float angleInRadians = ((float) i / (float) count)
                    * ((float) Math.PI * 2f);
            coords[offset++] = (float) Math.sin(angleInRadians) * radius;
            coords[offset++] = (float) (Math.cos(angleInRadians) * radius);
            coords[offset++] = 0;
        }
        return coords;
    }


    public void draw(float[] vPMatrix) {
        GLES20.glUseProgram(program);

        vPMatrixHandle = GLES20.glGetUniformLocation(program, "uMVPMatrix");
        GLES20.glUniformMatrix4fv(vPMatrixHandle, 1, false, vPMatrix, 0);

        positionHandle = GLES20.glGetAttribLocation(program, "vPosition");
        GLES20.glEnableVertexAttribArray(positionHandle);
        GLES20.glVertexAttribPointer(positionHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, vertexStride, vertexBuffer);

        colorHandle = GLES20.glGetUniformLocation(program, "vColor");
        GLES20.glUniform4fv(colorHandle, 1, color, 0);

        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, 0, (count + 2));

        GLES20.glDisableVertexAttribArray(positionHandle);

    }


}

 

public class Ball extends Shape {

    private FloatBuffer vertexBuffer;

    static final int COORDS_PER_VERTEX = 3;

    //將圓形切割成40個三角形
    private final int count = 40;
    private float radius;
    float color[] = {0.63671875f, 0.76953125f, 0.22265625f, 1.0f};
    static final int BYTES_PER_FLOAT = 4;
    int vertexStride = COORDS_PER_VERTEX * BYTES_PER_FLOAT;
    private final String vertexShaderCode =
            // This matrix member variable provides a hook to manipulate
            // the coordinates of the objects that use this vertex shader
            "uniform mat4 uMVPMatrix;" +
                    "attribute vec4 vPosition;" +
                    "void main() {" +
                    // the matrix must be included as a modifier of gl_Position
                    // Note that the uMVPMatrix factor *must be first* in order
                    // for the matrix multiplication product to be correct.
                    "  gl_Position = uMVPMatrix * vPosition;" +
                    "}";
    private final String fragmentShaderCode =
            "precision mediump float;" +
                    "uniform vec4 vColor;" +
                    "void main() {" +
                    "  gl_FragColor = vColor;" +
                    "}";


    private int program;
    private int vPMatrixHandle;
    private int positionHandle;
    private int colorHandle;

    private int vertexCount;

    private static final String TAG = Ball.class.getSimpleName();

    public Ball(float radius, int count) {
        float[] coords = initBallCoords(radius, count);
        Log.i(TAG, "coords = : " + Arrays.toString(coords));
        ByteBuffer bb = ByteBuffer.allocateDirect(coords.length * BYTES_PER_FLOAT);
        bb.order(ByteOrder.nativeOrder());
        vertexBuffer = bb.asFloatBuffer();
        vertexBuffer.put(coords);
        vertexBuffer.position(0);
        vertexCount = coords.length / COORDS_PER_VERTEX;

        program = GLES20.glCreateProgram();

        int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode);
        int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);
        GLES20.glAttachShader(program, vertexShader);
        GLES20.glAttachShader(program, fragmentShader);

        GLES20.glLinkProgram(program);
    }

    //赤道處圓心 0,0,0 半徑爲R 一個圓形 40份需要41個點
    //0-90°圓錐
    //0-> -90°圓錐
    private float[] initBallCoords(float radius, int count) {
        float[] coords = new float[((count + 1) * 181 + 1) * COORDS_PER_VERTEX];
        int offset = 0;
//        coords[offset++] = 0;
//        coords[offset++] = 0;
//        coords[offset++] = 0;
        //赤道
//        offset = getCircleCoords(coords, radius, count, 0, offset);
        //上半球,下半球
        for (int i = 1; i <= 90; i++) {
            float miniRadius = (float) (radius  * Math.cos(i * 180 / Math.PI));
            //座標Z
            float z = (float) (radius * Math.sin(i * 180 / Math.PI));
            offset = getCircleCoords(coords, miniRadius, count, z, offset);
        }
        for (int i = 1; i <= 90; i++) {
            float miniRadius = (float) (radius  * Math.cos(i * 180 / Math.PI));
            //座標Z
            float z = (float) (-radius * Math.sin(i * 180 / Math.PI));
            offset = getCircleCoords(coords, miniRadius, count, z, offset);
        }

        return coords;
    }

    private int getCircleCoords(float[] coords, float radius, int count, float z, int offset) {
        for (int i = 0; i < count + 1; i++) {
            float angleInRadians = ((float) i / (float) count)
                    * ((float) Math.PI * 2f);
            coords[offset++] = (float) Math.sin(angleInRadians) * radius;
            coords[offset++] = (float) (Math.cos(angleInRadians) * radius);
            coords[offset++] = z;
        }
        return offset;
    }


    public void draw(float[] vPMatrix) {

        GLES20.glUseProgram(program);

        vPMatrixHandle = GLES20.glGetUniformLocation(program, "uMVPMatrix");
        GLES20.glUniformMatrix4fv(vPMatrixHandle, 1, false, vPMatrix, 0);

        positionHandle = GLES20.glGetAttribLocation(program, "vPosition");
        GLES20.glEnableVertexAttribArray(positionHandle);
        GLES20.glVertexAttribPointer(positionHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, vertexStride, vertexBuffer);

        colorHandle = GLES20.glGetUniformLocation(program, "vColor");
        GLES20.glUniform4fv(colorHandle, 1, color, 0);

        GLES20.glDrawArrays(GLES20.GL_LINES, 0, vertexCount);

        GLES20.glDisableVertexAttribArray(positionHandle);

    }

}

爲了看起來方便可以順便加一個動畫

public class GLRender_Matrix_4 implements GLSurfaceView.Renderer {

    private float[] vPMatrix = new float[16];
    private float[] projectMatrix = new float[16];
    private float[] viewMatrix = new float[16];

    private float[] rotationMatrix = new float[16];
    private Ball ball;

    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        GLES20.glClearColor(0, 0, 0, 1);
        Matrix.setLookAtM(viewMatrix, 0, 6, 6, -6, 0, 0, 0, 1, 1, 1);
        ball = new Ball(0.5f, 40);
    }

    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {
        GLES20.glViewport(0, 0, width, height);
        float ratial = (float) width / height;
        Matrix.frustumM(projectMatrix, 0, -ratial, ratial, -1, 1, 3, 200);
    }

    @Override
    public void onDrawFrame(GL10 gl) {
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
        Matrix.multiplyMM(vPMatrix, 0, projectMatrix, 0, viewMatrix, 0);

        float[] scrach = new float[16];

        long time = SystemClock.uptimeMillis() % 4000L;
        float angle = 0.090f * ((int) time);
        //可以設置旋轉的方向 X軸、Y軸、Z軸
        Matrix.setRotateM(rotationMatrix, 0, angle, 0, 1, 0f);

        Matrix.multiplyMM(scrach, 0, vPMatrix, 0, rotationMatrix, 0);

        ball.draw(scrach);


    }
}

矩陣可以疊加,球型實在看不出來是球,所以換成GL_LINES 了,爲了驗證座標計算的正確性

繪製模式:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章