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

OpenGL ES Drawing in Android Development3Detailed Explanation of D Graphical Instance

OpenGL ES is a subset of the OpenGL 3D graphics API, designed for embedded devices such as mobile phones, PDAs, and game consoles. Ophone currently supports OpenGL ES 1.0, OpenGL ES 1.0 is based on the OpenGL 1.3 specification, OpenGL ES 1.1 is based on the OpenGL 1.5 based on the specification. This article mainly introduces the basic steps of drawing graphics using OpenGL ES.

The content of this article consists of three parts. Firstly, obtain the programming interface of OpenGL ES through EGL; secondly, introduce the construction3Basic concepts of D program; finally, there is an application example.

OpenGL ES is essentially a state machine for the graphics rendering pipeline, while EGL is an external layer used to monitor these states and maintain frame buffers and other rendering surfaces.1 It is a typical EGL system layout diagram. The EGL window design is based on the native interface for OpenGL, which is familiar to users on Microsoft Windows (WGL) and UNIX (GLX), and is relatively close to the latter. The state of the OpenGL ES graphics pipeline is stored in a context managed by EGL. Frame buffers and other drawing rendering surfaces are created, managed, and destroyed through the EGL API. EGL also controls and provides access to the device display and possible device rendering configurations.


Figure1

OpenGL ES requires a rendering context and a rendering surface. The rendering context stores the state information of OpenGL ES, and the rendering surface is used for the drawing of primitives. Before writing OpenGL ES, the operations required by EGL include:

Query the display handles supported by the device and initialize them.

Create rendering surface, draw OpenGL ES graphics.

Create rendering context. EGL needs to create an OpenGL ES rendering context to associate with a rendering surface.

In Ophone, EGL includes4classes, including EGLDisplay: display handle, EGLConfig: configuration class, EGLContext: rendering context, and EGLSurface: renderable view class.

EGL can be considered as an intermediate layer between OpenGL ES and the local window system. Local window system refers to GNU/Linux X window system, or Mac OS X's Quartz, etc. Before EGL determines the type of rendering surface, EGL needs to communicate with the underlying window system. Because window systems differ between different operating systems, EGL provides a transparent window type, namely EGLDisplay. It abstracts various window systems. Therefore, the first step is to create and initialize an EGLDisplay object.

// The static method getEGL of EGLContext gets the EGL instance
EGL10 egl = (EGL10)EGLContext.getEGL();
//Create EGLDisplay, EGL_DEFAULT_DISPLAY gets the default local window system type
EGLDisplay dpy = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
//Initializing EGLDisplay while obtaining the version number
int[] version = new int[2]);
egl.eglInitialize(dpy, version);

Each EGLDisplay needs to be initialized before use. Initializing EGLDisplay also allows you to obtain the implementation version number of EGL in the system. By using the version number, you can write compatible programs with the help of the corresponding OpenGL ES API, which can adapt to more devices and provide maximum portability. The prototype of the initialization function is:
boolean eglInitialize(EGLDisplay display, int[] major_minor)

where display is a valid EGLDisplay instance. When the function call is completed, major_minor will be assigned the current EGL version number. For example, EGL1.0 , major_minor[0] is1,major_minor[1] as 0. EGLSurface contains all the information related to the EGL rendering surface. There are two methods to query EGLSurface configuration information: one is to query all configuration information and select the most suitable one; the other is to specify the configuration information and let the system give the best matching result. Generally, the second method is used. The user specifies the desired configuration through configSpec, and the function eglChooseConfig returns the best configuration list through the parameter Configs. After obtaining the Configs, call eglCreateContext to create a rendering context, which returns an EGLContext structure. The creation of the rendering surface EGLSurface is completed through the function eglCreateWindowSurface. An application can create multiple EGLContexts. eglMakeCurrent binds a rendering context to the rendering surface. The query functions eglGetCurrentContext, eglGetCurrentDisplay, and eglGetCurrentSurface are used to obtain the current system's rendering context, display handle, and rendering surface, respectively. Finally, the static method getGL of EGLContext obtains the programming interface of OpenGL ES. The following program snippet summarizes the above content.

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

Building3Of D graphics point

Point is the building block3The foundation of D model. The internal calculation of OpenGL ES is based on points. Points can also represent the position of light sources and objects. Generally, we use a set of floating-point numbers to represent points. For example, a square's4A vertex can be represented as:

float vertices[] = {
-1.0f, 1.0f, 0.0f, //Top left
-1.0f, -1.0f, 0.0f, //Bottom left
1.0f, -1.0f, 0.0f, //Bottom right
1.0f, 1.0f, 0.0f, //Top right
};

To improve performance, the floating-point array needs to be stored in a byte buffer. Therefore, the following operations are performed:

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

where ByteOrder.nativeOrder() is used to obtain the native byte order. OpenGL ES has functions to operate on the graphics rendering pipeline, and by default, the usage status of these functions is turned off. These functions can be enabled or disabled using glEnableClientState and glDisableClientState.

// Specify the vertex arrays that need to be enabled
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
// This indicates the type of array and byte buffer enabled, with the type being GL_FLOAT
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
// Close the vertex array when no longer needed
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);

Edge

An edge is a line that connects two points and is the edge of a polygonal face.

Polygon

A polygon is a single closed loop composed of edges. Polygons in OpenGL ES must be convex, meaning that if you take any two points inside the polygon and connect them with a line segment, the segment must be entirely within the polygon for it to be convex. When drawing polygons, it is necessary to specify the rendering direction, which is either clockwise or counterclockwise. The direction determines the orientation of the polygon, i.e., the front and back sides. Avoiding the rendering of obscured parts can effectively improve program performance. The function glFrontFace defines the direction of rendering vertices.

// 设置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, the main work now is to render. 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.2n-1and2GL_LINES: Treats each vertex as an independent line segment, vertex/2n between define 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 order from the first vertex to the last vertex, the nth and nth-1lines. The nth vertex defines line n, a total of N lines are drawn.


GL_LINE_LOOP: Draws a set of lines connected in order from the first vertex to the last vertex, and then the last vertex is connected to the first vertex. The nth and nth+1vertices define line n, and then the last line is defined by vertex N and1are defined between, 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 n, vertex n, n+1and n+2Defining the nth triangle; for even n, vertex n+1, n and n+2Defining 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 subsequent vertices given. Vertex1, n+1and n+2Defining 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 array from the first to the first + count - 1The ending array element, mode is the drawing mode.

glDrawElements uses count elements to define a primitive sequence, type is the data type of the indices array, mode is the drawing mode, and the indices array stores the vertices

The index value of a point.

Application example

Using the content explained above to give an example of drawing a3D-shaped program. The effect is as follows:


Figure2 Sphere example

The main drawing program:

static private FloatBuffer vertex;//The byte buffer corresponding to the vertex
static private FloatBuffer normal;//The byte buffer corresponding to the normal vector
float[] lightPos = new float[] {10.0f, 10.0f, 10.0f, 1.0f };//The coordinates of the light source
private static final int STEP = 24;//
private static final float RADIUS = 1.0f;//radius
protected void init(GL10 gl) {
gl.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);//Set background color
gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_POSITION, lightPos, 0);
gl.glEnable(GL10.GL_LIGHTING);//Enable lighting
gl.glEnable(GL10.GL_LIGHT0); //Open light source
gl.glClearDepthf(1.0f);//Set depth cache
gl.glDepthFunc(GL10.GL_LEQUAL);//Set depth cache comparison function, GL_LEQUAL means the new pixel's depth cache value is less than or equal to the current pixel's depth cache value when passing the depth test
gl.glEnable(GL10.GL_DEPTH_TEST);//Enable depth cache
gl.glEnable(GL10.GL_CULL_FACE);
gl.glShadeModel(GL10.GL_SMOOTH);//Set shadow mode 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); //Draw a sphere
}
public static void gluLookAt (GL10 gl, float eyeX, float eyeY, float eyeZ, float centerX, float centerY, float centerZ, float upX, float upY, float upZ)

It accepts three sets of coordinates, namely eye, center, and up. Eye represents the position of our eyes in the 'world coordinate system', center represents the coordinates of the point that the eyes are looking at, and the up coordinate represents the direction of the observer itself. If we compare the observation point to our eyes, then this up indicates whether we are looking upright, inverted, or at an angle, here it is upright, so it is {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();
}

Summary:

This article introduces the basic concepts and methods of drawing graphics in Ophone using OpenGL ES. There are many other contents in OpenGL ES, such as textures, lighting and materials, blending, fog, mask, reflection,3Loading of D models and the like. Rich graphics applications and game interfaces can be drawn using OpenGL ES functions.

You May Also Like