I'm new in OpenGL ES 2, and I have read many topics about how to draw a circle in OpenGL ES 2 on Android. Based on Drawing Shapes and this code found on gamedev.net, I can draw triangles and quares, but I still don't know how to draw a circle. I now have three ways to draw a circle:
But how do I implement them?
I definitely do not recommend rendering a circle through geometry. It has two major disadvantages:
There is another method, which I personally use in every graphics API. Rendering at least a triangle or a sqare/quad and use the fragment-shader to only make the disired (based on a equation) pixel visible. It is very easy to understand. It is flexible and fast. It needs blending, but this is not really hard to get to work.
Steps:
Initialize your buffers with data. You need a vertex-buffer for the vertices, an index-buffer for the indices if you're a using a square geometry, and a textureCoord-buffer for your texture coordinates. For a square I recommend using -1.0 as the lowest and 1.0 as the highest texture coordinate, because then you are able to use the unit circle equation.
In your fragment-shader, use something like this:
if ((textureCoord.x * textureCoord.x) + (textureCoord.y * textureCoord.y) <= 1.0)
{
// Render colored and desired transparency
}
else
{
// Render with 0.0 in alpha channel
}
While (textureCoord.x * textureCoord.x) + (textureCoord.y * textureCoord.y) <= 1.0 is the inequality, because you need a circle, you have to render every pixel within that range, not just the border. You can change this so that it gives you the desired output.
And that is it. Not very complex to implement, so I don't offer any basic rendering code here. All you need happens within the fragment-shader.
If you want to create geometry for the circle, do something like this:
int vertexCount = 30;
float radius = 1.0f;
float center_x = 0.0f;
float center_y = 0.0f;
// Create a buffer for vertex data
float buffer[] = new float[vertexCount*2]; // (x,y) for each vertex
int idx = 0;
// Center vertex for triangle fan
buffer[idx++] = center_x;
buffer[idx++] = center_y;
// Outer vertices of the circle
int outerVertexCount = vertexCount-1;
for (int i = 0; i < outerVertexCount; ++i){
float percent = (i / (float) (outerVertexCount-1));
float rad = percent * 2*Math.PI;
//Vertex position
float outer_x = center_x + radius * cos(rad);
float outer_y = center_y + radius * sin(rad);
buffer[idx++] = outer_x;
buffer[idx++] = outer_y;
}
//Create VBO from buffer with glBufferData()
Then you can draw using glDrawArrays() either as:
.
// Draw circle contours (skip center vertex at start of the buffer)
glDrawArrays(GL_LINE_LOOP, 2, outerVertexCount);
// Draw circle as a filled shape
glDrawArrays(GL_TRIANGLE_FAN, 0, vertexCount);
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import android.opengl.GLES20;
import android.util.Log;
public class Circle {
private int mProgram, mPositionHandle, mColorHandle, mMVPMatrixHandle ;
private FloatBuffer mVertexBuffer;
private float vertices[] = new float[364 * 3];
float color[] = { 0.63671875f, 0.76953125f, 0.22265625f, 1.0f };
private final String vertexShaderCode =
"uniform mat4 uMVPMatrix;" +
"attribute vec4 vPosition;" +
"void main() {" +
" gl_Position = uMVPMatrix * vPosition;" +
"}";
private final String fragmentShaderCode =
"precision mediump float;" +
"uniform vec4 vColor;" +
"void main() {" +
" gl_FragColor = vColor;" +
"}";
Circle(){
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());
mVertexBuffer = vertexByteBuffer.asFloatBuffer();
mVertexBuffer.put(vertices);
mVertexBuffer.position(0);
int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode);
int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);
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 static int loadShader(int type, String shaderCode){
int shader = GLES20.glCreateShader(type);
GLES20.glShaderSource(shader, shaderCode);
GLES20.glCompileShader(shader);
return shader;
}
public void draw (float[] mvpMatrix){
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, 3,
GLES20.GL_FLOAT, false,12
,mVertexBuffer);
// 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 triangle
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, 0, 364);
// Disable vertex array
GLES20.glDisableVertexAttribArray(mPositionHandle);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With