English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
OpenGL ES es un subconjunto del API de gráficos tridimensionales OpenGL, diseñado para dispositivos嵌入式 como teléfonos inteligentes, PDA y consolas de juegos. Ophone currently supports OpenGL ES 1.0, OpenGL ES 1.0 se basa en la norma OpenGL 1.3 basada en la norma, OpenGL ES 1.1 Se basa en la norma OpenGL 1.5 basada en la norma. Este artículo principalmente introduce los pasos básicos para dibujar gráficos utilizando OpenGL ES.
El contenido de este artículo se compone de tres partes. Primero, obtener la interfaz de programación de OpenGL ES a través de EGL; luego, se introduce la construcción3Conceptos básicos del programa D; por último, un ejemplo de aplicación.
OpenGL ES es esencialmente un estado de máquina de tubería de renderizado gráfico, mientras que EGL es una capa externa para monitorear estos estados y mantener el buffer de cuadros y otras superficies de renderizado.1 Es un diagrama de disposición típico del sistema EGL. El diseño del ventanal EGL se basa en la interfaz nativa de OpenGL conocida para Microsoft Windows (WGL) y UNIX (GLX), que es más cercana a este último. El estado de la tubería gráfica de OpenGL ES se almacena en un contexto administrado por EGL. Los buffers de cuadros y otras superficies de renderizado se crean, gestionan y destruyen a través de la API EGL. EGL también controla y proporciona acceso a la configuración de visualización del dispositivo y a la posible configuración de renderizado del dispositivo.
imagen1
OpenGL ES necesita un contexto de renderizado y una superficie de renderizado. El contexto de renderizado almacena la información de estado de OpenGL ES, y la superficie de renderizado se utiliza para dibujar primitivas. Antes de escribir OpenGL ES, las operaciones de EGL necesarias son: }}
Consultar los punteros de visualización que el dispositivo puede soportar y inicializar.
Crear la superficie de renderizado, dibujar gráficos OpenGL ES.
Crear el contexto de renderizado. EGL necesita crear un contexto de renderizado de OpenGL ES para asociarlo con una superficie de renderizado.
En Ophone, EGL incluye4las clases, que son EGLDisplay: puntero de visualización, EGLConfig: clase de configuración; EGLContext: contexto de renderizado; y EGLSurface: clase de vista renderizable.
Se puede considerar que EGL es una capa intermedia entre OpenGL ES y el sistema de ventanas local. El sistema de ventanas local se refiere a GNU/En sistemas Linux, el sistema de ventanas X o Mac OS X's Quartz, entre otros. Antes de que EGL determine el tipo de superficie de renderizado, EGL necesita comunicarse con el sistema de ventanas subyacente. Debido a que los sistemas de ventanas en diferentes sistemas operativos son diferentes, EGL proporciona un tipo de ventana transparente, es decir, EGLDisplay. Abstrae varios sistemas de ventanas. Por lo tanto, primero se debe crear e inicializar un objeto EGLDisplay.
// El método estático getEGL de EGLContext obtiene la instancia de EGL EGL10 egl = (EGL10)EGLContext.getEGL(); //Crear EGLDisplay, EGL_DEFAULT_DISPLAY obtiene el tipo de sistema de ventanas local por defecto EGLDisplay dpy = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); //Al inicializar EGLDispla se obtiene el número de versión int[] version = new int[2]); egl.eglInitialize(dpy, version);
Cada EGLDisplay necesita ser inicializado antes de su uso. Al inicializar EGLDisplay, se puede obtener el número de versión de implementación de EGL en el sistema. A través del número de versión, se puede utilizar adecuadamente el API de OpenGL ES correspondiente, lo que permite escribir programas con buena compatibilidad, adaptándose a más dispositivos y proporcionando la máxima portabilidad. Prototipo de la función de inicialización:
boolean eglInitialize(EGLDisplay display, int[] major_minor)
donde display es una instancia válida de EGLDisplay. Al completar la función de llamada, major_minor se asignará el número de versión actual de EGL. Por ejemplo, EGL1.0 , major_minor[0] es1,major_minor[1] de 0. EGLSurface contiene toda la información relacionada con la superficie de renderizado EGL. Hay dos métodos para consultar la información de configuración de EGLSurface: uno es consultar toda la información de configuración y seleccionar una más adecuada; el otro es especificar la información de configuración y obtener el mejor resultado de coincidencia del sistema. Generalmente se utiliza el segundo método. El usuario especifica la configuración deseada a través de configSpec, y la función eglChooseConfig devuelve la lista de configuraciones más adecuadas como parámetro Configs. Después de obtener Configs, se llama a eglCreateContext para crear un contexto de renderizado, que devuelve la estructura EGLContext. La creación de la superficie de renderizado EGLSurface se realiza mediante la función eglCreateWindowSurface. Una aplicación puede crear múltiples EGLContext. eglMakeCurrent es la función que binda un contexto de renderizado a la superficie de renderizado. Las funciones de consulta eglGetCurrentContext, eglGetCurrentDisplay y eglGetCurrentSurface se utilizan para obtener el contexto de renderizado actual del sistema, el identificador de visualización y la superficie de renderizado. Finalmente, el método estático getGL de EGLContext obtiene la interfaz de programación OpenGL ES. El siguiente fragmento de programa resume lo anterior.
EGL10 egl = (EGL10)EGLContext.getEGL(); EGLDisplay dpy = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); int[] version = new int[2]); egl.eglInitialize(dpy, version); int[] configSpec = { EGL10.EGL_RED_SIZE, 5, EGL10.EGL_GREEN_SIZE, 6, EGL10.EGL_BLUE_SIZE, 5, EGL10.EGL_DEPTH_SIZE, 16, EGL10.EGL_NONE }; EGLConfig[] configs = new EGLConfig[1]); int[] num_config = new int[1]); egl.eglChooseConfig(dpy, configSpec, configs, 1, num_config); EGLConfig config = configs[0]; EGLContext context = egl.eglCreateContext(dpy, config, EGL10.EGL_NO_CONTEXT, null); EGLSurface surface = egl.eglCreateWindowSurface(dpy, config, EGLSurface surface = egl.eglCreateWindowSurface(dpy, config, sHolder, null); GL10 egl.eglMakeCurrent(dpy, surface, surface, context);10gl = (GL
)context.getGL();3Construcción
Punto de la gráfica D3El punto es la construcción4Base del modelo D. Los cálculos internos de OpenGL ES se basan en puntos. Los puntos también pueden representar la posición de la fuente de luz, la posición del objeto. Generalmente, se utiliza un grupo de números flotantes para representar un punto. Por ejemplo, un cuadrado
Un punto se puede representar como: -1.0f, 1.0f, 0.0f, //Arriba a la izquierda -1.0f, -1.0f, 0.0f, //Abajo a la izquierda 1.0f, -1.0f, 0.0f, //Abajo a la derecha 1.0f, 1.0f, 0.0f, //Arriba a la derecha };
Para mejorar el rendimiento, es necesario almacenar el array de flotantes en un búfer de bytes. Por lo tanto, se realizan las siguientes operaciones:
ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4); vbb.order(ByteOrder.nativeOrder()); FloatBuffer vertexBuffer = vbb.asFloatBuffer(); vertexBuffer.put(vertices); vertexBuffer.position(0);
donde ByteOrder.nativeOrder() es obtener el orden de bytes del sistema. OpenGL ES tiene funciones para operar en la tubería de renderizado de gráficos, en condiciones predeterminadas, el estado de uso de estas funciones está cerrado. Se puede habilitar y deshabilitar estas funciones con glEnableClientState y glDisableClientState.
// Se especifica el array de vértices que se debe habilitar
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
// Explicación: se habilita el tipo de array y el búfer de bytes, el tipo es GL_FLOAT
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
// Cierre el array de vértices cuando ya no sea necesario
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
Lado
El lado es una línea que conecta dos puntos, que es el borde de la superficie del polígono.
Polígono
El polígono está constituido por lados que forman un círculo cerrado. En OpenGL ES, los polígonos deben ser convexos, es decir, en el interior del polígono, si se toman dos puntos y la línea que los conecta está completamente dentro del polígono, ese polígono es convexo. Al dibujar un polígono, es necesario especificar la dirección de renderizado, que se divide en sentido horario y antihorario. Porque la dirección determina la orientación del polígono, es decir, la cara frontal y la cara posterior. Evitar la renderización de las partes ocultas puede mejorar eficazmente el rendimiento del programa. La función glFrontFace define la dirección de renderizado de los vértices.
// Establece la dirección CCW como 'cara', CCW es CounterClockWise, en el sentido contrario a las agujas del reloj
glFrontFace(GL_CCW);
// Establece la dirección CW como 'cara', CW es ClockWise, en el sentido de las agujas del reloj
glFrontFace(GL_CW);
renderización
Después de explicar los conceptos anteriores, ahora se procede con la tarea principal: la renderización. La renderización convierte los elementos geométricos especificados por las coordenadas del objeto en una imagen del búfer de cuadros. La imagen y las coordenadas de los vértices tienen una relación cercana. Esta relación se proporciona a través del modo de dibujo. Los modos de dibujo comunes son GL_POINTS、GL_LINE_STRIP、
GL_LINE_LOOP、GL_LINES、GL_TRIANGLES、GL_TRIANGLE_STRIP、GL_TRIANGLE_FAN. A continuación, se presentan:
GL_POINTS: Trata cada vértice como un punto, vértice n define el punto n, se dibujan n puntos.
GL_LINES: Considera cada vértice como un segmento independiente, vértice2n-1y2entre sí definen n segmentos, se dibujan N/2segmentos., si N es impar, se ignora el último vértice.
GL_LINE_STRIP: Dibuja un grupo de segmentos conectados desde el primer vértice hasta el último, el n y n+1vértices definen el segmento n, se dibujan N-1segmentos.
GL_LINE_LOOP: Dibuja un grupo de segmentos conectados desde el primer vértice hasta el último, luego el último vértice está conectado al primer vértice. El n y n+1vértices definen el segmento n, luego el último segmento está formado por el vértice N y1entre sí define, se dibujan N segmentos.
GL_TRIANGLES: Considera cada tres vértices como un triángulo independiente. Vértice3n-2,3n-1y3n define el triángulo n, se dibujan N/3triángulos.
GL_TRIANGLE_STRIP: Dibuja un grupo de triángulos conectados. Para n impar, el vértice n, n+1y n+2Define el triángulo n; para n par, el vértice n+1,n y n+2Define el triángulo n, se dibujan N-2triángulos.
GL_TRIANGLE_FAN: Dibuja un grupo de triángulos conectados. Los triángulos están determinados por el primer vértice y los vértices dados posteriores. Vértice1,n+1y n+2Define el triángulo n, se dibujan N-2triángulos.
Funciones de dibujo:
void glDrawArrays(int modo, int primero, int cantidad)
void glDrawElements(int modo, int cantidad, int tipo, Buffer índices)
glDrawArrays crea una secuencia de figuras geométricas, utilizando cada array desde first hasta first + count – 1el elemento final del array, mode es el modo de dibujo.
glDrawElements utiliza count elementos para definir una secuencia de elementos, type es el tipo de datos del array indices, mode es el modo de dibujo, el array indices almacena los vértices
el valor de índice del punto.
ejemplo de aplicación
basado en el contenido explicado anteriormente, proporcione un ejemplo de dibujar en un Ophone3el programa de D esfera. El efecto visual es como sigue:
imagen2 ejemplo de esfera
principal programa de dibujo:
static private FloatBuffer vertex;//búfer de bytes correspondiente al vértice static private FloatBuffer normal;//búfer de bytes correspondiente a la normal float[] lightPos = new float[] {10.0f, 10.0f, 10.0f, 1.0f };//coordenadas de la luz private static final int STEP = 24;// private static final float RADIUS = 1.0f;//radio protected void init(GL10 gl) { gl.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);//establecer el color de fondo gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_POSITION, lightPos, 0); gl.glEnable(GL10.GL_LIGHTING);//habilitar la iluminación gl.glEnable(GL10.GL_LIGHT0); //activar la luz gl.glClearDepthf(1.0f);//establecer el buffer de profundidad gl.glDepthFunc(GL10.GL_LEQUAL);//establecer la función de comparación del buffer de profundidad, GL_LEQUAL indica que el valor de profundidad del pixel nuevo es menor o igual al valor de profundidad del pixel actual y pasa la prueba de profundidad gl.glEnable(GL10.GL_DEPTH_TEST);//habilitar el buffer de profundidad gl.glEnable(GL10.GL_CULL_FACE); gl.glShadeModel(GL10.GL_SMOOTH);//establecer el modo de sombra GL_SMOOTH } protected void drawFrame(GL10 gl) { gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT); gl.glMatrixMode(GL10.GL_MODELVIEW); gl.glLoadIdentity(); GLU.gluLookAt(gl, 0, 0, 7f, 0f, 0f, 0f, 0f, 1.0f, 0.0f);// drawSphere(gl, RADIUS, STEP, STEP); //绘制球形 } public static void gluLookAt (GL10 gl, float eyeX, float eyeY, float eyeZ, float centerX, float centerY, float centerZ, float upX, float upY, float upZ)
它共接受三组坐标,分别为eye、 center和up。eye表示我们眼睛在"世界坐标系"中的位置,center表示眼睛"看"的那个点的坐标,up坐标表示观察者本身的方向,如果将观察点比喻成我们的眼睛,那么这个up则表示我们是正立还是倒立异或某一个角度在看,这里是正立方式,所以是{0,1,0}。
private static void drawSphere(GL10 gl, float radius, int stacks, int slices) { vertex=allocateFloatBuffer( 4* 6 * stacks * (slices+1) ); normal=allocateFloatBuffer( 4* 6 * stacks * (slices+1) ); int i, j, triangles; float slicestep, stackstep; stackstep = ((float)Math.PI) / stacks; slicestep = 2.0f * ((float)Math.PI) / slices; for (i = 0; i < stacks; ++i) { float a = i * stackstep; float b = a + stackstep; float s0 = (float)Math.sin(a); float s1 = (float)Math.sin(b); float c0 = (float)Math.cos(a); float c1 = (float)Math.cos(b); float nv; for (j = 0; j <= slices; ++j) { float c = j * slicestep; float x = (float)Math.cos(c); float y = (float)Math.sin(c); nv=x * s0; normal.put(nv); vertex.put(nv * radio); nv=y * s0; normal.put(nv); vertex.put(nv * radio); nv=c0; normal.put(nv); vertex.put(nv * radio); nv=x * s1; normal.put(nv); vertex.put(nv * radio); nv=y * s1; normal.put(nv); vertex.put(nv * radio); nv=c1; normal.put(nv); vertex.put(nv * radio); } } normal.position(0); vertex.position(0); gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertex); gl.glNormalPointer(GL10.GL_FLOAT, 0, normal); gl.glEnableClientState (GL10.GL_VERTEX_ARRAY); gl.glEnableClientState (GL10.GL_NORMAL_ARRAY); triangles = (slices + 1) * 2; for(i = 0; i < stacks; i++) gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, i * triangles, triangles); gl.glDisableClientState(GL10.GL_VERTEX_ARRAY); gl.glDisableClientState(GL10.GL_NORMAL_ARRAY); } private static FloatBuffer allocateFloatBuffer(int capacity){ ByteBuffer vbb = ByteBuffer.allocateDirect(capacity); vbb.order(ByteOrder.nativeOrder()); return vbb.asFloatBuffer(); }
Resumen:
Este artículo introduce los conceptos básicos y métodos para dibujar gráficos en Ophone utilizando OpenGL ES. Hay mucho más contenido en OpenGL ES, como texturas, iluminación y materiales, mezcla, neblina, máscaras, reflexiones,3La carga del modelo D y otros. Se pueden dibujar aplicaciones gráficas y interfaces de juegos ricas utilizando las funciones OpenGL ES.