这一简单示例演示如何通过使用 OpenGL ES 2.0 API 和可编程着色器,以及 SDK 中提供的简单帮助器框架将简单三角形渲染至屏幕。 本示例的完整源代码在 OpenGL ES SDK for Linux on ARM 和 OpenGL ES 2.0 SDK for Android 中提供。 本页不涵盖 EGL 的初始化,因此建议在这一部分中使用 SDK。
定义三角形顶点数据:
const float triangleVertices[] = { 0.0f, 0.5f, 0.0f, -0.5f, -0.5f, 0.0f, 0.5f, -0.5f, 0.0f, };
以及三角形颜色值:
const float triangleColors[] = { 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, };
至应用程序的入口点将设置平台并初始化 EGL。
int main(void) { /* Intialize the Platform object for platform specific functions. */ Platform *platform = Platform::getInstance(); /* Initialize windowing system. */ platform->createWindow(WINDOW_W, WINDOW_H); /* Initialize EGL. */ EGLRuntime::initializeEGL(EGLRuntime::OPENGLES2); EGL_CHECK(eglMakeCurrent(EGLRuntime::display, EGLRuntime::surface, EGLRuntime::surface, EGLRuntime::context)); /* Initialize OpenGL ES graphics subsystem. */ setupGraphics(WINDOW_W, WINDOW_H); bool end = false; /* The rendering loop to draw the scene. */ while(!end) { /* If something has happened to the window, end the sample. */ if(platform->checkWindow() != Platform::WINDOW_IDLE) { end = true; } /* Render a single frame */ renderFrame(); /* * Push the EGL surface color buffer to the native window. * Causes the rendered graphics to be displayed on screen. */ eglSwapBuffers(EGLRuntime::display, EGLRuntime::surface); } /* Shut down EGL. */ EGLRuntime::terminateEGL(); /* Shut down windowing system. */ platform->destroyWindow(); /* Shut down the Platform object*/ delete platform; return 0; }
这一工作的大部分在 setupGraphics 和 renderFrame 中进行。
此函数从 main 中调用,窗口大小则作为输入传递。 该函数将加载顶点和片段着色器,进行编译,并将它们链接至将在应用程序的其余部分中使用的程序。
bool setupGraphics(int width, int height) { /* Full paths to the shader files */ string vertexShaderPath = "Triangle_triangle.vert"; string fragmentShaderPath = "Triangle_triangle.frag"; GLuint vertexShaderID = 0; GLuint fragmentShaderID = 0; /* Initialize OpenGL ES. */ GL_CHECK(glEnable(GL_BLEND)); /* Should do: src * (src alpha) + dest * (1-src alpha). */ GL_CHECK(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); /* Process shaders. */ Shader::processShader(&vertexShaderID, vertexShaderPath.c_str(), GL_VERTEX_SHADER); Shader::processShader(&fragmentShaderID, fragmentShaderPath.c_str(), GL_FRAGMENT_SHADER); programID = GL_CHECK(glCreateProgram()); if (programID == 0) { //Could not create Program error return false; } GL_CHECK(glAttachShader(programID, vertexShaderID)); GL_CHECK(glAttachShader(programID, fragmentShaderID)); GL_CHECK(glLinkProgram(programID)); GL_CHECK(glUseProgram(programID)); /* Positions. */ GL_CHECK(iLocPosition = glGetAttribLocation(programID, "a_v4Position")); /* Fill colors. */ GL_CHECK(iLocFillColor = glGetAttribLocation(programID, "a_v4FillColor")); GL_CHECK(glViewport(0, 0, width, height)); /* Set clear screen color. */ GL_CHECK(glClearColor(0.0f, 0.0f, 1.0f, 1.0f)); return true; }
这会在每个循环中调用一次,并将顶点和颜色数据发送到 GPU,以便在下一次调用 eglSwapBuffers 时进行渲染。
void renderFrame(void) { GL_CHECK(glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)); GL_CHECK(glUseProgram(programID)); /* Pass the triangle vertex positions to the shader */ GL_CHECK(glVertexAttribPointer(iLocPosition, 3, GL_FLOAT, GL_FALSE, 0, triangleVertices)); GL_CHECK(glEnableVertexAttribArray(iLocPosition)); if(iLocFillColor != -1) { /* Pass the vertex colours to the shader */ GL_CHECK(glVertexAttribPointer(iLocFillColor, 4, GL_FLOAT, GL_FALSE, 0, triangleColors)); GL_CHECK(glEnableVertexAttribArray(iLocFillColor)); } GL_CHECK(glDrawArrays(GL_TRIANGLES, 0, 3)); }
顶点着色器和片段着色器比较琐碎:
顶点:
attribute vec4 a_v4Position; attribute vec4 a_v4FillColor; varying vec4 v_v4FillColor; void main() { v_v4FillColor = a_v4FillColor; gl_Position = a_v4Position; }
片段:
precision mediump float; varying vec4 v_v4FillColor; void main() { gl_FragColor = v_v4FillColor; }