热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

OpenGLES2学习教程2——HelloOpenGLES2.0

HelloGLES2和ES1.0不同,ES2.0引入了可编程管线,如下图中,可编程阶段为VertexShader,FragmentShad
Hello GLES2

和ES1.0不同,ES2.0引入了可编程管线,如下图中,可编程阶段为VertexShader,FragmentShader顶点和片段着色器阶段。

图片描述

顶点着色器被使用在传统的基于顶点的操作,例如位移矩阵、计算光照方程、产生贴图
坐标。顶点着色器被应用指定,应用于客户端的顶点转化。顶点着色器需要一个位置和颜色数据作为输入属性,输入位置数据是 4×4 的矩阵,输出是变换后的位置和颜色。
片段着色器不需定义输出,这是因为片段着色器仅仅的输出是gl_FragColor。

现在我们用上一节的Android入口渲染一个三角形。这里借用NDK包里的例子hello-gl2。项目代码看里面的lesson2的tag

宏文件

#ifndef _APPMACROS_H__
#define _APPMACROS_H__#include #include
#include #include
#include #define LOG_TAG "GLES-Tutorial"#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE,LOG_TAG,__VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)static void printGLString(const char *name, GLenum s) {const char *v = (const char *) glGetString(s);LOGI("GL %s = %s\n", name, v);
}static void checkGlError(const char* op) {for (GLint error = glGetError(); error; error = glGetError()) {LOGI("after %s() glError (0x%x)\n", op, error);}
}#endif

这里除了android里的Log外添加了gl2.h, gl2ext.h头文件,这两个文件可以在NDK包(platforms/android-19/)中找到,这里使用了android里的libGLESv2.so库。printGLString可以获取到OpenGL属性的状态,checkGlError可以检测OpenGL状态是否有错误。

使用OpenGLES2

先给Director添加成员变量:

GLProgram *_glProgram; // opengl状态机GLuint _vPositionHandle; // 获取到的顶点位置属性

#include "Director.h"
#include "AppMacros.h"// 顶点着色器
static const char gVertexShader[] = "attribute vec4 vPosition;\n""void main() {\n"" gl_Position = vPosition;\n""}\n";
// 片段着色器
static const char gFragmentShader[] = "precision mediump float;\n""void main() {\n"" gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);\n""}\n";
// 三角形顶点数据
const GLfloat gTriangleVertices[] = { 0.0f, 0.5f, -0.5f,-0.5f, 0.5f, -0.5f };
// ... 省略掉一些void Director::setFrameSize(float width, float height)
{LOGI("Director::setFrameSize(%lf, %lf)", width, height);_fFrameWidth = width;_fFrameHeight = height;// 创建一个空源的OpenGL状态机_glProgram = new GLProgram();// 将着色器装载和编译_glProgram->initWithVertexShaderByteArray(gVertexShader, gFragmentShader);// 链接着色器_glProgram->link();// 使用此状态机,着色器将能运用上_glProgram->use();// 获取到位置属性,以便用来绘制图形;顶点着色器里的vPosition属性_vPositionHandle = _glProgram->getAttribLocation("vPosition");// 设置OpenGL视口,一个2D的长方形区域(Android里GLSurfaceView窗体的大小)glViewport(0, 0, width, height);checkGlError("glViewport");
}void Director::mainLoop()
{// 每一帧都让灰度值叠加static float grey;grey += 0.01f;if (grey > 1.0f) {grey = 0.0f;}// 用颜色来填充清除深度和颜色缓冲区glClearColor(grey, grey, grey, 1.0f);glClear( GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);// 将顶点位置属性获取到glVertexAttribPointer(_vPositionHandle, 2, GL_FLOAT, GL_FALSE, 0, gTriangleVertices);checkGlError("glVertexAttribPointer");glEnableVertexAttribArray(_vPositionHandle); // 并将三角形顶点设置进顶点矩阵checkGlError("glEnableVertexAttribArray");glDrawArrays(GL_TRIANGLES, 0, 3); // 绘制三角形图元checkGlError("glDrawArrays");
}

GLProgram是我包装了OpenGL的一些操作,便于使用:

class GLProgram
{
public:GLProgram();~GLProgram();/** init GLProgram with vertex shader array data and fragment shader array data*/bool initWithVertexShaderByteArray(const GLchar* vShaderByteArray, const GLchar* fShaderByteArray);/** link shader*/bool link();/** use this opengl program*/void use();/** get location attrib*/GLuint getAttribLocation(const GLchar* attrib);private:GLuint loadShader(GLenum shaderType, const GLchar* shaderSrc);GLuint _uProgram;GLuint _uVertShader;GLuint _uFragShader;};

bool GLProgram::initWithVertexShaderByteArray(const GLchar* vShaderByteArray, const GLchar* fShaderByteArray)
{_uVertShader = loadShader(GL_VERTEX_SHADER, vShaderByteArray);if (!_uVertShader) {return false;}_uFragShader = loadShader(GL_FRAGMENT_SHADER, fShaderByteArray);if (!_uFragShader) {return false;}_uProgram = glCreateProgram();if (!_uProgram) {return false;}glAttachShader(_uProgram, _uVertShader);checkGlError("glAttachShader");glAttachShader(_uProgram, _uFragShader);checkGlError("glAttachShader");return true;
}bool GLProgram::link()
{glLinkProgram(_uProgram);GLint linkStatus = GL_FALSE;glGetProgramiv(_uProgram, GL_LINK_STATUS, &linkStatus);if (linkStatus != GL_TRUE) {GLint bufLength = 0;glGetProgramiv(_uProgram, GL_INFO_LOG_LENGTH, &bufLength);if (bufLength) {char* buf = (char*) malloc(bufLength);if (buf) {glGetProgramInfoLog(_uProgram, bufLength, NULL, buf);LOGE("Could not link _uProgram:\n%s\n", buf);free(buf);}}glDeleteProgram(_uProgram);_uProgram = 0;return false;}return true;
}void GLProgram::use()
{glUseProgram(_uProgram);checkGlError("glUseProgram");
}GLuint GLProgram::loadShader(GLenum shaderType, const char* shaderSrc)
{GLuint shader = glCreateShader(shaderType);if (shader) {glShaderSource(shader, 1, &shaderSrc, NULL);glCompileShader(shader);GLint compiled = 0;glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled); // check compile informationif (!compiled) {GLint infoLen = 0;glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);if (infoLen) {char* infoLog = (char*) malloc(infoLen);if (infoLog) {glGetShaderInfoLog(shader, infoLen, NULL, infoLog); // seek infor log LOGE("Could not compile shader %d:\n%s\n",shaderType, infoLog);free(infoLog);}glDeleteShader(shader);shader = 0;}}}return shader;
}GLuint GLProgram::getAttribLocation(const GLchar* attrib)
{GLuint retAtt = glGetAttribLocation(_uProgram, attrib);checkGlError("glGetAttribLocation");LOGI("glGetAttribLocation(\"%s\") = %d\n", attrib, retAtt);return retAtt;
}

OpenGL ES提供了一套运行期动态编译的流程:

  • 1.创建着色器:glCreateShader

  • 2.指定着色器源代码字符串:glShaderSource

  • 3.编译着色器:glCompileShader

  • 4.创建着色器可执行程序:glCompileShader

  • 5.向可执行程序中添加着色器:glAttachShader

  • 6.链接可执行程序:glLinkProgram

Run

编译之前,需要修改下Android.mk

LOCAL_SRC_FILES := \
com_richard_glestutorial_GLRenderer.cpp \
../core/Director.cpp \
../core/GLProgram.cppLOCAL_C_INCLUDES := \
$(LOCAL_PATH)

$ndk-build && ant debug && adb install -r bin/GlesTutorial-debug.apk

运行脚本,将可以看一个绿色的三角形,并且背景在不断变化。

图片描述



推荐阅读
author-avatar
我爱上帝爱我
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有