English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

OpenGL ES drawing in Android development3D Graph instance detailed explanation

OpenGL ES ist ein Teilmenge der OpenGL-Dreidimensionalen Grafik-API und ist für eingebettete Geräte wie Handys, PDAs und Spielekonsole entwickelt. Ophone unterstützt derzeit OpenGL ES 1.0, OpenGL ES 1.0 basiert auf OpenGL 1.3 basiert auf OpenGL 1.1 basiert auf OpenGL 1.5 auf Normen basierend. Dieser Artikel beschreibt die grundlegenden Schritte zur Zeichnung von Grafiken mit OpenGL ES.

Dieser Artikel besteht aus drei Teilen. Zunächst wird die Programmierschnittstelle von OpenGL ES über EGL erhalten;其次介绍构建3Grundkonzepte des D-Programms; letztlich ein Beispiel für eine Anwendung.

OpenGL ES ist im Wesentlichen ein Zustandsautomat der Grafikrenderpipeline, während EGL ein externes Schicht zur Überwachung dieser Zustände und zur Wartung von Framebuffer und anderen Renderflächen ist.1 Es ist ein typisches EGL-Systemlayoutdiagramm. Das EGL-Fensterdesign basiert auf dem bekannten Native-Interface für OpenGL auf Microsoft Windows (WGL) und UNIX (GLX), das dem Letzteren ähnlich ist. Der Zustand der OpenGL ES-Grafikpipeline wird in einem Kontext von EGL verwaltet. Framebuffer und andere Zeichnungsrenderflächen werden durch das EGL-API erstellt, verwaltet und zerstört. EGL kontrolliert auch den Zugriff auf die Anzeigeeinrichtung und mögliche Geräteweiterverarbeitungskonfigurationen.


图1

OpenGL ES benötigt einen Rendering-Kontext und eine Rendering-Oberfläche. Der Rendering-Kontext speichert die Statusinformationen von OpenGL ES, und die Rendering-Oberfläche wird für die Zeichnung von Primitiven verwendet. Vor der Schreibweise von OpenGL ES müssen die Aktionen von EGL durchgeführt werden:

Abfrage der von dem Gerät unterstützten Display-Handle und Initialisierung.

Erstellung von Rendering-Oberflächen, Zeichnung von OpenGL ES-Graphiken.

Erstellung von Rendering-Kontexten. EGL muss einen OpenGL ES-Rendering-Kontext erstellen, um ihn mit einer Rendering-Oberfläche zu verknüpfen.

Ophone umfasst EGL4Klassen, darunter EGLDisplay: Display-Handle, EGLConfig: Konfigurationsklasse; EGLContext: Rendering-Kontext; und EGLSurface: Zeichnungsoberflächeklasse.

EGL kann als eine Zwischenschicht zwischen OpenGL ES und dem lokalen FensterSystem betrachtet werden. Lokales FensterSystem bezieht sich auf GNU/Linux auf dem X-FensterSystem oder Mac OS X's Quartz und anderen. Vor dem Bestimmen des Typs der Rendering-Oberfläche durch EGL muss EGL mit dem unteren FensterSystem kommunizieren. Da die FensterSysteme auf verschiedenen Betriebssystemen unterschiedlich sind, bietet EGL eine transparente Fensterart, die EGLDisplay genannt wird. Diese abstrahiert verschiedene FensterSysteme. Daher muss zunächst ein EGLDisplay-Objekt erstellt und initialisiert werden.

// Die statische Methode getEGL von EGLContext erhält das EGL-Instanz
EGL10 egl = (EGL10)EGLContext.getEGL();
//Erstellung von EGLDisplay, EGL_DEFAULT_DISPLAY erhält den Standardtyp des lokalen FensterSystems
EGLDisplay dpy = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
//Initialisierung von EGLDispla während der Erhalt der Versionsnummer
int[] version = new int[2]);
egl.eglInitialize(dpy, version);

Jeder EGLDisplay muss vor der Verwendung initialisiert werden. Während der Initialisierung von EGLDisplay kann die Implementierungsversion von EGL im System erhalten werden. Durch die Versionsnummer kann ein gut kompatibler Programmcode geschrieben werden, der mehr Geräte unterstützt und die größtmögliche Portabilität bietet. Der Prototyp der Initialisierungsfunktion ist:
boolean eglInitialize(EGLDisplay display, int[] major_minor)

davon display ein gültiges EGLDisplay-Objekt ist. Wenn die Funktion aufgerufen wird, wird major_minor mit der aktuellen EGL-Version zugewiesen. Zum Beispiel EGL1.0 , major_minor[0] ist1,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,
sHolder, null);
egl.eglMakeCurrent(dpy, surface, surface, context);
GL10 gl = (GL10)context.getGL();

Aufbau3D-Grafikspunkt

Punkt ist der Aufbau3D-Modell ist die Grundlage. Die internen Berechnungen von OpenGL ES basieren auf Punkten. Man kann auch die Position des Lichts und die Position des Objekts mit Punkten darstellen. Normalerweise verwenden wir eine Gruppe von Floating-Point-Zahlen, um Punkte zu darstellen. Zum Beispiel ein quadratisches4Ein Punkt kann dargestellt werden als:

