Android使用OpenGL编程,Android的NDK开发(2)-基于NDK的OpenGL开发

之前在学习Android的时候有写过如果在Android中使用OpenGL,当时完全都是用java语言来实现的,现在我们用NDK来实现一次。

实现的思路就是将渲染器中的onDrawFrame,onSurfaceChanged,onSurfaceCreated分别在C中实现,然后将C编译成.so文件之后在Java中直接调用相应的函数就可以了。

步骤就不详细叙述了,代码贴一下。

主Activity:

package com.empty.ndkgl; import com.example.ndkgl.R; import android.opengl.GLSurfaceView; import android.os.Bundle; import android.app.Activity; import android.view.Menu; public class NdkGlActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); GLSurfaceView surface = new GLSurfaceView(this); surface.setRenderer(new NdkGlRender()); setContentView(surface); } static { //load library System.loadLibrary("NdkGLRenderer"); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.activity_ndkgl, menu); return true; } }

Render类代码:

package com.empty.ndkgl; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.opengles.GL10; import android.opengl.GLSurfaceView.Renderer; public class NdkGlRender implements Renderer{ //declare native function native private void onNdkSurfaceCreated (); native private void onNdkSurfaceChanged (int width, int height); native private void onNdkDrawFrame(); @Override public void onDrawFrame(GL10 arg0) { // TODO Auto-generated method stub onNdkDrawFrame (); } @Override public void onSurfaceChanged(GL10 gl, int width, int height) { // TODO Auto-generated method stub onNdkSurfaceChanged (width, height); } @Override public void onSurfaceCreated(GL10 gl, EGLConfig config) { // TODO Auto-generated method stub onNdkSurfaceCreated (); } }

在工程目录下创建jni文件夹,用下面的命令生成.h文件。

javah -classpath bin/classes -d jni com.empty.ndkgl.NdkGlRender

根据头文件来创建.c文件。

注:虽然生产的 .h文件在编译的时候并没有什么作用,但还是建议做这一步,因为.c文件中的函数名一定要和.h文件中的函数名一致,最后的程序才能正常运行,不然会出现如

java.lang.UnsatisfiedLinkError的bug。

#include #include unsigned int vbo[2]; float positions[12] = {1,-1,0, 1,1,0, -1,-1,0, -1,1,0}; short indices [4] = {0,1,2,3}; JNIEXPORT void JNICALL Java_com_empty_ndkgl_NdkGlRender_onNdkSurfaceCreated (JNIEnv* env, jobject obj) { //生成两个缓存区对象 glGenBuffers (2, vbo); //绑定第一个缓存对象 glBindBuffer (GL_ARRAY_BUFFER, vbo[0]); //创建和初始化第一个缓存区对象的数据 glBufferData (GL_ARRAY_BUFFER, 4*12, positions, GL_STATIC_DRAW); //绑定第二个缓存对象 glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, vbo[1]); //创建和初始化第二个缓存区对象的数据 glBufferData (GL_ELEMENT_ARRAY_BUFFER, 2*4, indices, GL_STATIC_DRAW); } JNIEXPORT void JNICALL Java_com_empty_ndkgl_NdkGlRender_onNdkSurfaceChanged(JNIEnv* env, jobject obj, jint width, jint height) { //图形最终显示到屏幕的区域的位置、长和宽 glViewport (0,0,width,height); //指定矩阵 glMatrixMode (GL_PROJECTION); //将当前的矩阵设置为glMatrixMode指定的矩阵 glLoadIdentity (); glOrthof(-2, 2, -2, 2, -2, 2); } JNIEXPORT void JNICALL Java_com_empty_ndkgl_NdkGlRender_onNdkDrawFrame (JNIEnv* env, jobject obj) { //启用顶点设置功能,之后必须要关闭功能 glEnableClientState (GL_VERTEX_ARRAY); //清屏 glClearColor (0,0,1,1); glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode (GL_MODELVIEW); glLoadIdentity (); glBindBuffer (GL_ARRAY_BUFFER, vbo[0]); //定义顶点坐标 glVertexPointer (3, GL_FLOAT, 0, 0); glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, vbo[1]); //按照参数给定的值绘制图形 glDrawElements (GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_SHORT, 0); //关闭顶点设置功能 glDisableClientState(GL_VERTEX_ARRAY); }

编写Android.mk

#FileName:Android.mk #Description:makefile of NdkGl LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := NdkGLRenderer LOCAL_SRC_FILES := com_empty_ndkgl_NdkGlRender.c LOCAL_LDLIBS := -lGLESv1_CM include $(BUILD_SHARED_LIBRARY)

编译库

$NDK_ROOT/ndk-build

在Eclipse中运行程序

1357979824_3910.png

通过修改.c的实现,我们就可以绘制不同的图形。

比如网格圆球:

#include #include #include #include #include #include typedef unsigned char byte; typedef struct { GLfloat x,y,z; } XYZ; float rotateQuad; #define PI 3.14159265 #define DTOR PI/180 static byte indices[8]={0,1,1,2,2,3,3,0}; //索引数组 void CreateUnitSphere(int dtheta,int dphi) { int n; int theta,phi; XYZ p[4]; for (theta=-90;theta<=90-dtheta;theta+=dtheta) { for (phi=0;phi<=360-dphi;phi+=dphi) { n = 0; p[n].x = cos(theta*DTOR) * cos(phi*DTOR); p[n].y = cos(theta*DTOR) * sin(phi*DTOR); p[n].z = sin(theta*DTOR); n++; p[n].x = cos((theta+dtheta)*DTOR) * cos(phi*DTOR); p[n].y = cos((theta+dtheta)*DTOR) * sin(phi*DTOR); p[n].z = sin((theta+dtheta)*DTOR); n++; p[n].x = cos((theta+dtheta)*DTOR) * cos((phi+dphi)*DTOR); p[n].y = cos((theta+dtheta)*DTOR) * sin((phi+dphi)*DTOR); p[n].z = sin((theta+dtheta)*DTOR); n++; if (theta >=-90 && theta <= 90) { p[n].x = cos(theta*DTOR) * cos((phi+dphi)*DTOR); p[n].y = cos(theta*DTOR) * sin((phi+dphi)*DTOR); p[n].z = sin(theta*DTOR); n++; } /* Do something with the n vertex facet p */ glVertexPointer(3, GL_FLOAT, 0, p); glDrawElements(GL_LINES, 8, GL_UNSIGNED_BYTE, indices); } } } JNIEXPORT void JNICALL Java_com_empty_ndkgl_NdkGlRender_onNdkSurfaceCreated (JNIEnv* env, jobject obj) { // 启用阴影平滑 glShadeModel(GL_SMOOTH); // 黑色背景 glClearColor(0, 0, 0, 0); // 设置深度缓存 glClearDepthf(1.0f); // 启用深度测试 glEnable(GL_DEPTH_TEST); // 所作深度测试的类型 glDepthFunc(GL_LEQUAL); // 告诉系统对透视进行修正 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);} JNIEXPORT void JNICALL Java_com_empty_ndkgl_NdkGlRender_onNdkSurfaceChanged(JNIEnv* env, jobject obj, jint width, jint height) { //图形最终显示到屏幕的区域的位置、长和宽 glViewport (0,0,width,height); //指定矩阵 glMatrixMode (GL_PROJECTION); //将当前的矩阵设置为glMatrixMode指定的矩阵 glLoadIdentity (); glOrthof(-2, 2, -2, 2, -2, 2); } JNIEXPORT void JNICALL Java_com_empty_ndkgl_NdkGlRender_onNdkDrawFrame (JNIEnv* env, jobject obj) { //启用顶点设置功能,之后必须要关闭功能 glEnableClientState (GL_VERTEX_ARRAY); //清屏 glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode (GL_MODELVIEW); glLoadIdentity (); glFrontFace(GL_CW); glRotatef(rotateQuad, 1.0f, 1.0f, 0.0f);//旋转效果 CreateUnitSphere(10,10); //关闭顶点设置功能 glDisableClientState(GL_VERTEX_ARRAY); rotateQuad -= 1.5f; }

1357980846_5949.png

立方体

#include #include #include #include #include #include #define col 1.0f #define pos 1.0f #define PI 3.14159265 static GLfloat vertex[] = { -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 GLfloat colors[] = { 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, }; static GLubyte mindex[] = { 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 angle = 0.0f; JNIEXPORT void JNICALL Java_com_empty_ndkgl_NdkGlRender_onNdkSurfaceCreated (JNIEnv* env, jobject obj) { // 启用阴影平滑 glShadeModel(GL_SMOOTH); // 黑色背景 glClearColor(0, 0, 0, 0); // 设置深度缓存 glClearDepthf(1.0f); // 启用深度测试 glEnable(GL_DEPTH_TEST); // 所作深度测试的类型 glDepthFunc(GL_LEQUAL); // 告诉系统对透视进行修正 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST); } 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); } JNIEXPORT void JNICALL Java_com_empty_ndkgl_NdkGlRender_onNdkSurfaceChanged(JNIEnv* env, jobject obj, jint width, jint height) { if (height==0) // 防止被零除 { height=1; // 将Height设为1 } glViewport(0, 0, width, height); // 重置当前的视口 glMatrixMode(GL_PROJECTION); // 选择投影矩阵 glLoadIdentity(); // 重置投影矩阵 GLfloat ratio = (GLfloat)width/(GLfloat)height; // 设置视口的大小 _gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.1f,100.0f); // glOrthof(-2.0f, 2.0f, -2.0f, 2.0f, -2.0f, 2.0f); glMatrixMode(GL_MODELVIEW); // 选择模型观察矩阵 glLoadIdentity(); // 重置模型观察矩阵 } JNIEXPORT void JNICALL Java_com_empty_ndkgl_NdkGlRender_onNdkDrawFrame (JNIEnv* env, jobject obj) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslatef(0, 0, -8.0f); glRotatef(angle, 0, 1.0F, 0); glRotatef(angle, 0, 0, 1.0F); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_COLOR_ARRAY); glVertexPointer(3,GL_FLOAT,0,vertex); glColorPointer(4,GL_FLOAT,0,colors); glDrawElements(GL_TRIANGLES,36,GL_UNSIGNED_BYTE,mindex); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_COLOR_ARRAY); angle += 1.2f; }

1357988659_7346.png

打完收工。

2013.1.15日更新:

发现一个更强的demo,就在NDK的samples文件夹中,san-angeles就是了!

San Angeles Observation,XX大赛的冠军,原程序只有4K,被google收录到NDK的demo里面了,下面我们就跑一下它。

直接在Eclipse中创建Android工程,选择Android Project From Exiting Code。

1358231627_7328.png

直接跑的话会报错,提示无法初始化,我们必须先把c编译成.so.

命令行进入到项目文件夹,执行ndk-build

1358231747_7075.png

再修改一下Activity,让它全屏幕现实,只修改onCreate函数就可以了。

@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mGLView = new DemoGLSurfaceView(this); requestWindowFeature(Window.FEATURE_NO_TITLE); getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); setContentView(mGLView); }

运行结果:

1358231873_2119.png

1358232011_1588.png

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值