資料來源: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變量在存儲光照參數(光照位置、方向等)、變換矩陣、紋理對象句柄等這一類型的數據時很是有用。
效果圖:
代碼連接: