开发框架介绍请参见:Opengl ES NDK实例开发之一:搭建开发框架
本章在上一章的基础上讲解顶点缓存数组(Vertex Buffer Object)即VBO的使用,使用VBO来实现金字塔和立方体的绘制,绘制的效果和上一章相同。这个系列教程主要是采用实例演示 Opengl ES 1.x NDK开发,对一些要点进行解释,因此对API的用法和说明较少,建议初学者可以参考Opengl ES 1.x的API手册。
>>>为什么要使用VBO?
VBO的数据存放在显卡内存中,能节省从系统内存复制到显卡内存中的时间,提高渲染的效率。
>>>VBO顶点缓存的使用范围?
VBO可以缓存顶点、颜色、纹理坐标、索引。
【实例讲解】
本章示例了VBO缓存顶点、颜色和索引的用法。
【实例源码】
[GLJNIActivity.java]
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* author: [email protected]
* created: 2014/10/20
* purpose: 顶点缓冲对象(VBO)的使用
*/
// OpenGL ES 1.x code
#include
#include
#include
#include
#include
#include
#include
/************************************************************************/
/* 定义 */
/************************************************************************/
#define LOG_TAG "libgljni"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
// 定义π
const GLfloat PI = 3.1415f;
// 旋转角度
static GLfloat gAngle = 0.0f;
// 金字塔顶点数组
const GLfloat gVertices[] = {
// 底面:地面为正方形,拆分为两个三角形
-1.0f,-1.0f,1.0f,
1.0f,-1.0f,1.0f,
1.0f,-1.0f, -1.0f,
1.0f,-1.0f,-1.0f,
-1.0f,-1.0f,-1.0f,
-1.0f,-1.0f,1.0f,
// 侧面:侧面为4个三角形
0.0f, 1.0f, 0.0f,
-1.0f,-1.0f, 1.0f,
1.0f,-1.0f, 1.0f,
0.0f, 1.0f, 0.0f,
1.0f,-1.0f, 1.0f,
1.0f,-1.0f, -1.0f,
0.0f, 1.0f, 0.0f,
1.0f,-1.0f, -1.0f,
-1.0f,-1.0f, -1.0f,
0.0f, 1.0f, 0.0f,
-1.0f,-1.0f,-1.0f,
-1.0f,-1.0f, 1.0f
};
// 金字塔颜色数组
const GLfloat gColors[] = {
1.0f,0.0f,0.0f, 1.0f,
1.0f,0.0f,0.0f, 1.0f,
1.0f,0.0f,0.0f, 1.0f,
1.0f,0.0f,0.0f, 1.0f,
1.0f,0.0f,0.0f, 1.0f,
1.0f,0.0f,0.0f, 1.0f,
1.0f,0.0f,0.0f, 1.0f,
0.0f,1.0f,0.0f, 1.0f,
0.0f,0.0f,1.0f, 1.0f,
1.0f,0.0f,0.0f, 1.0f,
0.0f,0.0f,1.0f, 1.0f,
0.0f,1.0f,0.0f, 1.0f,
1.0f,0.0f,0.0f, 1.0f,
0.0f,0.0f,1.0f, 1.0f,
0.0f,1.0f,0.0f, 1.0f,
1.0f,0.0f,0.0f, 1.0f,
0.0f,0.0f,1.0f, 1.0f,
0.0f,1.0f,0.0f, 1.0f,
};
// 立方体顶点数组
#define col 1.0f
#define pos 1.0f
static GLfloat gVerticesSquare[] = {
-pos,-pos,-pos, /*0*/
-pos,-pos,pos, /*1*/
pos,-pos,pos, /*2*/
pos,-pos,-pos, /*3*/
-pos,pos,-pos, /*4*/
-pos,pos,pos, /*5*/
pos,pos,pos, /*6*/
pos,pos,-pos, /*7*/
};
// 立方体顶点索引
static GLubyte gIndexSquare[] = {
0,2,1, 0,3,2,
5,1,6, 6,1,2,
6,2,7, 7,2,3,
0,4,3, 4,7,3,
4,0,1, 4,1,5,
4,5,6, 4,6,7,
};
// 立方体颜色数组
static GLfloat gColorsSquare[] = {
col,0,0,col,
0,col,0,col,
0,0,col,col,
col,col,0,col,
col,0,col,col,
0,col,col,col,
0,0,0,col,
col,col,col,col,
};
GLuint gVerticesVBO;
GLuint gColorsVBO;
GLuint gVerticesSquareVBO;
GLuint gColorsSquareVBO;
GLuint gIndexSquareVBO;
/************************************************************************/
/* C++代码 */
/************************************************************************/
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);
}
}
bool init() {
printGLString("Version", GL_VERSION);
printGLString("Vendor", GL_VENDOR);
printGLString("Renderer", GL_RENDERER);
printGLString("Extensions", GL_EXTENSIONS);
// 启用阴影平滑
glShadeModel(GL_SMOOTH);
// 黑色背景
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
// 设置深度缓存
glClearDepthf(1.0f);
// 启用深度测试
glEnable(GL_DEPTH_TEST);
// 所作深度测试的类型
glDepthFunc(GL_LEQUAL);
// 对透视进行修正
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
// VBO相关处理
// 金字塔
glGenBuffers(1, &gVerticesVBO);
glBindBuffer(GL_ARRAY_BUFFER, gVerticesVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(gVertices), gVertices, GL_STATIC_DRAW);
glGenBuffers(1, &gColorsVBO);
glBindBuffer(GL_ARRAY_BUFFER, gColorsVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(gColors), gColors, GL_STATIC_DRAW);
// 立方体
glGenBuffers(1, &gVerticesSquareVBO);
glBindBuffer(GL_ARRAY_BUFFER, gVerticesSquareVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(gVerticesSquare), gVerticesSquare, GL_STATIC_DRAW);
glGenBuffers(1, &gColorsSquareVBO);
glBindBuffer(GL_ARRAY_BUFFER, gColorsSquareVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(gColorsSquare), gColorsSquare, GL_STATIC_DRAW);
glGenBuffers(1, &gIndexSquareVBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, gIndexSquareVBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(gIndexSquare), gIndexSquare, GL_STATIC_DRAW);
return true;
}
static void _gluPerspective(GLfloat fovy, GLfloat aspect, GLfloat zNear, GLfloat zFar)
{
GLfloat top = zNear * ((GLfloat) tan(fovy * PI / 360.0));
GLfloat bottom = -top;
GLfloat left = bottom * aspect;
GLfloat right = top * aspect;
glFrustumf(left, right, bottom, top, zNear, zFar);
}
void resize(int width, int height)
{
// 防止被零除
if (height==0)
{
height=1;
}
// 重置当前的视口
glViewport(0, 0, width, height);
// 选择投影矩阵
glMatrixMode(GL_PROJECTION);
// 重置投影矩阵
glLoadIdentity();
// 设置视口的大小
_gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.1f,100.0f);
// 选择模型观察矩阵
glMatrixMode(GL_MODELVIEW);
// 重置模型观察矩阵
glLoadIdentity();
}
void renderFrame() {
// 清除屏幕及深度缓存
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// 设置背景颜色为黑色
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
// 重置当前的模型观察矩阵
glLoadIdentity();
// 启用顶点数组
glEnableClientState(GL_VERTEX_ARRAY);
// 启用颜色数组
glEnableClientState(GL_COLOR_ARRAY);
// 移入屏幕,便于图形显示
glTranslatef(0.0f,2.0f,-10.0f);
// 绘制金字塔,采用VBO进行绘制
glRotatef(gAngle,0.0f,1.0f,0.0f);
glRotatef(gAngle,1.0f,0.0f,0.0f);
////glColorPointer(4, GL_FLOAT, 0, gColors);
////glVertexPointer(3, GL_FLOAT, 0, gVertices);
////glDrawArrays(GL_TRIANGLES, 0, 20);
glBindBuffer(GL_ARRAY_BUFFER, gVerticesVBO);
glVertexPointer(3, GL_FLOAT, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, gColorsVBO);
glColorPointer(4, GL_FLOAT, 0, 0);
glDrawArrays(GL_TRIANGLES, 0, 20);
// 绘制立方形,使用VBO进行绘制
// 重置当前的模型观察矩阵
glLoadIdentity();
glTranslatef(0.0f, -2.0f,-10.0f);
glRotatef(gAngle,0.0f,1.0f,0.0f);
glRotatef(gAngle,1.0f,0.0f,0.0f);
// glVertexPointer(3,GL_FLOAT,0,gVerticesSquare);
// glColorPointer(4,GL_FLOAT,0,gColorsSquare);
glBindBuffer(GL_ARRAY_BUFFER, gVerticesSquareVBO);
glVertexPointer(3,GL_FLOAT, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, gColorsSquareVBO);
glColorPointer(4, GL_FLOAT, 0, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, gIndexSquareVBO);
glDrawElements(GL_TRIANGLES,36,GL_UNSIGNED_BYTE,0);
// 关闭顶点数组
glDisableClientState(GL_VERTEX_ARRAY);
// 关闭颜色数组
glDisableClientState(GL_COLOR_ARRAY);
// 增加旋转角度
gAngle += 2.0f;
}
/************************************************************************/
/* JNI代码 */
/************************************************************************/
extern "C" {
JNIEXPORT void JNICALL Java_com_android_gljni_GLJNILib_resize(JNIEnv * env, jobject obj, jint width, jint height);
JNIEXPORT void JNICALL Java_com_android_gljni_GLJNILib_step(JNIEnv * env, jobject obj);
JNIEXPORT void JNICALL Java_com_android_gljni_GLJNILib_init(JNIEnv * env, jobject obj);
};
JNIEXPORT void JNICALL Java_com_android_gljni_GLJNILib_resize(JNIEnv * env, jobject obj, jint width, jint height)
{
resize(width, height);
}
JNIEXPORT void JNICALL Java_com_android_gljni_GLJNILib_step(JNIEnv * env, jobject obj)
{
renderFrame();
}
JNIEXPORT void JNICALL Java_com_android_gljni_GLJNILib_init(JNIEnv * env, jobject obj)
{
init();
}