资料来源:java
OpenGL ES 2 for Android —a Quick-Start Guideandroid
https://developer.android.com/guide/topics/graphics/openglgit
本章文章只是简单的画一个三角形到手机端中,比较简单,直接看着官网资料就能写出来,下面是代码:github
Manifest中声明使用的opengl es版本:缓存
<uses-feature android:glEsVersion="0x00030000" android:required="true" />
xml中直接声明一个全屏的GLSurfaceView,这里不就贴了。ide
在MainActivity中:ui
private GLSurfaceView mSurfaceView; @Override protected void onPause() { super.onPause(); if (mSurfaceView != null) { mSurfaceView.onPause(); } } @Override protected void onResume() { super.onResume(); if (mSurfaceView != null) { mSurfaceView.onResume(); } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); intGL(); } private void intGL() { mSurfaceView = findViewById(R.id.gl); mSurfaceView.setEGLContextClientVersion(3); mSurfaceView.setEGLConfigChooser(8, 8, 8, 8, 16, 0); mSurfaceView.setRenderer(new MyRenderer()); //RenderMode 有两种,RENDERMODE_WHEN_DIRTY 和 RENDERMODE_CONTINUOUSLY, // 前者是懒惰渲染,须要手动调用 glSurfaceView.requestRender() 才会进行更新,然后者则是不停渲染。 mSurfaceView.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY); } private static class MyRenderer implements GLSurfaceView.Renderer { private Triangle mSquare; @Override public void onSurfaceCreated(GL10 unused, EGLConfig config) { mSquare = new Triangle(); } @Override public void onSurfaceChanged(GL10 unused, int width, int height) { //设置 Screen space 的大小 GLES30.glViewport(0, 0, width, height); } //绘制的过程其实就是为 shader 代码变量赋值,并调用绘制命令的过程 @Override public void onDrawFrame(GL10 unused) { mSquare.onDraw(); } }
Triangle文件:this
public class Triangle { private FloatBuffer vertexBuffer; private final String vertexShaderCode = "#version 300 es \n" + "layout(location = 0) in vec4 vPosition;\n" + "layout(location = 1) in vec4 aColor;\n"+ "out vec4 vColor;"+ "void main() {\n" + "gl_Position = vPosition;\n" + "vColor=aColor;\n" + "}"; private final String fragmentShaderCode = "#version 300 es \n" + "precision mediump float;\n" + "out vec4 fragColor;\n" + "in vec4 vColor;" + "void main() {\n" + "fragColor = vColor;\n" + "}"; // number of coordinates per vertex in this array static final int COORDS_PER_VERTEX = 3; static float triangleCoords[] = { // in counterclockwise order: 0.0f, 0.622008459f, 0.0f, // top -0.5f, -0.311004243f, 0.0f, // bottom left 0.5f, -0.311004243f, 0.0f // bottom right }; private final int mProgram; // Set color with red, green, blue and alpha (opacity) values float color[] = { 1.0f,0.0f,0.0f, 1.0f }; public static int loadShader(int type, String shaderCode){ // create a vertex shader type (GLES30.GL_VERTEX_SHADER) // or a fragment shader type (GLES30.GL_FRAGMENT_SHADER) int shader = GLES30.glCreateShader(type); // add the source code to the shader and compile it GLES30.glShaderSource(shader, shaderCode); GLES30.glCompileShader(shader); return shader; } public Triangle() { // initialize vertex byte buffer for shape coordinates ByteBuffer bb = ByteBuffer.allocateDirect( // (number of coordinate values * 4 bytes per float) triangleCoords.length * 4); // use the device hardware's native byte order bb.order(ByteOrder.nativeOrder()); // create a floating point buffer from the ByteBuffer vertexBuffer = bb.asFloatBuffer(); // add the coordinates to the FloatBuffer vertexBuffer.put(triangleCoords); // set the buffer to read the first coordinate vertexBuffer.position(0); int vertexShader = loadShader(GLES30.GL_VERTEX_SHADER, vertexShaderCode); int fragmentShader = loadShader(GLES30.GL_FRAGMENT_SHADER, fragmentShaderCode); // create empty OpenGL ES Program mProgram = GLES30.glCreateProgram(); // add the vertex shader to program GLES30.glAttachShader(mProgram, vertexShader); // add the fragment shader to program GLES30.glAttachShader(mProgram, fragmentShader); // creates OpenGL ES program executables GLES30.glLinkProgram(mProgram); } private int mPositionHandle; private int mColorHandle; private final int vertexCount = triangleCoords.length / COORDS_PER_VERTEX; private final int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertex public void onDraw(){ // Add program to OpenGL ES environment GLES30.glUseProgram(mProgram); // get handle to vertex shader's vPosition member mPositionHandle = GLES30.glGetAttribLocation(mProgram, "vPosition"); // Enable a handle to the triangle vertices GLES30.glEnableVertexAttribArray(mPositionHandle); // Prepare the triangle coordinate data GLES30.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX, GLES30.GL_FLOAT, false, vertexStride, vertexBuffer); // get handle to fragment shader's vColor member mColorHandle = GLES30.glGetAttribLocation(mProgram, "aColor"); // Set color for drawing the triangle GLES30.glVertexAttrib4fv(mColorHandle, color, 0); // Draw the triangle GLES30.glDrawArrays(GLES30.GL_TRIANGLES, 0, vertexCount); // Disable vertex array GLES30.glDisableVertexAttribArray(mPositionHandle); } }
这样就会在GlSurfaceView当中绘制出一个三角形了。spa
这里顺便记录一下对应的glVertexAttrib4fv()
和glUniform4fv()
的区别:.net
private final String vertexShaderCode = "#version 300 es \n" + "layout(location = 0) in vec4 vPosition;\n" + "layout(location = 1) in vec4 aColor;\n"+ //和下面代码的区别 "out vec4 vColor;"+ "void main() {\n" + "gl_Position = vPosition;\n" + "vColor=aColor;\n" + "}"; private final String fragmentShaderCode = "#version 300 es \n" + "precision mediump float;\n" + "out vec4 fragColor;\n" + "in vec4 vColor;" + "void main() {\n" + "fragColor = vColor;\n" + "}"; ... // get handle to fragment shader's vColor member mColorHandle = GLES30.glGetAttribLocation(mProgram, "aColor"); // Set color for drawing the triangle GLES30.glVertexAttrib4fv(mColorHandle, color, 0);
上述代码中在glsl语言中使用了in vec4 aColor;
说明这个变量经由外部传递,是个可变的参数(即咱们在第一次刷新能够设置为红色,第二次刷新能够改变成蓝色),使用的方法则是经过glVertexAttrib4fv()
或者glVertexAttrib4f()
来进行传递 ,而若是使用了底下的代码的话:
private final String vertexShaderCode = "#version 300 es \n" + "layout(location = 0) in vec4 vPosition;\n" + "void main() {\n" + "gl_Position = vPosition;\n" + "}"; private final String fragmentShaderCode = "#version 300 es \n" + "precision mediump float;\n" + "out vec4 fragColor;\n" + "uniform vec4 vColor;\n"+ //区别 "void main() {\n" + "fragColor = vColor;\n" + "}"; .... mColorHandle = GLES30.glGetUniformLocation(mProgram, "vColor"); // Set color for drawing the triangle // GLES30.glVertexAttrib4fv(mColorHandle, color, 0); GLES30.glUniform4fv(mColorHandle, 1, color, 0);
那么永远都只会是一种颜色,由于uniform
设置至关于java里的final和c中的const,即常量的概念。
若是讲的不太清楚,引用一下大牛的博客(基于opengl es2.0,3.0中使用in类型来表明attribute):
attribute(属性)变量和uniform变量的不一样之处在于attribute 变量中包含顶点的具体数据,当每次执行shader调用时会从顶点缓存中从新加载一个新的值。而uniform类型的变量在整个绘制调用中始终使用同一个变量。这意味着你在绘制调用前加载的值在每一个vertex shader调用时能访问到相同的值。uniform变量在存储光照参数(光照位置、方向等)、变换矩阵、纹理对象句柄等这一类型的数据时很是有用。
效果图:
代码连接: