Hello Triangle:opengl ES 2.0 version of "Hello World"
Most of the text in this article was extracted from the OpenGL ES 2.0 Programming Wizard, which is hereby explained.
This article is based on OPENGGL ES 2.0, I am learning OpenGL "Hello World" bar.
The implementation of a OPENGGL ES 2.0 program is broadly as follows:
- Loads vertex and fragment shaders.
- Create a Project object, contact the vertex and fragment shader, and link the project.
- Settings window.
- Clears the color buffer.
- The most basic rendering.
Preparatory work
As a "Hello World" class program, the function is to draw a triangle on the phone. As a result, the code will be relatively humble, pre-prepared ingredients are relatively simple, is the following five files (even the layout files are saved):
Androidmanifest.xml
<!-- Tell the system this app requires OpenGL ES 2.0. --><uses-feature android:glEsVersion="0x00020000" android:required="true" />
Mainactivity.java
publicclass MainActivity extends Activity { private TriangleGLSurfaceView mTriangleGLSurfaceView; @Override protectedvoidonCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); new TriangleGLSurfaceView(getApplication()); setContentView(mTriangleGLSurfaceView); }}
Triangleglsurfaceview.java
publicclass TriangleGLSurfaceView extends GLSurfaceView{ publicTriangleGLSurfaceView(Context context) { super(context); setEGLContextClientVersion(2); setRenderer(new TriangleRender()); }}
Trianglerender.java
Public class trianglerender implements Renderer{ PrivateTriangle Mtriangle;@Override Public void onsurfacecreated(GL10 gl, EGLConfig config) {Gles20.glclearcolor (0,0,0,1); Mtriangle =NewTriangle (); }@Override Public void onsurfacechanged(GL10 GL,intWidthintHeight) {Gles20.glviewport (0,0, width, height); }@Override Public void Ondrawframe(GL10 GL) {//Clear the color bufferGles20.glclear (Gles20.gl_color_buffer_bit); Mtriangle.draw (); }}
Triangle.java
public class Triangle { ...省略大段文字,会在下面补充啦...}
Specific implementation
The following operations are mostly Triangle.java
implemented in this class.
Create a simple vertex and fragment shader
OpenGL ES 2.0, no rendering can be done until a valid vertex and fragment shader is loaded. To define a fixed-point shader:
privatestaticfinal String VERTEX_SHADER = "attribute vec4 vPosition; \n" + "void main() \n" + "{ \n" + " gl_Position = vPosition; \n" + "}";
The vertex shader defines an input attribute, which is a vector vposition of 4 members. The following draw
function sets the position variable value for each vertex. The main
function declaration shader declares the shader to begin execution. The shader body is very simple, it copies the input Vposition property into the gl_position output variable, and each vertex shader must output the position value into the gl_position variable, which is passed into the next stage of the pipeline.
The vertex shader is as follows:
privatestaticfinal String FRAGMENT_SHADER = "precision mediump float; \n" + "void main() \n" + "{ \n" + " gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); \n" + "}";
The first line declares the shader's default floating-point variable precision. On the main function, its output value (1.0, 0.0, 0.0, 1.0) is assigned to the variable gl_fragcolor,gl_fragcolor is the final output value of the fragment shader, in this case the output value is red.
A typical game or application will not inline a shader source string, most of the actual application shader should be filled with text or data, and then loaded by the API, we for the sake of simplification, in the program source code directly assigned value.
Compiling and loading shaders
After the shader source is defined, we load the shader into OpenGL ES, which is done by the loadShader
function, and after checking for no errors, the function returns the shader object, which is later used to connect the project object
Private int Loadshader(intType, String shadercode) {intShaderint[] compiled =New int[1];//Create The Shader objectShader = Gles20.glcreateshader (type);if(Shader = =0) {return 0; }//Load the shader sourceGles20.glshadersource (shader, Shadercode);//Compile the shaderGles20.glcompileshader (shader);//Check the compile statusGles20.glgetshaderiv (shader, Gles20.gl_compile_status, compiled,0);if(compiled[0] ==0) {LOG.E (TAG,"Could not compile shader"+ Type +":"); LOG.E (TAG, Gles20.glgetshaderinfolog (shader)); Gles20.gldeleteshader (shader); Shader =0; }returnShader;}
If the shader object is loaded successfully, a new shader object is returned, which is later connected to the Project object.
Create a Project object chain color filter
Once the application has created the vertex, fragment shader object, it needs to create the project object, which is the final linked object, and each shader should contact the project or project object before it is drawn.
- 1. Create a Project Object
// Create the program object.mProgram = GLES20.glCreateProgram();if0) { return;}GLES20.glAttachShader(mProgram, vertexShader);GLES20.glAttachShader(mProgram, fragmentShader);
- 2. Set the vertex shader Vposition property:
toattribute00"vPosition");
Vertex properties, vertex matrices, buffer objects, telling more details now let's see the glbindattriblocation function binds the Vposition property to the vertex shader position 0, and when we specify the vertex data, the position pointer points to the next position.
- 3. Link Item Check Error:
Link the PROGRAMGLES20. Gllinkprogram(Mprogram);Check the link statusint[] linkstatus = new int[1];GLES20. GLGETPROGRAMIV(Mprogram, GLES20. GL_link_status, Linkstatus,0);if (linkstatus[0]! = GLES20. GL_true) {Log. E(TAG," Could not Link program:");Log. E(TAG, GLES20. Glgetprograminfolog(Mprogram));GLES20. Gldeleteprogram(Mprogram);Mprogram =0;}
After all these steps, compile the shader, check for errors, create Project objects, attach on shaders, link items, check for link errors. After success, you can use the project object to render.
setting windows and clearing buffers
Creating a render plane to initialize and load the shader, ready to draw the actual object, we need to use: TriangleRender.java
this class. and GLSurfaceView.Renderer
This interface, the official description given in Android is this:
Public InterfaceRenderer {/** * called whenThe surface is createdorRecreated. * <p> * called whenThe rendering thread * starts andWhenever the EGL context is lost. The EGL context would typically * be lost whenThe Android device awakes after going toSleep. * <p> * Since This method was called at the beginning ofRendering asWell as* Every time the EGL context is lost, this method is a convenient place toPut * code toCreate resources that need toBe created whenThe rendering * starts, andthat need toBe recreated whenThe EGL context is lost. * Textures is an example ofA resource that might want toCreate * here. * <p> * Note that whenThe EGL context is lost, all OpenGL resources Associated * withThat context would be automatically deleted. You Donot need toCall * the corresponding"Gldelete"Methods such asGldeletetextures to* Manually delete these lost resources. * <p> * @param GL The GLInterface. Use <code>instanceof</code> to* TestifTheInterfaceSupports GL11orHigher interfaces. * @param config the EGLConfig ofThe created surface. Can be used * toCreate matching pbuffers. */voidOnsurfacecreated (GL10 gl, EGLConfig config); /** * called whenThe surface changed size. * <p> * Called after the surface is created andWhenever * The OpenGL ES surface size changes. * <p> * Typically you'll set your viewport here. If your camera * is fixed ThenYou could also set your projection matrix here: * <preclass="Prettyprint"> *voidOnsurfacechanged (GL10 gl, int width, int height) {* Gl.glviewport (0,0, width, height); *//For a fixed camera, set the projection too* Float ratio = (float) width/height; * Gl.glmatrixmode (gl10.gl_projection); * Gl.glloadidentity (); * GL.GLFRUSTUMF (-ratio, ratio,-1,1,1,Ten); *} * </pre> * @param GL The GLInterface. Use <code>instanceof</code> to* TestifTheInterfaceSupports GL11orHigher interfaces. * @param width * @param height */voidOnsurfacechanged (GL10 gl, int width, int height); /** * called toDraw the current frame. * <p> * This method is responsible forDrawing the current frame. * <p> * The implementation ofThis method typically looks like this: * <preclass="Prettyprint"> *voidOndrawframe (GL10 gl) {* Gl.glclear (Gl10.gl_color_buffer_bit | Gl10.gl_depth_buffer_bit); *//... other GL calls to render the scene ...*} * </pre> * @param GL The GLInterface. Use <code>instanceof</code> to* TestifTheInterfaceSupports GL11orHigher interfaces. */voidOndrawframe (GL10 gl);}
The 1th function We explained is Glviewport, which defines the coordinates origin and window width and height of the 2D window where OpenGL ES will draw the object. In OpenGL ES, viewport defines the 2D rectangular display area that the render operation will display.
@OverridepublicvoidonSurfaceChangedintint height) { GLES20.glViewport(00, width, height);}
Viewport setting the origin of the window origin (x, y), Width and height
After the window is set, the next step is to clear the screen, in OpenGL ES, there are a variety of buffer types, colors, depths, and templates that need to be drawn. In this case, only the color buffers are used. Before we start drawing each frame, we use glclear to clear the color buffer.
@OverridepublicvoidonDrawFrame(GL10 gl) { // Clear the color buffer GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); else...}
The buffer will be cleared with the value of the color parameter of the Glclearcolor function, and after the initialization of this example, the clear color is set to (0.0, 0.0, 0.0, 1.0) and the screen turns black. Clear color is set by Glclear.
publicvoidonSurfaceCreated(GL10 gl, EGLConfig config) { GLES20.glClearColor(0001); else...}
Loading geometric image Drawing primitives
Now that we have cleared the color buffer, set the viewport, loaded the project object, we specify that the geometry to be drawn is a triangle, and the coordinates of the triangle vertices are as follows:
static float trianglecoords[] = {0.0f,0.5f,0.0f,-0.5f,-0.5f,0.0f,0.5f,-0.5f,0.0f};...Public Triangle () {Bytebuffer BB = bytebuffer.allocatedirect (trianglecoords.length*4); Bb.order (Byteorder.nativeorder ()); Mvertexbuffer = Bb.asfloatbuffer (); Mvertexbuffer.put (trianglecoords); Mvertexbuffer.position (0);}...public void Draw () {//With the program Object Gles20.gluseprogram (Mprogram); Load the vertex data gles20.glvertexattribpointer (0,3, Gles20.gl_float, False,0, Mvertexbuffer); Gles20.glenablevertexattribarray (0); Gles20.gldrawarrays (Gles20.gl_triangles,0,3);}
Vertex position needs to be loaded to GL to contact Vposition, do you think that before we bound the vposition variable to attribute position 0, each vertex shader property has a unique position marked with an unsigned number of characters, calling the Glvertexattribpointer function , we load the data into position 0
The final step in drawing a triangle is to call OpenGL ES to draw primitives, in this case using the Gldrawarrays function. This function draws primitives such as triangles, lines, or strips, and the details of these geometries are described in detail in the 7th chapter.
Back buffer display
Finally, we talk about the triangles drawn in the buffer. Finally, describe how the buffer is displayed on the screen, before discussing the concept of a bit of double buffer.
The frame buffers that you see on the display are 2-dimensional pixel data, and the possible way to do this is to simply update the data in the visible buffer, to update the data in the display buffer directly, and to have a fixed frequency for displaying the screen buffer memory updates. If two times is different, you will see a flashing mark.
To solve this problem, the system generally uses a double buffer: the front buffer and the back buffer, all the rendering takes place in the back buffer, it is the invisible buffer memory on the screen, after rendering is complete, the buffer before and after the swap, that is, before the next frame
The buffer becomes the back buffer.
Using this technique, we do not display any images until a frame is rendered, and this OpenGL ES method uses
Implemented through EGL, the function is eglswapbuffers; This EGL function swaps the buffer before and after, and the input parameters of Eglswapbuffers are the EGL display area and the window, which represent the actual physical display area and the rendering area. Now that we know we swapped the buffers, we show the triangles we want to display.
Results
The result is as shown in the figure below, but the look will change depending on the screen orientation because there is no screen change to handle the horizontal screen.
Horizontal Screen
Vertical Screen
Copyright NOTICE: This article for Bo Master original article, without Bo Master permission not reproduced.
Hello World
in Triangle:opengl ES version 2.0