Cómo dibujar círculo básico en OpenGL ES 2.0 Android

Soy nuevo en OpenGL ES 2, y he leído muchos temas sobre cómo dibujar un círculo en OpenGL ES 2 en Android. Basado en dibujo formas y este código se encuentra en gamedev.net , puedo dibujar triángulos y quares, pero todavía no sé cómo dibujar un círculo. Ahora tengo tres maneras de dibujar un círculo:

  1. Genere vértices en un círculo y use glDrawArray (GL_LINES, …). Dependiendo de cuántos vértices genere, obtendrá un resultado agradable y nítido.
  2. Usa una textura pregenerada de un círculo (con transparencia alfa) y haz un mapa en un cuadrángulo. Esto resultará en gráficos muy suaves y permitirá un círculo "grueso", pero no será tan flexible: Incluso con mipmapping, usted querrá que su textura sea aproximadamente del mismo tamaño que está representando el quad.
  3. Utilice un shader de fragmentos.

¿Pero cómo los implemento?

Si desea crear geometría para el círculo, haga algo como esto:

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() 

A continuación, puede dibujar utilizando glDrawArrays () como:

  • GL_LINE_LOOP (solo contorno) o
  • GL_TRIANGLE_FAN (forma llena)

.

 // 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); 

Definitivamente no recomiendo hacer un círculo a través de la geometría. Tiene dos desventajas principales:

  1. Es lento. Si desea obtener una precisión aceptable necesita muchos vértices y cualquiera de estos vértices debe procesarse en el sombreado. Para un círculo real necesita tantos vértices como su círculo tiene píxeles.
  2. No es muy flexible. Tener diferentes círculos, estilo y colring ellos es difícil de dominar.

Hay otro método, que personalmente uso en cada API de gráficos. Renderizar al menos un triángulo o un sqare / quad y utilizar el fragment-shader para hacer sólo visible el pixel (basado en una ecuación). Es muy fácil de entender. Es flexible y rápido. Necesita mezcla, pero esto no es realmente difícil de conseguir para trabajar.

Pasos:

Inicialice sus búferes con datos. Necesitas un buffer de vértices para los vértices, un buffer de índices para los índices si usas una geometría cuadrada y un buffer textureCoord para tus coordenadas de textura. Para un cuadrado recomiendo usar -1.0 como el más bajo y 1.0 como la mayor coordenada de textura, porque entonces usted es capaz de usar la ecuación de círculo unidad.

En tu fragment-shader, usa algo como esto:

 if ((textureCoord.x * textureCoord.x) + (textureCoord.y * textureCoord.y) <= 1.0) { // Render colored and desired transparency } else { // Render with 0.0 in alpha channel } 

Mientras que (textureCoord.x * textureCoord.x) + (textureCoord.y * textureCoord.y) <= 1.0 es la desigualdad, porque necesitas un círculo, tienes que renderizar cada píxel dentro de ese rango, no solo el borde. Puede cambiar esto para que le dé la salida deseada.

Y eso es todo. No es muy complejo de implementar, así que no ofrezco ningún código de renderización básico aquí. Todo lo que necesitas sucede dentro del fragment-shader.

 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); } } 

Esta es una versión modificada de la respuesta anterior. También incluye el código para colorear el círculo también. La mayoría de las funciones se utilizan como OpenGL ES1 sin embargo. Cuidado con las convenciones de nomenclatura del baño de clase, LOL. Si necesitas el código de otras clases donde también muestre OpenGL, hazme saber.

 import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.FloatBuffer; import javax.microedition.khronos.opengles.GL10; public class Toilet { // Circle variables int circlePoints = 30; float radius = 1.0f; float center_x = 0.0f; float center_y = 0.0f; // Outer vertices of the circle ie excluding the center_x, center_y int circumferencePoints = circlePoints-1; // Circle vertices and buffer variables int vertices = 0; float circleVertices[] = new float[circlePoints*2]; private FloatBuffer toiletBuff; // 4 bytes per float // Color values private float rgbaValues[] = { 1, 1, 0, .5f, .25f, 0, .85f, 1, 0, 1, 1, 1 }; private FloatBuffer colorBuff; public Toilet() { // The initial buffer values circleVertices[vertices++] = center_x; circleVertices[vertices++] = center_y; // Set circle vertices values for (int i = 0; i < circumferencePoints; i++) { float percent = (i / (float) (circumferencePoints - 1)); float radians = (float) (percent * 2 * Math.PI); // Vertex position float outer_x = (float) (center_x + radius * Math.cos(radians)); float outer_y = (float) (center_y + radius * Math.sin(radians)); circleVertices[vertices++] = outer_x; circleVertices[vertices++] = outer_y; } // Float buffer short has four bytes ByteBuffer toiletByteBuff = ByteBuffer .allocateDirect(circleVertices.length * 4); // Garbage collector won't throw this away toiletByteBuff.order(ByteOrder.nativeOrder()); toiletBuff = toiletByteBuff.asFloatBuffer(); toiletBuff.put(circleVertices); toiletBuff.position(0); // Float buffer short has four bytes ByteBuffer clrBuff = ByteBuffer.allocateDirect(rgbaValues.length * 4); // garbage collector wont throw this away clrBuff.order(ByteOrder.nativeOrder()); colorBuff = clrBuff.asFloatBuffer(); colorBuff.put(rgbaValues); colorBuff.position(0); } // Draw methods public void draw(GL10 gl) { // Get the front face gl.glFrontFace(GL10.GL_CW); // Front facing is clockwise gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); // Enable color array gl.glEnableClientState(GL10.GL_COLOR_ARRAY); // Pointer to the buffer gl.glVertexPointer(2, GL10.GL_FLOAT, 0, toiletBuff); // Pointer to color gl.glColorPointer(4, GL10.GL_FLOAT, 0, colorBuff); // Draw hollow circle //gl.glDrawArrays(GL10.GL_LINE_LOOP, 1, circumferencePoints); // Draw circle as filled shape gl.glDrawArrays(GL10.GL_TRIANGLE_FAN, 0, circlePoints); gl.glDisableClientState(GL10.GL_COLOR_ARRAY); gl.glDisableClientState(GL10.GL_VERTEX_ARRAY); } } 

Un fallo importante que noté en el post de la portería: No puedes cambiar la posición del círculo.

Aquí está la solución. Observe el final de las dos primeras líneas en el bucle 'for'.

 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[0]); vertices[(i * 3)+ 1] = (float) (0.5 * Math.sin((3.14/180) * (float)i ) + vertices[1]); vertices[(i * 3)+ 2] = 0; } 
  • Cómo mejorar el rendimiento de la representación de ping-pong (para desenfoque) en OpenGL ES
  • No se puede lograr 60fps rendering quad simple, Android, Opengl ES 2.0
  • Carga rápida de texturas en OpenGL 2.0
  • Android NDK - OpenGL ES 2.0 - vinculación de la biblioteca
  • Algunos tutoriales para OpenGL ES 2 en Android con NDK?
  • ¿Por qué mi programa de shader openGL para puntos tiene anillos de artefactos?
  • OpenGL en Android versus iOS: optimizaciones, y donde difieren
  • LibGDX - Shader trabajando en el escritorio pero no en Android
  • Cómo pasar los datos correctos a un programa de shader OpenGL-ES 2.0
  • Dibujo de un gradiente en Libgdx
  • Compartir el contexto EGL2.0 entre 2 GLSurfaceViews causó EGL_BAD_ACCESS en las tabletas Android
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.