English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
OpenGL ES est un sous-ensemble de l'API OpenGL pour graphiques 3D, conçu pour des appareils embarqués tels que les téléphones mobiles, les PDA et les consoles de jeu. Ophone prend actuellement en charge OpenGL ES 1.0, OpenGL ES 1.0 est basé sur la norme OpenGL 1.3 basé sur la norme OpenGL ES 1.1 basé sur la norme OpenGL 1.5 basé sur la norme. Cet article présente principalement les étapes de base pour dessiner des graphiques avec OpenGL ES.
Le contenu de cet article est composé de trois parties. Premièrement, l'obtention de l'interface de programmation OpenGL ES via EGL; ensuite, l'introduction de la construction3Concepts fondamentaux du programme D; enfin, un exemple d'application.
OpenGL ES est essentiellement un mécanisme de machine d'état de pipeline graphique, tandis que EGL est une couche externe utilisée pour surveiller ces états et maintenir les tampons d'image et d'autres surfaces de rendu.1 Il s'agit d'un diagramme de disposition typique du système EGL. La conception des fenêtres EGL est basée sur l'interface native utilisée pour OpenGL sur Microsoft Windows (WGL) et UNIX (GLX), et elle est comparable à cette dernière. L'état de la pipeline graphique OpenGL ES est stocké dans un contexte géré par EGL. Les tampons d'image et les autres surfaces de rendu sont créés, gérés et détruits via l'API EGL. EGL contrôle également et fournit l'accès aux configurations d'affichage et de rendu possible des appareils.
图1
OpenGL ES nécessite un contexte de rendu et une surface de rendu. Le contexte de rendu stocke les informations d'état d'OpenGL ES, et la surface de rendu est utilisée pour le dessin des primitives. Avant d'écrire OpenGL ES, les opérations EGL nécessaires incluent :
Requérir les gestionnaires de display pris en charge par l'appareil et les initialiser.
Créer une surface de rendu, dessiner des graphiques OpenGL ES.
Créer un contexte de rendu. EGL doit créer un contexte de rendu OpenGL ES pour l'associer à une surface de rendu.
Ophone, EGL inclut4les classes, à savoir EGLDisplay : gestionnaire de display, EGLConfig : classe de configuration; EGLContext : contexte de rendu; et EGLSurface : classe de vue rendable.
EGL peut être considéré comme une couche intermédiaire entre OpenGL ES et le système de fenêtres local. Le système de fenêtres local fait référence à GNU/système de fenêtres X sur Linux, ou Mac OS X's Quartz, etc. Avant que EGL ne détermine le type de surface de rendu, EGL doit communiquer avec le système de fenêtres de bas niveau. Comme les systèmes de fenêtres sur différents systèmes d'exploitation sont différents, EGL fournit un type de fenêtre transparent, à savoir EGLDisplay. Il abstrait divers systèmes de fenêtres. Par conséquent, il faut d'abord créer et initialiser un objet EGLDisplay.
// La méthode statique getEGL de EGLContext pour obtenir l'instance EGL EGL10 egl = (EGL10)EGLContext.getEGL(); //Créer un EGLDisplay, EGL_DEFAULT_DISPLAY pour obtenir le type de système de fenêtres local par défaut EGLDisplay dpy = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); //Obtenir le numéro de version tout en initialisant EGLDispla int[] version = new int[2]); egl.eglInitialize(dpy, version);
Chaque EGLDisplay doit être initialisé avant d'être utilisé. En initiaлизant EGLDisplay, on peut obtenir le numéro de version de l'implémentation EGL du système. Grâce au numéro de version, on peut utiliser les API OpenGL ES de manière raisonnable pour écrire des programmes compatibles, pour s'adapter à plus d'appareils et offrir la plus grande portabilité. Le prototype de la fonction d'initialisation :
boolean eglInitialize(EGLDisplay display, int[] major_minor)
dans lequel display est une instance valide de EGLDisplay. Lorsque l'appel de la fonction est terminé, major_minor recevra le numéro de version actuel de EGL. Par exemple, EGL1.0 , major_minor[0] est un1,major_minor[1]为0。EGLSurface包含了EGL渲染面相关的所有信息。查询EGLSurface配置信息有两种方法,一是查询所有的配置信息,从中选择一个最为适合的;二是指定好配置信息,由系统给出最佳匹配结果。一般采用第二种方法。用户通过configSpec指定出希望获得的配置,函数eglChooseConfig通过参数Configs返回最佳的配置列表。之后利用已获得的Configs,调用eglCreateContext创建一个渲染上下文,该函数返回EGLContext结构。渲染面EGLSurface的创建通过函数eglCreateWindowSurface完成。一个应用程序可以创建多个EGLContext。 eglMakeCurrent就是将某个渲染上下文绑定到渲染面。查询函数eglGetCurrentContext, eglGetCurrentDisplay和eglGetCurrentSurface分别用于获得当前系统的渲染上下文、显示句柄和渲染面。最后EGLContext的静态方法getGL获得OpenGL ES的编程接口。下面的程序片段总结了上述内容。
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();3Construire
Les points de la graphique D3Le point est utilisé pour construire4Base du modèle D. Les calculs internes d'OpenGL ES sont basés sur des points. Les points peuvent également représenter la position de la lumière et la position des objets. Généralement, nous utilisons un ensemble de nombres flottants pour représenter un point. Par exemple, un carré
Un sommet peut être représenté comme : -1.0f, 1.0f, 0.0f, //En haut à gauche -1.0f, -1.0f, 0.0f, //En bas à gauche 1.0f, -1.0f, 0.0f, //En bas à droite 1.0f, 1.0f, 0.0f, //En haut à droite };
Pour améliorer les performances, il est nécessaire de stocker un tableau de flottants dans un tampon d'octets. Voici les opérations suivantes :
ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4); vbb.order(ByteOrder.nativeOrder()); FloatBuffer vertexBuffer = vbb.asFloatBuffer(); vertexBuffer.put(vertices); vertexBuffer.position(0);
Dans lequel ByteOrder.nativeOrder() récupère l'ordre des octets du système. OpenGL ES possède des fonctions pour manipuler le pipeline de rendu graphique, qui sont par défaut désactivées. Ces fonctions peuvent être activées ou désactivées à l'aide de glEnableClientState et glDisableClientState.
// Spécifiez les arrays de sommets à activer
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
// Cela indique que l'array est activé avec un type et un tampon en octets, le type étant GL_FLOAT
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
// Fermez l'array de sommets lorsque cela n'est plus nécessaire
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
Côté
Un côté est une ligne reliant deux points et constitue la bordure de la face d'un polygone.
Polygone
Un polygone est formé par des côtés et constitue un cercle fermé simple. Les polygones OpenGL ES doivent être convexes, c'est-à-dire que si l'on choisit deux points à l'intérieur du polygone et que les segments reliant ces points sont tous situés à l'intérieur du polygone, alors ce polygone est convexe. Lors du dessin d'un polygone, il est nécessaire de spécifier la direction de rendu, qui est soit dans le sens horaire soit dans le sens inverse des aiguilles d'une montre. La direction détermine la face avant et la face arrière du polygone. Éviter de rendre les parties cachées peut efficacement améliorer les performances du programme. La fonction glFrontFace définit la direction de rendu des sommets.
// 设置CCW方向为“正面”,CCW即CounterClockWise,逆时针
Set CCW direction as 'front', CCW stands for CounterClockWise, counterclockwise
// glFrontFace(GL_CCW);
Set CW direction as 'front', CW stands for ClockWise, clockwise
glFrontFace(GL_CW);
Rendering
After the above concept explanation, now we need to do the most important work—rendering. Rendering is to convert the primitives specified by the object coordinates into images in the frame buffer. The image and vertex coordinates have a close relationship. This relationship is given by the drawing mode. Commonly used drawing modes are GL_POINTS, GL_LINE_STRIP,
GL_LINE_LOOP, GL_LINES, GL_TRIANGLES, GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN. The following are introduced separately:
GL_POINTS: Treats each vertex as a point, vertex n defines point n, a total of n points are drawn.2n-1and2GL_LINES: Treats each vertex as an independent line segment, vertex/2n define together n lines, a total of N lines are drawn
lines., If N is odd, the last vertex is ignored.+1GL_LINE_STRIP: Draws a set of lines connected in sequence from the first vertex to the last vertex, the nth and nth-1lines. A vertex defines line n, a total of N lines are drawn
GL_LINE_LOOP: Draws a set of lines connected in sequence from the first vertex to the last vertex, and then the last vertex is connected to the first vertex. The nth and nth+1a vertex defines line n, and then the last line is defined by vertex N and1between define N lines, a total of N lines are drawn.
GL_TRIANGLES: Treats every three vertices as an independent triangle. Vertices3n-2,3n-1and3n defines the nth triangle, a total of N triangles are drawn/3a triangle.
GL_TRIANGLE_STRIP: Draws a set of connected triangles. For odd vertex n, vertex n, n+1and n+2Defined the nth triangle; for even n, vertex n+1, n and n+2Defined the nth triangle, a total of N triangles are drawn-2a triangle.
GL_TRIANGLE_FAN: Draws a set of connected triangles. Triangles are determined by the first vertex and the vertices given after it. Vertex1, n+1and n+2Defined the nth triangle, a total of N triangles are drawn-2a triangle.
Drawing functions:
void glDrawArrays(int mode, int first, int count)
void glDrawElements(int mode, int count, int type, Buffer indices)
glDrawArrays creates a sequence of geometric primitives, using each element of the array from first to first + count – 1结束的数组元素, mode为绘制模式。
glDrawElements使用count个元素定义一个图元序列,type是indices数组中的数据类型,mode为绘制模式,indices数组存储顶
点的索引值。
应用举例
利用上面讲解的内容给出一个Ophone上绘制一个3D球形的程序。效果图如下:
图2 球形示例
主要的绘制程序:
static private FloatBuffer vertex;//顶点对应的字节缓冲 static private FloatBuffer normal;//法向量对应的字节缓冲 float[] lightPos = new float[] {10.0f, 10.0f, 10.0f, 1.0f };//光源的坐标 private static final int STEP = 24;// private static final float RADIUS = 1.0f;//半径 protected void init(GL10 gl) { gl.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);//设置背景颜色 gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_POSITION, lightPos, 0); gl.glEnable(GL10.GL_LIGHTING);//启用光照 gl.glEnable(GL10.GL_LIGHT0); //打开光源 gl.glClearDepthf(1.0f);//设置深度缓存 gl.glDepthFunc(GL10.GL_LEQUAL);//设置深度缓存比较函数,GL_LEQUAL表示新的像素的深度缓存值小于等于当前像素的深度缓存值时通过深度测试 gl.glEnable(GL10.GL_DEPTH_TEST);//启用深度缓存 gl.glEnable(GL10.GL_CULL_FACE); gl.glShadeModel(GL10.GL_SMOOTH);//设置阴影模式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); //dessiner la sphère } public static void gluLookAt (GL10 gl, float eyeX, float eyeY, float eyeZ, float centerX, float centerY, float centerZ, float upX, float upY, float upZ)
Il accepte trois groupes de coordonnées, respectivement eye, center et up. eye représente la position de nos yeux dans le "système de coordonnées mondial", center représente la coordonnée du point que nous regardons, et la coordonnée up représente la direction de l'observateur, si nous comparons le point d'observation à nos yeux, alors cette up indique si nous regardons en position debout, inversée ou à un certain angle, ici c'est une position debout, donc c'est {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 * radius); nv=y * s0; normal.put(nv); vertex.put( nv * radius); nv=c0; normal.put(nv); vertex.put( nv * radius); nv=x * s1; normal.put(nv); vertex.put( nv * radius); nv=y * s1; normal.put(nv); vertex.put( nv * radius); nv=c1; normal.put(nv); vertex.put( nv * radius); } } 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(); }
Résumé :
Cet article présente les concepts de base et les méthodes pour dessiner des graphiques dans Ophone à l'aide d'OpenGL ES. Il y a beaucoup d'autres contenus dans OpenGL ES, tels que les textures, l'éclairage et les matériaux, le mélange, la brume, le masque, la réflexion,3Le chargement du modèle D et autres. Les fonctions OpenGL ES peuvent être utilisées pour dessiner des applications graphiques riches et des interfaces de jeu.