首页 > 代码库 > Opengl ES 1.x NDK实例开发之五:顶点缓存VBO

Opengl ES 1.x NDK实例开发之五:顶点缓存VBO

    开发框架介绍请参见: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]

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. /* 
  2.  * Copyright (C) 2007 The Android Open Source Project 
  3.  * 
  4.  * Licensed under the Apache License, Version 2.0 (the "License"); 
  5.  * you may not use this file except in compliance with the License. 
  6.  * You may obtain a copy of the License at 
  7.  * 
  8.  *      http://www.apache.org/licenses/LICENSE-2.0 
  9.  * 
  10.  * Unless required by applicable law or agreed to in writing, software 
  11.  * distributed under the License is distributed on an "AS IS" BASIS, 
  12.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
  13.  * See the License for the specific language governing permissions and 
  14.  * limitations under the License. 
  15.  *  
  16.  * author: mnorst@foxmail.com 
  17.  */  
  18.   
  19. package com.android.gljni;  
  20.   
  21. import com.android.gljni.GLJNIView;  
  22.   
  23. import android.app.Activity;  
  24. import android.os.Bundle;  
  25.   
  26. public class GLJNIActivity extends Activity {  
  27.     GLJNIView mView;  
  28.   
  29.     @Override  
  30.     protected void onCreate(Bundle icicle) {  
  31.         super.onCreate(icicle);  
  32.         mView = new GLJNIView(getApplication());  
  33.         setContentView(mView);  
  34.     }  
  35.   
  36.     @Override  
  37.     protected void onPause() {  
  38.         super.onPause();  
  39.         mView.onPause();  
  40.     }  
  41.   
  42.     @Override  
  43.     protected void onResume() {  
  44.         super.onResume();  
  45.         mView.onResume();  
  46.     }  
  47. }  
[GLJNIView.java]

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. /* 
  2.  * Copyright (C) 2007 The Android Open Source Project 
  3.  * 
  4.  * Licensed under the Apache License, Version 2.0 (the "License"); 
  5.  * you may not use this file except in compliance with the License. 
  6.  * You may obtain a copy of the License at 
  7.  * 
  8.  *      http://www.apache.org/licenses/LICENSE-2.0 
  9.  * 
  10.  * Unless required by applicable law or agreed to in writing, software 
  11.  * distributed under the License is distributed on an "AS IS" BASIS, 
  12.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
  13.  * See the License for the specific language governing permissions and 
  14.  * limitations under the License. 
  15.  *  
  16.  * author: mnorst@foxmail.com 
  17.  */  
  18.   
  19. package com.android.gljni;  
  20.   
  21. import javax.microedition.khronos.egl.EGLConfig;  
  22. import javax.microedition.khronos.opengles.GL10;  
  23.   
  24. import com.android.gljni.GLJNILib;  
  25.   
  26. import android.content.Context;  
  27. import android.opengl.GLSurfaceView;  
  28.   
  29. /** 
  30.  * A simple GLSurfaceView sub-class that demonstrate how to perform 
  31.  * OpenGL ES 1.x rendering into a GL Surface. 
  32.  */  
  33. public class GLJNIView extends GLSurfaceView {  
  34.   
  35.     private static final String LOG_TAG = GLJNIView.class.getSimpleName();  
  36.   
  37.     private Renderer renderer;  
  38.   
  39.     public GLJNIView(Context context) {  
  40.         super(context);  
  41.   
  42.         // setEGLConfigChooser会对fps产生影响  
  43.         setEGLConfigChooser(8888160);  
  44.   
  45.         renderer = new Renderer(context);  
  46.         setRenderer(renderer);  
  47.     }  
  48.   
  49.     private static class Renderer implements GLSurfaceView.Renderer {  
  50.   
  51.         public Renderer(Context ctx) {  
  52.   
  53.         }  
  54.   
  55.         public void onDrawFrame(GL10 gl) {  
  56.             GLJNILib.step();  
  57.         }  
  58.   
  59.         public void onSurfaceChanged(GL10 gl, int width, int height) {  
  60.             GLJNILib.resize(width, height);  
  61.         }  
  62.   
  63.         public void onSurfaceCreated(GL10 gl, EGLConfig config) {  
  64.             GLJNILib.init();  
  65.         }  
  66.     }  
  67.   
  68. }  
[GLJNILib.java]

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. /* 
  2.  * Copyright (C) 2007 The Android Open Source Project 
  3.  * 
  4.  * Licensed under the Apache License, Version 2.0 (the "License"); 
  5.  * you may not use this file except in compliance with the License. 
  6.  * You may obtain a copy of the License at 
  7.  * 
  8.  *      http://www.apache.org/licenses/LICENSE-2.0 
  9.  * 
  10.  * Unless required by applicable law or agreed to in writing, software 
  11.  * distributed under the License is distributed on an "AS IS" BASIS, 
  12.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
  13.  * See the License for the specific language governing permissions and 
  14.  * limitations under the License. 
  15.  *  
  16.  * author: mnorst@foxmail.com 
  17.  */  
  18.   
  19. package com.android.gljni;  
  20.   
  21. //Wrapper for native library  
  22. public class GLJNILib {  
  23.       
  24.     static {  
  25.         System.loadLibrary("gljni");  
  26.     }  
  27.   
  28.     /** 
  29.      * @param width the current view width 
  30.      * @param height the current view height 
  31.      */  
  32.     public static native void resize(int width, int height);   
  33.       
  34.     public static native void step();    
  35.       
  36.     public static native void init();    
  37. }  
[gl_code.cpp]

/*
 * 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: 	mnorst@foxmail.com
 * created:	2014/10/20
 * purpose:	顶点缓冲对象(VBO)的使用
 */

// OpenGL ES 1.x code

#include <jni.h>
#include <android/log.h>

#include <GLES/gl.h>
#include <GLES/glext.h>

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

/************************************************************************/
/*                             定义                                     */
/************************************************************************/

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


Opengl ES 1.x NDK实例开发之五:顶点缓存VBO