开发框架介绍请参见: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
- /*
- * 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]
- */
- package com.android.gljni;
- import com.android.gljni.GLJNIView;
- import android.app.Activity;
- import android.os.Bundle;
- public class GLJNIActivity extends Activity {
- GLJNIView mView;
- @Override
- protected void onCreate(Bundle icicle) {
- super.onCreate(icicle);
- mView = new GLJNIView(getApplication());
- setContentView(mView);
- }
- @Override
- protected void onPause() {
- super.onPause();
- mView.onPause();
- }
- @Override
- protected void onResume() {
- super.onResume();
- mView.onResume();
- }
- }
[GLJNIView.java]
[java] view
plaincopy
- /*
- * 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]
- */
- package com.android.gljni;
- import javax.microedition.khronos.egl.EGLConfig;
- import javax.microedition.khronos.opengles.GL10;
- import com.android.gljni.GLJNILib;
- import android.content.Context;
- import android.opengl.GLSurfaceView;
- /**
- * A simple GLSurfaceView sub-class that demonstrate how to perform
- * OpenGL ES 1.x rendering into a GL Surface.
- */
- public class GLJNIView extends GLSurfaceView {
- private static final String LOG_TAG = GLJNIView.class.getSimpleName();
- private Renderer renderer;
- public GLJNIView(Context context) {
- super(context);
- // setEGLConfigChooser会对fps产生影响
- setEGLConfigChooser(8, 8, 8, 8, 16, 0);
- renderer = new Renderer(context);
- setRenderer(renderer);
- }
- private static class Renderer implements GLSurfaceView.Renderer {
- public Renderer(Context ctx) {
- }
- public void onDrawFrame(GL10 gl) {
- GLJNILib.step();
- }
- public void onSurfaceChanged(GL10 gl, int width, int height) {
- GLJNILib.resize(width, height);
- }
- public void onSurfaceCreated(GL10 gl, EGLConfig config) {
- GLJNILib.init();
- }
- }
- }
[GLJNILib.java]
[java] view
plaincopy
- /*
- * 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]
- */
- package com.android.gljni;
- //Wrapper for native library
- public class GLJNILib {
- static {
- System.loadLibrary("gljni");
- }
- /**
- * @param width the current view width
- * @param height the current view height
- */
- public static native void resize(int width, int height);
- public static native void step();
- public static native void init();
- }
[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: [email protected] * 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(); }
时间: 2024-10-07 11:58:09