看Opengl es的相关知识也有几天了。开始动手跟着例子写代码了。现在就先写个最简单的,画个三角形吧,里面包含了最基本的vertex shader和fragment shader的用法.
Activity里设置opengl es版本为2.0,如果没设,会默认用1.0,然后运行会报API未实现exception.
TestActivity.java
1 package com.android.jayce.test; 2 3 import android.app.Activity; 4 import android.app.ActivityManager; 5 import android.content.Context; 6 import android.content.pm.ConfigurationInfo; 7 import android.opengl.GLSurfaceView; 8 import android.opengl.GLSurfaceView.Renderer; 9 import android.os.Bundle; 10 11 public class TestActivity extends Activity 12 { 13 private GLSurfaceView mGLSurfaceView; 14 15 public void onCreate(Bundle savedInstanceState) 16 { 17 super.onCreate(savedInstanceState); 18 mGLSurfaceView = new GLSurfaceView(this); 19 final ActivityManager activityManager = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE); 20 final ConfigurationInfo configInfo = activityManager.getDeviceConfigurationInfo(); 21 if(configInfo.reqGlEsVersion >= 0x20000) 22 { 23 mGLSurfaceView.setEGLContextClientVersion(2); 24 Renderer renderer = new TestRenderer(); 25 mGLSurfaceView.setRenderer(renderer); 26 } 27 28 setContentView(mGLSurfaceView); 29 } 30 31 @Override 32 protected void onResume() 33 { 34 // The activity must call the GL surface view's onResume() on activity onResume(). 35 super.onResume(); 36 mGLSurfaceView.onResume(); 37 } 38 39 @Override 40 protected void onPause() 41 { 42 // The activity must call the GL surface view's onPause() on activity onPause(). 43 super.onPause(); 44 mGLSurfaceView.onPause(); 45 } 46 }
然后是Renderer的实现,参数很少,只有点坐标,颜色
TestRenderer.java
1 package com.android.jayce.test; 2 3 import java.nio.ByteBuffer; 4 import java.nio.ByteOrder; 5 import java.nio.FloatBuffer; 6 7 import javax.microedition.khronos.egl.EGLConfig; 8 import javax.microedition.khronos.opengles.GL10; 9 10 import android.opengl.GLES20; 11 import android.opengl.Matrix; 12 import android.opengl.GLSurfaceView; 13 14 15 public class TestRenderer implements GLSurfaceView.Renderer 16 { 17 18 private final FloatBuffer mTriangle1Vertices; 19 private static final int BYTES_PER_FLOAT = 4; 20 private float[] mMVPMatrix = new float[16]; 21 private float[] mViewMatrix = new float[16]; 22 private float[] mModelMatrix = new float[16]; 23 private float[] mProjectionMatrix = new float[16]; 24 private int mMVPMatrixHandle; 25 private int mPositionHandle; 26 private int mColorHandle; 27 private final int POSITION_OFFSET = 0; 28 private final int COLOR_OFFSET = 3; 29 private final int POSITION_DATA_SIZE = 3; 30 private final int COLOR_DATA_SIZE = 4; 31 private final int STRIDE = 7 * BYTES_PER_FLOAT; 32 33 public TestRenderer() 34 { 35 final float[] triangle1VerticesData = { 36 // X, Y, Z, 37 // R, G, B, A 38 -0.5f, -0.25f, 0.0f, 39 1.0f, 0.0f, 0.0f, 1.0f, 40 41 0.5f, -0.25f, 0.0f, 42 0.0f, 0.0f, 1.0f, 1.0f, 43 44 0.0f, 0.559016994f, 0.0f, 45 0.0f, 1.0f, 0.0f, 1.0f}; 46 47 mTriangle1Vertices = ByteBuffer.allocateDirect(triangle1VerticesData.length * BYTES_PER_FLOAT) 48 .order(ByteOrder.nativeOrder()).asFloatBuffer(); 49 mTriangle1Vertices.put(triangle1VerticesData).position(0); 50 } 51 52 @Override 53 public void onDrawFrame(GL10 gl) { 54 // TODO Auto-generated method stub 55 GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT); 56 57 Matrix.setIdentityM(mModelMatrix, 0); 58 drawTriandle(mTriangle1Vertices); 59 } 60 61 private void drawTriandle(final FloatBuffer triangleBuffer) 62 { 63 triangleBuffer.position(POSITION_OFFSET); 64 GLES20.glVertexAttribPointer(mPositionHandle, POSITION_DATA_SIZE, GLES20.GL_FLOAT, false, STRIDE, triangleBuffer); 65 GLES20.glEnableVertexAttribArray(mPositionHandle); 66 67 triangleBuffer.position(COLOR_OFFSET); 68 GLES20.glVertexAttribPointer(mColorHandle, COLOR_DATA_SIZE, GLES20.GL_FLOAT, false, STRIDE, triangleBuffer); 69 GLES20.glEnableVertexAttribArray(mColorHandle); 70 71 Matrix.multiplyMM(mMVPMatrix, 0, mViewMatrix, 0, mModelMatrix, 0); 72 Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mMVPMatrix, 0); 73 74 GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mMVPMatrix, 0); 75 GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 3); 76 } 77 78 @Override 79 public void onSurfaceChanged(GL10 gl, int width, int height) { 80 // TODO Auto-generated method stub 81 GLES20.glViewport(0, 0, width, height); 82 83 final float ratio = (float) width / height; 84 final float left = -ratio; 85 final float right = ratio; 86 final float bottom = -1.0f; 87 final float top = 1.0f; 88 final float near = 1.0f; 89 final float far = 10.0f; 90 91 Matrix.frustumM(mProjectionMatrix, 0, left, right, bottom, top, near, far); 92 } 93 94 @Override 95 public void onSurfaceCreated(GL10 gl, EGLConfig config) { 96 // TODO Auto-generated method stub 97 GLES20.glClearColor(0f, 0f, 0f, 1f); 98 99 // Position the eye behind the origin. 100 final float eyeX = 0.0f; 101 final float eyeY = 0.0f; 102 final float eyeZ = 1.5f; 103 104 // We are looking toward the distance 105 final float lookX = 0.0f; 106 final float lookY = 0.0f; 107 final float lookZ = -5.0f; 108 109 // Set our up vector. This is where our head would be pointing were we holding the camera. 110 final float upX = 0.0f; 111 final float upY = 1.0f; 112 final float upZ = 0.0f; 113 114 // Set the view matrix. This matrix can be said to represent the camera position. 115 // NOTE: In OpenGL 1, a ModelView matrix is used, which is a combination of a model and 116 // view matrix. In OpenGL 2, we can keep track of these matrices separately if we choose. 117 Matrix.setLookAtM(mViewMatrix, 0, eyeX, eyeY, eyeZ, lookX, lookY, lookZ, upX, upY, upZ); 118 119 final String vertexShader = 120 "uniform mat4 u_MVPMatrix; \n" // A constant representing the combined model/view/projection matrix. 121 122 + "attribute vec4 a_Position; \n" // Per-vertex position information we will pass in. 123 + "attribute vec4 a_Color; \n" // Per-vertex color information we will pass in. 124 125 + "varying vec4 v_Color; \n" // This will be passed into the fragment shader. 126 127 + "void main() \n" // The entry point for our vertex shader. 128 + "{ \n" 129 + " v_Color = a_Color; \n" // Pass the color through to the fragment shader. 130 // It will be interpolated across the triangle. 131 + " gl_Position = u_MVPMatrix \n" // gl_Position is a special variable used to store the final position. 132 + " * a_Position; \n" // Multiply the vertex by the matrix to get the final point in 133 + "} \n"; // normalized screen coordinates. 134 135 final String fragmentShader = 136 "precision mediump float; \n" // Set the default precision to medium. We don't need as high of a 137 // precision in the fragment shader. 138 + "varying vec4 v_Color; \n" // This is the color from the vertex shader interpolated across the 139 // triangle per fragment. 140 + "void main() \n" // The entry point for our fragment shader. 141 + "{ \n" 142 + " gl_FragColor = v_Color; \n" // Pass the color directly through the pipeline. 143 + "} \n"; 144 145 int vertexShaderHandle = GLES20.glCreateShader(GLES20.GL_VERTEX_SHADER); 146 if(vertexShaderHandle != 0) 147 { 148 GLES20.glShaderSource(vertexShaderHandle, vertexShader); 149 GLES20.glCompileShader(vertexShaderHandle); 150 151 final int[] compileStatus = new int[1]; 152 GLES20.glGetShaderiv(vertexShaderHandle, GLES20.GL_COMPILE_STATUS, compileStatus, 0); 153 154 if(compileStatus[0] == 0) 155 { 156 GLES20.glDeleteShader(vertexShaderHandle); 157 vertexShaderHandle = 0; 158 } 159 } 160 161 if(vertexShaderHandle == 0) 162 { 163 throw new RuntimeException("failed to creating vertex shader"); 164 } 165 166 int fragmentShaderHandle = GLES20.glCreateShader(GLES20.GL_FRAGMENT_SHADER); 167 if(fragmentShaderHandle != 0) 168 { 169 GLES20.glShaderSource(fragmentShaderHandle, fragmentShader); 170 GLES20.glCompileShader(fragmentShaderHandle); 171 172 final int[] compileStatus = new int[1]; 173 GLES20.glGetShaderiv(fragmentShaderHandle, GLES20.GL_COMPILE_STATUS, compileStatus, 0); 174 175 if(compileStatus[0] == 0) 176 { 177 GLES20.glDeleteShader(fragmentShaderHandle); 178 fragmentShaderHandle = 0; 179 } 180 181 } 182 183 if(fragmentShaderHandle == 0) 184 { 185 throw new RuntimeException("failed to create fragment shader"); 186 } 187 188 int programHandle = GLES20.glCreateProgram(); 189 if(programHandle != 0) 190 { 191 GLES20.glAttachShader(programHandle, vertexShaderHandle); 192 GLES20.glAttachShader(programHandle, fragmentShaderHandle); 193 194 GLES20.glBindAttribLocation(programHandle, 0, "a_Position"); 195 GLES20.glBindAttribLocation(programHandle, 1, "a_Color"); 196 197 GLES20.glLinkProgram(programHandle); 198 199 final int[] linkStatus = new int[1]; 200 GLES20.glGetProgramiv(programHandle, GLES20.GL_LINK_STATUS, linkStatus, 0); 201 202 if(linkStatus[0] == 0) 203 { 204 GLES20.glDeleteProgram(programHandle); 205 programHandle = 0; 206 } 207 } 208 209 if(programHandle == 0) 210 { 211 throw new RuntimeException("failed to create program"); 212 } 213 214 mMVPMatrixHandle = GLES20.glGetUniformLocation(programHandle, "u_MVPMatrix"); 215 mPositionHandle = GLES20.glGetAttribLocation(programHandle, "a_Position"); 216 mColorHandle = GLES20.glGetAttribLocation(programHandle, "a_Color"); 217 218 GLES20.glUseProgram(programHandle); 219 } 220 221 222 223 }
最后附上效果图: