OpenGL ES初探(三) -- 用OpenGL画正方形,圆,正多边形,圆环,正五角星

OpenGL ES初探(三) – 用OpenGL画正方形,圆,圆环,正五角星

目录

准备工作

添加初始代码

  1. 构建包com.yxf.variousshape

  2. 将上篇博客的源码1中的MainActivityCommonUtils复制到com.yxf.variousshape包下

  3. 添加MyRenderer类到com.yxf.vriousshape包,内容如下

package com.yxf.variousshapes;

import android.content.Context;
import android.opengl.GLSurfaceView;

import com.yxf.variousshapes.shapes.Shape;
import com.yxf.variousshapes.shapes.Square;

import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import static android.opengl.GLES20.*;
import static android.opengl.Matrix.orthoM;

public class MyRenderer implements GLSurfaceView.Renderer {

    private static final String A_POSITION = "a_Position";
    private int aPositionLocation;

    private static final String U_MATRIX = "u_Matrix";
    private final float[] projectionMatrix = new float[16];
    private int uMatrixLocation;

    private static final String A_COLOR = "a_Color";
    private int aColorLocation;

    private Context context;
    private int program;

    //1,定义图形容器,SurfaceView是多线程的,所以使用线程安全的CopyOnWriteArrayList
    private List<Shape> shapeList = new CopyOnWriteArrayList<Shape>();


    public MyRenderer(Context context) {
        this.context = context;
    }

    public void addShape(Shape shape) {
        shapeList.add(shape);
    }


    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        glClearColor(0f, 1f, 0f, 0f);

        String vertexShaderSource = CommonUtils.readTextFromResource(context, R.raw.shape_vertex_shader);
        String fragmentShaderSource = CommonUtils.readTextFromResource(context, R.raw.shape_fragment_shader);
        int vertexShader = CommonUtils.compileVertexShader(vertexShaderSource);
        int fragmentShader = CommonUtils.compileFragmentShader(fragmentShaderSource);
        program = CommonUtils.linkProgram(vertexShader, fragmentShader);
        glUseProgram(program);
        aPositionLocation = glGetAttribLocation(program, A_POSITION);
        uMatrixLocation = glGetUniformLocation(program, U_MATRIX);
        aColorLocation = glGetAttribLocation(program, A_COLOR);

        glEnableVertexAttribArray(aPositionLocation);
        glEnableVertexAttribArray(aColorLocation);

    }

    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {
        glViewport(0, 0, width, height);
        final float aspectRatio = height / (float) width;
        orthoM(projectionMatrix, 0, -1, 1, -aspectRatio, aspectRatio, -1, 1);

        initShapeList(aspectRatio);
    }

    private void initShapeList(float aspectRatio) {
        shapeList.clear();

    }

    @Override
    public void onDrawFrame(GL10 gl) {
        glClear(GL_COLOR_BUFFER_BIT);
        glUniformMatrix4fv(uMatrixLocation, 1, false, projectionMatrix, 0);
        for (Shape shape : shapeList) {
            shape.setLocation(aPositionLocation, aColorLocation);
            shape.draw();
        }
    }
}

  1. com.yxf.variousshape包下创建包shapes
  2. shapes中添加Shape类,内容如下
package com.yxf.variousshapes.shapes;


import com.yxf.variousshapes.Point;

public abstract class Shape {
    public static final int BYTES_PER_FLOAT = 4;
    public static final int POSITION_COMPONENT_COUNT = 2;
    public static final int COLOR_COMPONENT_COUNT = 3;
    public static final int STRIDE = (POSITION_COMPONENT_COUNT +
            COLOR_COMPONENT_COUNT) * BYTES_PER_FLOAT;
    protected int aPositionLocation;
    protected int aColorLocation;

    protected Point center;
    protected float width;
    protected float height;

    public Shape(Point center, float width, float height) {
        this.center = center;
        this.width = width;
        this.height = height;
    }

    public void setLocation(int aPositionLocation, int aColorLocation) {
        this.aPositionLocation = aPositionLocation;
        this.aColorLocation = aColorLocation;
    }

    public abstract void draw();

}
  1. com.yxf.variousshape中添加Point类,如下
package com.yxf.variousshapes;

public class Point {
    public float x;
    public float y;
    public float z;

    public Point(float x, float y, float z) {
        this.x = x;
        this.y = y;
        this.z = z;
    }
}
  1. 在res中增加raw文件夹

  2. 在raw中添加文件shape_vertex_shader.glsl