float vertices[] = {
-1.0f, 1.0f, 0.0f, //Links oben
-1.0f, -1.0f, 0.0f, //Links unten
1.0f, -1.0f, 0.0f, //Rechts unten
1.0f, 1.0f, 0.0f, //Rechts oben
};

Um die Leistung zu verbessern, müssen die Floating-Point-Arrays in einen Byte-Puffer eingefügt werden. Daher gibt es die folgenden Operationen:

ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4);
vbb.order(ByteOrder.nativeOrder());
FloatBuffer vertexBuffer = vbb.asFloatBuffer();
vertexBuffer.put(vertices);
vertexBuffer.position(0);

daher ist ByteOrder.nativeOrder() der Weg, um die Byte-Reihenfolge des Systems zu erhalten. OpenGL ES verfügt über Funktionen zur Manipulation des Grafikrenderpfades, deren Funktionsstatus standardmäßig auf ausgeschaltet ist. Diese Funktionen können mit glEnableClientState und glDisableClientState aktiviert und deaktiviert werden.

// Spezifizieren Sie das Vertex-Array, das aktiviert werden muss
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
// Erklärung zur Aktivierung des Typs und des Byte-Puffers, Typ GL_FLOAT
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
// Schließen Sie das Vertex-Array ab, wenn es nicht mehr benötigt wird
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);

Kanten

Kanten sind die Linien, die zwei Punkte verbinden und die Kantenfläche des Polygons darstellen.

多边形

Polygon sind durch Kanten构成的单一闭合环。 In OpenGL ES müssen Polygon konvexe Polygon sein, d.h. wenn man zwei Punkte im Inneren eines Polygons wählt und die Linie, die diese Punkte verbindet, immer im Inneren des Polygons verläuft, dann ist dieses Polygon konvex. Beim Zeichnen von Polygonen muss die Renderrichtung angegeben werden, die sich in Uhrzeigersinn und gegen den Uhrzeigersinn unterscheidet. Da die Richtung die Ausrichtung des Polygons bestimmt, d.h. Vorder- und Rückseite, kann das Rendern der verdeckten Teile vermieden werden, was die Leistung des Programms effektiv verbessern kann. Die Funktion glFrontFace definiert die Richtung der Renderkante.

// Sets CCW direction as 'front', CCW stands for CounterClockWise, counterclockwise
glFrontFace(GL_CCW);
// Sets CW direction as 'front', CW stands for ClockWise, clockwise
glFrontFace(GL_CW);

rendering

After the above concept explanation, now the main work to be done is rendering. Rendering converts the primitives specified by the object coordinates into images in the frame buffer. The relationship between the image and the vertex coordinates is closely related. This relationship is given by the drawing mode. Common drawing modes include 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.

GL_LINES: Treats each vertex as an independent line segment, vertex2n-1and2n defines n line segments in total, with a total of N/2line segment., If N is odd, the last vertex is ignored.

GL_LINE_STRIP: Draws a set of line segments connected in sequence from the first vertex to the last vertex, the nth and nth+1a vertex defines line segment n, with a total of N triangles drawn-1line segment.


GL_LINE_LOOP: Draws a set of line segments 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 segment n, and then the last line segment is defined by vertex N and1, a total of N line segments are drawn.


GL_TRIANGLES: Treats every three vertices as an independent triangle. Defined between vertices3n-2,3n-1and3n defines the nth triangle, with a total of N triangles drawn/3a triangle.

GL_TRIANGLE_STRIP: Draws a set of connected triangles. For odd vertex n, vertex n, n+1and n+2defines the nth triangle; for even n, vertex n+1, n and n+2Defines the nth triangle, with a total of N triangles drawn-2a triangle.


GL_TRIANGLE_FAN: Draws a set of connected triangles. Triangles are determined by the first vertex and the subsequent vertices given. Vertex1, n+1and n+2Defines the nth triangle, with a total of N triangles 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); //Zeichnen Sie einen Kugel
}
public static void gluLookAt (GL10 gl, float eyeX, float eyeY, float eyeZ, float centerX, float centerY, float centerZ, float upX, float upY, float upZ)

Es akzeptiert insgesamt drei Koordinatenpaare,分别为eye、 center und up。Eye bedeutet die Position unseres Auges im "Weltkoordinatensystem",center bedeutet die Koordinaten des Punktes, auf den unser Auge "schaut",und die Koordinaten von up zeigen die Richtung des Beobachters selbst. Wenn man den Beobachtungspunkt metaphorisch als unser Auge betrachtet, so bedeutet diese up, ob wir aufrecht, umgekehrt oder aus einer bestimmten Perspektive schauen, hier ist es die aufrechte Art, also {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();
}

Zusammenfassung:

Dieser Artikel stellt die grundlegenden Konzepte und Methoden zur Zeichnung von Grafiken in Ophone mit OpenGL ES vor. In OpenGL ES gibt es viele andere Inhalte, wie Textur, Beleuchtung und Materialien, Mischen, Nebel, Maskierung, Reflexion,3Ladung des D-Modells und dergleichen. Mit OpenGL ES-Funktionen können reichhaltige Grafikanwendungen und Spieloberflächen dargestellt werden.

You may also like