时间:2021-02-18 11:18:23 | 栏目:Android代码 | 点击:次
渲染管线一般是由显示芯片GPU内部处理图形信号的并行处理单元组成,这些并行处理单元之间是独立的,从另一个角度看,渲染管线实际上也是一系列绘制过程,这一系列过程的输入是待绘制物体的相关描述信息,输出的是要显示的图像帧数据。
OpenGL ES管线主要包括:
读取顶点数据―>顶点着色器―>组装图元―>光栅化图元―>片元着色器―>写入帧缓冲区―>显示到屏幕上
在OpenGL ES2.0中主要的两个部分就是上面的可编程顶点着色器和片段着色器。学习OpenGL ES主要是要了解渲染管线,了解CPU的渲染过程,主要编程工作在于顶点着色器和片元着色器的编写。
绘制一个六边形
效果如图所示
六边形类
public class SixShape { private FloatBuffer mVertexBuffer; private FloatBuffer mColorBuffer; private int mProgram; private int mPositionHandle; private int mColorHandle; private int muMVPMatrixHandle; public SixShape(float r) { initVetexData(r); } public void initVetexData(float r) { // 初始化顶点坐标 float[] vertexArray = new float[8*3]; // 初始化顶点颜色 float[] colorArray=new float[8*4]; int j = 0, k = 0; vertexArray[j++] = 0; vertexArray[j++] = 0; vertexArray[j++] = 0; colorArray[k++] = 1; colorArray[k++] = 1; colorArray[k++] = 1; colorArray[k++] = 0; for (int angle = 0; angle <= 360; angle += 60) { vertexArray[j++] = (float) (r*Math.cos(Math.toRadians(angle))); vertexArray[j++] = (float) (r*Math.sin(Math.toRadians(angle))); vertexArray[j++] = 0; colorArray[k++] = 1; colorArray[k++] = 0; colorArray[k++] = 0; colorArray[k++] = 0; } ByteBuffer buffer = ByteBuffer.allocateDirect(vertexArray.length * 4); buffer.order(ByteOrder.nativeOrder()); mVertexBuffer = buffer.asFloatBuffer(); mVertexBuffer.put(vertexArray); mVertexBuffer.position(0); ByteBuffer cbb=ByteBuffer.allocateDirect(colorArray.length*4); cbb.order(ByteOrder.nativeOrder()); mColorBuffer=cbb.asFloatBuffer(); mColorBuffer.put(colorArray); mColorBuffer.position(0); int vertexShader = loaderShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode); int fragmentShader = loaderShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode); mProgram = GLES20.glCreateProgram(); GLES20.glAttachShader(mProgram, vertexShader); GLES20.glAttachShader(mProgram, fragmentShader); GLES20.glLinkProgram(mProgram); mPositionHandle = GLES20.glGetAttribLocation(mProgram, "aPosition"); mColorHandle = GLES20.glGetAttribLocation(mProgram, "aColor"); muMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix"); } public void draw(float[] mvpMatrix) { GLES20.glUseProgram(mProgram); // 将顶点数据传递到管线,顶点着色器 GLES20.glVertexAttribPointer(mPositionHandle, 3, GLES20.GL_FLOAT, false, 3 * 4, mVertexBuffer); // 将顶点颜色传递到管线,顶点着色器 GLES20.glVertexAttribPointer(mColorHandle, 4, GLES20.GL_FLOAT, false,4*4, mColorBuffer); // 将变换矩阵传递到管线 GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, mvpMatrix, 0); GLES20.glEnableVertexAttribArray(mPositionHandle); GLES20.glEnableVertexAttribArray(mColorHandle); // 绘制图元 GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, 0, 8); } private int loaderShader(int type, String shaderCode) { int shader = GLES20.glCreateShader(type); GLES20.glShaderSource(shader, shaderCode); GLES20.glCompileShader(shader); return shader; } private String vertexShaderCode = "uniform mat4 uMVPMatrix;" + "attribute vec3 aPosition;" + "attribute vec4 aColor;" + "varying vec4 aaColor;" + "void main(){" + "gl_Position = uMVPMatrix * vec4(aPosition,1);" + "aaColor = aColor;" + "}"; private String fragmentShaderCode = "precision mediump float;" + "varying vec4 aaColor;" + "void main(){" + "gl_FragColor = aaColor;" + "}"; }
六边形View
public class SixView extends GLSurfaceView{ public SixView(Context context) { super(context); setEGLContextClientVersion(2); setRenderer(new MyRender()); } class MyRender implements GLSurfaceView.Renderer { private SixShape circle; @Override public void onSurfaceCreated(GL10 gl, EGLConfig config) { GLES20.glClearColor(0.5f, 0.5f, 0.5f, 1); circle = new SixShape(0.5f); GLES20.glEnable(GLES20.GL_DEPTH_TEST); } // 投影矩阵 private final float[] mProjectionMatrix = new float[16]; // 视图矩阵 private final float[] mViewMatrix = new float[16]; // 模型矩阵 private final float[] mMMatrix = new float[16]; private final float[] mViewProjectionMatrix = new float[16]; private final float[] mMVPMatrix = new float[16]; @Override public void onSurfaceChanged(GL10 gl, int width, int height) { GLES20.glViewport(0, 0, width, height); float ratio= (float) width / height; // 设置正交投影 Matrix.orthoM(mProjectionMatrix, 0, -ratio, ratio, -1, 1, 0, 5); // 设置视图矩阵 Matrix.setLookAtM(mViewMatrix, 0, 0, 0, 2, 0, 0, 0, 0, 1, 0); } @Override public void onDrawFrame(GL10 gl) { GLES20.glClear( GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT); Matrix.multiplyMM(mViewProjectionMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0); // 设置模型矩阵 Matrix.setIdentityM(mMMatrix, 0); Matrix.translateM(mMMatrix,0,0,0,1); Matrix.rotateM(mMMatrix, 0, 30, 0, 0, 1); Matrix.multiplyMM(mMVPMatrix, 0, mViewProjectionMatrix, 0, mMMatrix, 0); circle.draw(mMVPMatrix); } } }
接下来在Activity中就可以使用这个View了。上面的例子虽然简单,但是包括了使用OpenGL ES编程的主要流程,包括生成顶点数据,编写顶点着色器,片元着色器,传递数据给顶点/片元着色器,这里最主要的就是着色器语言。此外包括投影,平移,旋转等操作。在后面会详细学习每个细节以及上面例子没有涉及到的光照,纹理等OpenGL的知识。