uniform mat4 u_Matrix;
attribute vec4 a_Position;
attribute vec4 a_Color;

varying vec4 v_Color;
void main() {
    v_Color = a_Color;
    gl_Position = u_Matrix * a_Position;
}
  1. 在raw中添加文件shape_fragment_shader.glsl
precision mediump float;

varying vec4 v_Color;

void main(){
    gl_FragColor = v_Color;
}

结构说明

这次我们项目结构稍有变动,关键在于引入Shape,我们将延伸这个类去创建正方形,圆,圆环,正五角星,使用MyRenderer.addShape()将延伸的Shape添加到MyRenderer中,然后绘制.

其他内容大部分均在前两篇博客中说明或较简单,故而不再赘述.

绘制正方形

com.yxf.variousshape.shapes包下添加Square类,内容如下

package com.yxf.variousshapes.shapes;

import android.graphics.Color;

import com.yxf.variousshapes.Point;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;


import static android.opengl.GLES20.*;

public class Square extends Shape {
    private float[] vertices;
    private FloatBuffer vertexData;
    private final int color = Color.rgb(255, 0, 0);

    public Square(Point center, float width, float height) {
        super(center, width, height);
        float left = center.x - width / 2;
        float right = center.x + width / 2;
        float top = center.y + height / 2;
        float bottom = center.y - height / 2;
        float red = Color.red(color) / 255f;
        float green = Color.green(color) / 255f;
        float blue = Color.blue(color) / 255f;
        vertices = new float[]{
                left, top, red, green, blue,
                left, bottom, red, green, blue,
                right, bottom, red, green, blue,
                right, top, red, green, blue,

        };
        vertexData = ByteBuffer.allocateDirect(vertices.length * BYTES_PER_FLOAT)
                .order(ByteOrder.nativeOrder())
                .asFloatBuffer();
        vertexData.put(vertices);
    }

    @Override
    public void draw() {
        vertexData.position(0);
        glVertexAttribPointer(aPositionLocation, POSITION_COMPONENT_COUNT, GL_FLOAT,
                false, STRIDE, vertexData);
        vertexData.position(POSITION_COMPONENT_COUNT);
        glVertexAttribPointer(aColorLocation, COLOR_COMPONENT_COUNT, GL_FLOAT,
                false, STRIDE, vertexData);

        glDrawArrays(GL_TRIANGLE_FAN, 0, 4);

    }
}

可以看到画正方形和画三角形的区别不大,仅在于多了一个顶点的数据,然后glDrawArrays使用的是GL_TRIANGLE_FAN而不是GL_TRIANGLES.详细解释参见

然后我们更新下MyRenderer.initShapeList()如下

private void initShapeList(float aspectRatio) {
        shapeList.clear();
        addShape(new Square(new Point(-0.5f, aspectRatio * 2 / 3, 0), 0.4f, 0.4f));
    }

运行程序

应该会获得如下图中效果

squire

绘制圆形

然后我们继续绘制圆形

在绘制圆之前,我们先想想正多边形应该如何绘制

我们先构建一个正多边形的构建类

com.yxf.variousshape.shapes包下添加Polygon类,内容如下

package com.yxf.variousshapes.shapes;

import android.graphics.Color;

import com.yxf.variousshapes.Point;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;

import static android.opengl.GLES20.GL_FLOAT;
import static android.opengl.GLES20.GL_TRIANGLE_FAN;
import static android.opengl.GLES20.glDrawArrays;
import static android.opengl.GLES20.glVertexAttribPointer;

public class Polygon extends Shape {
    private final float radius;

    private  final int edgeCount;

    private final int pointCount;

    private float[] vertices;
    private FloatBuffer vertexData;
    private final int centerColor = Color.rgb(255, 255, 255);
    private final int circumColor = Color.rgb(0, 0, 255);

    public Polygon(Point center, float radius, int edgeCount) {
        super(center, radius * 2, radius * 2);
        this.radius = radius;
        this.edgeCount = edgeCount;
        pointCount = edgeCount + 2;

        vertices = new float[(POSITION_COMPONENT_COUNT + COLOR_COMPONENT_COUNT) * pointCount];
        int i = 0;
        //中心
        vertices[i++] = center.x;
        vertices[i++] = center.y;
        vertices[i++] = Color.red(centerColor) / 255f;
        vertices[i++] = Color.green(centerColor) / 255f;
        vertices[i++] = Color.blue(centerColor) / 255f;
        while (i < vertices.length) {
            int index = i / (POSITION_COMPONENT_COUNT + COLOR_COMPONENT_COUNT) - 1;
            double angle = Math.PI * 2 * index / this.edgeCount;
            vertices[i++] = center.x + (float) Math.cos(angle) * radius;
            vertices[i++] = center.y + (float) Math.sin(angle) * radius;
            vertices[i++] = Color.red(circumColor) / 255f;
            vertices[i++] = Color.green(circumColor) / 255f;
            vertices[i++] = Color.blue(circumColor) / 255f;
        }

        vertexData = ByteBuffer.allocateDirect(vertices.length * BYTES_PER_FLOAT)
                .order(ByteOrder.nativeOrder())
                .asFloatBuffer();
        vertexData.put(vertices);

    }

    @Override
    public void draw() {
        vertexData.position(0);
        glVertexAttribPointer(aPositionLocation, POSITION_COMPONENT_COUNT, GL_FLOAT,
                false, STRIDE, vertexData);
        vertexData.position(POSITION_COMPONENT_COUNT);
        glVertexAttribPointer(aColorLocation, COLOR_COMPONENT_COUNT, GL_FLOAT,
                false, STRIDE, vertexData);

        glDrawArrays(GL_TRIANGLE_FAN, 0, pointCount);
    }
}

我们依然是采用三角形扇(GL_TRANGLE_FAN)来绘制正多边形,一个中点顶点+多个边界点.

应当注意的是,顶点数应该比边数多两个,除开一个中心点,边上最后一个点也需要借助边上第一个才能完成最后一段三角形的绘制.

从数学的极限思想上说,圆其实可以认为是边数接近无穷大的正多边形,那么其实我们也可以根据这个来以一个边数非常大的正多边形来近似为圆,比如我们将边数扩大为360试试效果.

我们更新MyRenderer.initShapeList()如下

    private void initShapeList(float aspectRatio) {
        shapeList.clear();
        //正方形
        addShape(new Square(new Point(-0.5f, aspectRatio * 2 / 3, 0), 0.4f, 0.4f));
        //圆
        addShape(new Polygon(new Point(0.5f, aspectRatio * 2 / 3, 0), 0.2f, 360));
        //正五边形
        addShape(new Polygon(new Point(-0.5f, 0, 0), 0.2f, 5));
        //正六边形
        addShape(new Polygon(new Point(0.5f, 0, 0), 0.2f, 6));
        //正八边形
        addShape(new Polygon(new Point(-0.5f, -aspectRatio * 2 / 3, 0), 0.2f, 8));

    }

运行程序,会获得如下效果

polygon

正三百六十边形在半径不大的情况下已经可以说就是一个圆了.

绘制圆环

圆形我们画完了,我们将正八边形的绘制注释掉,继续画圆环.

com.yxf.variousshape.shapes包下添加Ring类,内容如下

package com.yxf.variousshapes.shapes;

import android.graphics.Color;

import com.yxf.variousshapes.Point;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;

import static android.opengl.GLES20.GL_FLOAT;
import static android.opengl.GLES20.GL_TRIANGLE_STRIP;
import static android.opengl.GLES20.glDrawArrays;
import static android.opengl.GLES20.glVertexAttribPointer;

public class Ring extends Shape {
    private static final int EDGE_COUNT = 180;
    private static final int POINT_COUNT = (EDGE_COUNT + 1) * 2;

    private final float radius;
    private final float width;

    private final int insideColor = Color.YELLOW;
    private final int outsideColor = Color.MAGENTA;

    private float[] vertices;
    private FloatBuffer vertexData;


    public Ring(Point center, float radius, float width) {
        super(center, radius * 2, radius * 2);
        this.radius = radius;
        this.width = width;

        vertices = new float[(POSITION_COMPONENT_COUNT + COLOR_COMPONENT_COUNT) * POINT_COUNT];
        int i = 0;
        while (i < vertices.length) {
            int index = i / (POSITION_COMPONENT_COUNT + COLOR_COMPONENT_COUNT);
            double angle = Math.PI  * index / EDGE_COUNT;
            if (index % 2 == 0) {
                vertices[i++] = center.x + (float) Math.cos(angle) * (radius - width);
                vertices[i++] = center.y + (float) Math.sin(angle) * (radius - width);
                vertices[i++] = Color.red(insideColor) / 255f;
                vertices[i++] = Color.green(insideColor) / 255f;
                vertices[i++] = Color.blue(insideColor) / 255f;
            } else {
                vertices[i++] = center.x + (float) Math.cos(angle) * (radius);
                vertices[i++] = center.y + (float) Math.sin(angle) * (radius);
                vertices[i++] = Color.red(outsideColor) / 255f;
                vertices[i++] = Color.green(outsideColor) / 255f;
                vertices[i++] = Color.blue(outsideColor) / 255f;
            }
            vertexData = ByteBuffer.allocateDirect(vertices.length * BYTES_PER_FLOAT)
                    .order(ByteOrder.nativeOrder())
                    .asFloatBuffer();
            vertexData.put(vertices);
        }
    }

    @Override
    public void draw() {
        vertexData.position(0);
        glVertexAttribPointer(aPositionLocation, POSITION_COMPONENT_COUNT, GL_FLOAT,
                false, STRIDE, vertexData);
        vertexData.position(POSITION_COMPONENT_COUNT);
        glVertexAttribPointer(aColorLocation, COLOR_COMPONENT_COUNT, GL_FLOAT,
                false, STRIDE, vertexData);

        glDrawArrays(GL_TRIANGLE_STRIP, 0, POINT_COUNT);
    }
}

这次使用的glDrawArrays所用的参数是GL_TRIANGLE_STRIP,此参数会连接相邻点绘制三角形,详情见

更新MyRender.initShapeList()如下

    private void initShapeList(float aspectRatio) {
        shapeList.clear();
        //正方形
        addShape(new Square(new Point(-0.5f, aspectRatio * 2 / 3, 0), 0.4f, 0.4f));
        //圆
        addShape(new Polygon(new Point(0.5f, aspectRatio * 2 / 3, 0), 0.2f, 360));
        //正五边形
        addShape(new Polygon(new Point(-0.5f, 0, 0), 0.2f, 5));
        //正六边形
        addShape(new Polygon(new Point(0.5f, 0, 0), 0.2f, 6));
        //正八边形
        //addShape(new Polygon(new Point(-0.5f, -aspectRatio * 2 / 3, 0), 0.2f, 8));
        //圆环
        addShape(new Ring(new Point(-0.5f, -aspectRatio * 2 / 3, 0), 0.2f, 0.03f));

    }

运行程序查看会获得下图效果

ring

绘制正五角星

然后最后一个正五角星

com.yxf.variousshape.shapes包下添加Star类,内容如下

package com.yxf.variousshapes.shapes;

import android.graphics.Color;

import com.yxf.variousshapes.Point;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;

import static android.opengl.GLES20.GL_FLOAT;
import static android.opengl.GLES20.GL_TRIANGLE_FAN;
import static android.opengl.GLES20.glDrawArrays;
import static android.opengl.GLES20.glVertexAttribPointer;

public class Star extends Shape {

    private final int angleCount;
    private final int pointCount;
    private final int size;
    private float[] vertices;
    private FloatBuffer vertexData;
    private final int centerColor = Color.rgb(255, 255, 255);
    private final int circumColor = Color.rgb(0, 0, 255);

    private final float rate;

    public Star(Point center, float size, int angleCount) {
        super(center, size, size);
        this.angleCount = angleCount;
        this.size = (int) size;
        pointCount = angleCount * 2 + 2;
        rate = getRate(angleCount);
        vertices = new float[(POSITION_COMPONENT_COUNT + COLOR_COMPONENT_COUNT) * pointCount];
        int i = 0;
        //中心
        vertices[i++] = center.x;
        vertices[i++] = center.y;
        vertices[i++] = Color.red(centerColor) / 255f;
        vertices[i++] = Color.green(centerColor) / 255f;
        vertices[i++] = Color.blue(centerColor) / 255f;

        while (i < vertices.length) {
            int index = i / (POSITION_COMPONENT_COUNT + COLOR_COMPONENT_COUNT) - 1;
            double angle = Math.PI * index / angleCount;
            if (index % 2 == 1) {
                vertices[i++] = center.x + (float) Math.cos(angle) * size / 2;
                vertices[i++] = center.y + (float) Math.sin(angle) * size / 2;
                vertices[i++] = Color.red(circumColor) / 255f;
                vertices[i++] = Color.green(circumColor) / 255f;
                vertices[i++] = Color.blue(circumColor) / 255f;
            } else {
                vertices[i++] = center.x + (float) Math.cos(angle) * size / 2 / rate;
                vertices[i++] = center.y + (float) Math.sin(angle) * size / 2 / rate;
                vertices[i++] = Color.red(circumColor) / 255f;
                vertices[i++] = Color.green(circumColor) / 255f;
                vertices[i++] = Color.blue(circumColor) / 255f;
            }
        }

        vertexData = ByteBuffer.allocateDirect(vertices.length * BYTES_PER_FLOAT)
                .order(ByteOrder.nativeOrder())
                .asFloatBuffer();
        vertexData.put(vertices);
    }


    /**
     * 获得外径和内径的比值
     *
     * @param angleCount
     * @return
     */
    public static float getRate(int angleCount) {
        float outSizeAngle = (float) ((angleCount - 2) * Math.PI / angleCount);
        float insideAngle = (float) (Math.PI - outSizeAngle);
        return (float) (0.5 / Math.cos(insideAngle) * Math.sin(outSizeAngle / 2) * 2);
    }

    @Override
    public void draw() {
        vertexData.position(0);
        glVertexAttribPointer(aPositionLocation, POSITION_COMPONENT_COUNT, GL_FLOAT,
                false, STRIDE, vertexData);
        vertexData.position(POSITION_COMPONENT_COUNT);
        glVertexAttribPointer(aColorLocation, COLOR_COMPONENT_COUNT, GL_FLOAT,
                false, STRIDE, vertexData);

        glDrawArrays(GL_TRIANGLE_FAN, 0, pointCount);
    }
}

这个类是采用三角扇(GL_TRIANGLE_FAN)画的,其实除了五角星,它也适用于角大于4个的正n角星

更新MyRenderer.initShapeList()如下

    private void initShapeList(float aspectRatio) {
        shapeList.clear();
        //正方形
        //addShape(new Square(new Point(-0.5f, aspectRatio * 2 / 3, 0), 0.4f, 0.4f));
        //圆
        addShape(new Polygon(new Point(0.5f, aspectRatio * 2 / 3, 0), 0.2f, 360));
        //正五边形
        addShape(new Polygon(new Point(-0.5f, 0, 0), 0.2f, 5));
        //正六边形
        addShape(new Polygon(new Point(0.5f, 0, 0), 0.2f, 6));
        //正八边形
        //addShape(new Polygon(new Point(-0.5f, -aspectRatio * 2 / 3, 0), 0.2f, 8));
        //圆环
        addShape(new Ring(new Point(-0.5f, -aspectRatio * 2 / 3, 0), 0.2f, 0.03f));
        //正五角星
        addShape(new Star(new Point(0.5f, -aspectRatio * 2 / 3, 0), 0.4f, 5));
        //正六角星
        addShape(new Star(new Point(-0.5f, aspectRatio * 2 / 3, 0), 0.4f, 6));
    }

代码中注释了正方形,增加了正六角星,运行效果如下

Star

总结

用OpenGL画2D图形相比于Canvas真的费劲不少,不过费劲的同时OpenGL也可以更好的画出一些Canvas画不出来的效果.

OpenGL一般用于3D,在我们接下来进入的OpenGL的3D世界,定会有更多神奇与精彩.

示例源码

OpenGL-VariousShapes

参考

OpenGL ES应用开发实践指南 Android卷

相关链接

OpenGL ES 中 GLSL Shader常见属性说明

Android OpenGL ES 部分方法说明

OpenGL ES初探(一) – 用OpenGL画一个三角形(1)

OpenGL ES初探(二) – 用OpenGL画一个三角形(2)

OpenGL ES初探(四) – 用OpenGL画正四面体,正方体,球

附录

最初的源码

附1

MainActivity.java

package com.yxf.variousshapes;

import android.opengl.GLSurfaceView;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {

    //1,定义GLSurfaceView对象,这个View提供了OpenGL ES的显示窗口
    private GLSurfaceView glSurfaceView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //2,创建GLSurfaceView对象
        glSurfaceView = new GLSurfaceView(this);
        //3,设置OpenGL ES版本为2.0
        glSurfaceView.setEGLContextClientVersion(2);
        //4,设置渲染器
        glSurfaceView.setRenderer(new MyRenderer(this));
        //5,设置GLSurfaceView为主窗口
        setContentView(glSurfaceView);
    }

    @Override
    protected void onPause() {
        super.onPause();
        //6.1,当Activity暂停时暂停glSurfaceView
        glSurfaceView.onPause();
    }

    @Override
    protected void onResume() {
        super.onResume();
        //6.2,当Activity恢复时恢复glSurfaceView
        glSurfaceView.onResume();
    }
}

