Android Opengl es 2.0 画圆,网上说原理的文章挺多的,但要么是1.0的实现,要么无法跑起来。发现一个可以跑起来的方案:http://www.java2s.com/Open-Source/Android_Free_Code/OpenGL/Shape/mkabatek_androidOpenGLShapes.htm。在此记录一下。
原文中由于没有进行坐标转换,所以画出来的圆不是正圆,下面的代码对此进行了更正。当然,你也可以用其他方式变换,比如:http://androidblog.reindustries.com/a-real-open-gl-es-2-0-2d-tutorial-part-1/上面的变换方式。
主要类如下:
Circle.java:
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import android.opengl.GLES20;
import android.util.Log;
public class Circle {
static final int COORDS_PER_VERTEX = 3;
private int mProgram, mPositionHandle, mColorHandle, mMVPMatrixHandle;
private FloatBuffer vertexBuffer;
private float vertices[];
float color[] = {0.00f, 0.76953125f, 0.22265625f, 1.0f};
private final int vertexCount = 364 * 3 / COORDS_PER_VERTEX;
private final int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertex
private final String vertexShaderCode ="attribute vec4 vPosition;"
+ "uniform mat4 uMVPMatrix;"
+ "void main() {"
+ " gl_Position = uMVPMatrix * vPosition;"
+ "}";
private final String fragmentShaderCode =
"precision mediump float;" +
"uniform vec4 vColor;" +
"void main() {" +
" gl_FragColor = vColor;" +
"}";
public Circle() {
int vertexShader = MyGLRenderer.loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode);
int fragmentShader = MyGLRenderer.loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);
vertices = new float[364 * 3];
vertices[0] = 0;
vertices[1] = 0;
vertices[2] = 0;
for (int i =1; i <364; i++){
vertices[(i * 3)+ 0] = (float) (0.5 * Math.cos((3.14/180) * (float)i ));
vertices[(i * 3)+ 1] = (float) (0.5 * Math.sin((3.14/180) * (float)i ));
vertices[(i * 3)+ 2] = 0;
}
Log.v("Thread", "" + vertices[0] + "," + vertices[1] + "," + vertices[2]);
ByteBuffer vertexByteBuffer = ByteBuffer.allocateDirect(vertices.length * 4);
vertexByteBuffer.order(ByteOrder.nativeOrder());
vertexBuffer = vertexByteBuffer.asFloatBuffer();
vertexBuffer.put(vertices);
vertexBuffer.position(0);
mProgram = GLES20.glCreateProgram(); // create empty OpenGL ES Program
GLES20.glAttachShader(mProgram, vertexShader); // add the vertex shader to program
GLES20.glAttachShader(mProgram, fragmentShader); // add the fragment shader to program
GLES20.glLinkProgram(mProgram);
}
public void draw(float[] mvpMatrix) {
// Add program to OpenGL ES environment
GLES20.glUseProgram(mProgram);
// get handle to vertex shader's vPosition member
mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
// Enable a handle to the triangle vertices
GLES20.glEnableVertexAttribArray(mPositionHandle);
// Prepare the triangle coordinate data
GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX,
GLES20.GL_FLOAT, false,
vertexStride, vertexBuffer);
// get handle to fragment shader's vColor member
mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");
// Set color for drawing the triangle
GLES20.glUniform4fv(mColorHandle, 1, color, 0);
mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
// Apply the projection and view transformation
GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);
// Draw the circle
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, 0, vertexCount);
// Disable vertex array
GLES20.glDisableVertexAttribArray(mPositionHandle);
}
}
MyGLRenderer.java
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.opengl.Matrix;
import android.util.Log;
public class MyGLRenderer implements GLSurfaceView.Renderer {
private static final String TAG = "MyGLRenderer";
// initialize a circle
Circle mCircle;
//Our screenresolution
float mScreenWidth = 1920;
float mScreenHeight = 1080;
// mMVPMatrix is an abbreviation for "Model View Projection Matrix"
private final float[] mMVPMatrix = new float[16];
private final float[] mProjectionMatrix = new float[16];
private final float[] mViewMatrix = new float[16];
public void onSurfaceCreated(GL10 unused, EGLConfig config) {
// Set the background frame color
GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
mCircle = new Circle();
}
public void onDrawFrame(GL10 unused) {
// Redraw background color
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
mCircle.draw(mMVPMatrix);
}
public void onSurfaceChanged(GL10 unused, int width, int height) {
mScreenWidth = width;
mScreenHeight = height;
GLES20.glViewport(0, 0, width, height);
// Clear our matrices
for (int i = 0; i < 16; i++) {
mProjectionMatrix[i] = 0.0f;
mViewMatrix[i] = 0.0f;
mMVPMatrix[i] = 0.0f;
}
float ratio = (float) width / height;
// 在onDrawFrame()方法中,将投影矩阵应用到对象的坐标
Matrix.frustumM(mProjectionMatrix, 0, -ratio, ratio, -1, 1, 3, 7);
// Set the camera position (View matrix)
Matrix.setLookAtM(mViewMatrix, 0, 0, 0, -3, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
// Calculate the projection and view transformation
Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0);
}
public static int loadShader(int type, String shaderCode) {
// create a vertex shader type (GLES20.GL_VERTEX_SHADER)
// or a fragment shader type (GLES20.GL_FRAGMENT_SHADER)
int shader = GLES20.glCreateShader(type);
// add the source code to the shader and compile it
GLES20.glShaderSource(shader, shaderCode);
GLES20.glCompileShader(shader);
return shader;
}
public static void checkGlError(String glOperation) {
int error;
while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
Log.e(TAG, glOperation + ": glError " + error);
throw new RuntimeException(glOperation + ": glError " + error);
}
}
}
如果坐标变换变为下面这样:
// Setup our screen width and height for normal sprite translation.
Matrix.orthoM(mProjectionMatrix, 0, 0f, width, 0.0f, height, 0, 50);
// Set the camera position (View matrix)
Matrix.setLookAtM(mViewMatrix, 0, 0f, 0f, 1f, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
// Calculate the projection and view transformation
Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0);
vertices = new float[364 * 3];
int x = 540,y=960,r=200;
for (int i =0; i <364; i++){
vertices[(i * 3)+ 0] = (float) (Math.cos((3.14/180) * (float)i )) * r +x;
vertices[(i * 3)+ 1] = (float) (Math.sin((3.14/180) * (float)i )) * r + y;
vertices[(i * 3)+ 2] = 0;
}
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, 0, vertexCount);
变为:
GLES20.glDrawArrays(GLES20.GL_LINE_STRIP, 0, vertexCount);//空心