附2

CommonUtils.java

package com.yxf.variousshapes;

import android.content.Context;
import android.util.Log;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

import static android.opengl.GLES20.GL_COMPILE_STATUS;
import static android.opengl.GLES20.GL_FRAGMENT_SHADER;
import static android.opengl.GLES20.GL_LINK_STATUS;
import static android.opengl.GLES20.GL_VERTEX_SHADER;
import static android.opengl.GLES20.glAttachShader;
import static android.opengl.GLES20.glCompileShader;
import static android.opengl.GLES20.glCreateProgram;
import static android.opengl.GLES20.glCreateShader;
import static android.opengl.GLES20.glGetProgramInfoLog;
import static android.opengl.GLES20.glGetProgramiv;
import static android.opengl.GLES20.glGetShaderInfoLog;
import static android.opengl.GLES20.glGetShaderiv;
import static android.opengl.GLES20.glLinkProgram;
import static android.opengl.GLES20.glShaderSource;

//1,静态导入导入OpenGL ES 2.0常用方法

public class CommonUtils {

    private static final String TAG = "CommonUtils";

    /**
     * 用于读取GLSL Shader文件内容
     *
     * @param context
     * @param resId
     * @return
     */
    public static String readTextFromResource(Context context, int resId) {
        StringBuilder builder = new StringBuilder();
        InputStream inputStream = null;
        InputStreamReader inputStreamReader = null;
        BufferedReader reader = null;
        try {
            inputStream = context.getResources().openRawResource(resId);
            inputStreamReader = new InputStreamReader(inputStream);
            reader = new BufferedReader(inputStreamReader);

            String nextLine;
            while ((nextLine = reader.readLine()) != null) {
                builder.append(nextLine);
                builder.append("\n");
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (reader != null) {
                    reader.close();
                }
                if (inputStreamReader != null) {
                    inputStreamReader.close();
                }
                if (inputStream != null) {
                    inputStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return builder.toString();
    }

    /**
     * 编译着色器
     *
     * @param type
     * @param source
     * @return
     */
    public static int compileShader(int type, String source) {
        final int shaderId = glCreateShader(type);
        if (shaderId == 0) {
            //2,如果着色器创建失败则会返回0
            Log.w(TAG, "Could not create new shader");
            return 0;
        }
        //3,将Shader源文件加载进ID为shaderId的shader中
        glShaderSource(shaderId, source);
        //4,编译这个shader
        glCompileShader(shaderId);
        final int[] status = new int[1];
        //5,获取编译状态储存于status[0]
        glGetShaderiv(shaderId, GL_COMPILE_STATUS, status, 0);

        Log.v(TAG, "compile source : \n" + source + "\n" +
                "info log : " + glGetShaderInfoLog(shaderId));
        if (status[0] == 0) {
            //6,检查状态是否正常,0为不正常
            Log.w(TAG, "Compilation of shader failed.");
            return 0;
        }
        return shaderId;
    }

    /**
     * 编译顶点着色器
     *
     * @param source
     * @return
     */
    public static int compileVertexShader(String source) {
        return compileShader(GL_VERTEX_SHADER, source);
    }

    /**
     * 编译片段着色器
     *
     * @param source
     * @return
     */
    public static int compileFragmentShader(String source) {
        return compileShader(GL_FRAGMENT_SHADER, source);
    }

    /**
     * 创建OpenGL对象,并添加着色器,返回OpenGL对象Id
     * @param vertexShaderId
     * @param fragmentShaderId
     * @return
     */
    public static int linkProgram(int vertexShaderId, int fragmentShaderId) {
        //7,创建OpenGL对象
        final int programId = glCreateProgram();
        if (programId == 0) {
            Log.w(TAG, "Create OpenGL program failed");
            return 0;
        }

        //8,在program上附上着色器
        glAttachShader(programId, vertexShaderId);
        glAttachShader(programId, fragmentShaderId);
        //9,链接程序
        glLinkProgram(programId);
        final int[] status = new int[1];
        glGetProgramiv(programId, GL_LINK_STATUS, status, 0);
        Log.v(TAG, "Results of linking program : \n" + glGetProgramInfoLog(programId));
        if (status[0] == 0) {
            Log.w(TAG, "Link program failed");
            return 0;
        }
        return programId;
    }
}

猜你喜欢

转载自blog.csdn.net/dqh147258/article/details/79818834