例子见附件.
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="anson.code.openGLDemo1" android:versionCode="1" android:versionName="1.0"> <application android:icon="@drawable/icon" android:label="@string/app_name"> <activity android:name=".OGDActivity" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
OGDActivity.java
package anson.code.openGLDemo1; import android.app.Activity; import android.os.Bundle; public class OGDActivity extends Activity { /** Called when the activity is first created. */ VortexView vortexView; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //setContentView(R.layout.main); vortexView = new VortexView(this); setContentView(vortexView); } @Override protected void onPause() { // TODO Auto-generated method stub super.onPause(); vortexView.onPause(); } @Override protected void onResume() { // TODO Auto-generated method stub super.onResume(); vortexView.onResume(); } }
VortexView.java
package anson.code.openGLDemo1; import android.content.Context; import android.opengl.GLSurfaceView; import android.util.AttributeSet; import android.view.MotionEvent; public class VortexView extends GLSurfaceView { private VortexRenderer renderer; public VortexView(Context context, AttributeSet attrs) { super(context, attrs); // TODO Auto-generated constructor stub } public VortexView(Context context) { super(context); // TODO Auto-generated constructor stub renderer = new VortexRenderer(); setRenderer(renderer); } @Override public boolean onTouchEvent(final MotionEvent event) { // TODO Auto-generated method stub queueEvent(new Runnable(){ @Override public void run() { // TODO Auto-generated method stub renderer.setColor(event.getX()/getWidth(), event.getY() /getHeight(), 1.0f); renderer.setAngle(event.getX()/10); } }); return super.onTouchEvent(event); } }
VortexRenderer.java
package anson.code.openGLDemo1; /** * 程序开始 :onSurfaceCreated --> onSurfaceChanged --> onDrawFrame --> onDrawFrame --> onDrawFrame --> * 程序后台唤醒:onSurfaceChanged --> onDrawFrame --> onSurfaceChanged --> onDrawFrame --> onDrawFrame --> * * 1) onDrawFrame() 方法会在每帧中被调用,用于描述一个时时绘制的场景,你还可以通过调用 glclear 方法去清空帧缓冲,接着通过其他OpenGl ES 调用去绘制目前的场景。 * 2) onSurfaceChanged() 方法在surface 大小尺寸改变的时候被调用,它主要设置你的openGL的观察点,你也可以在这里设置一个不会被移动到固定Camera * 3) onSurfaceCreated() 方法被调用在开始渲染的时候,OpenGL ES 绘图上下文时都会被重建(当activity暂停和恢复的时候,绘图的上下文也随着丢失和重建. */ import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.FloatBuffer; import java.nio.ShortBuffer; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.opengles.GL10; import android.opengl.GLSurfaceView.Renderer; public class VortexRenderer implements Renderer { private float red = 0f; private float green = 0f; private float blue = 0f; private ShortBuffer indexBuffer; private FloatBuffer vertexBuffer; private short[] indicesArray = {0, 1, 2}; private int numberOfVertices = 3; private float angle; private void initTriangle(){ /** * allocate和allocateDirect方法都做了相同的工作, * 不同的是allocateDirect方法 "直接"使用操作系统来分配Buffer. * 因而它将提供更快的访问速度。不幸的是,并非所有的虚拟机都支持这种直接分配的方法. * Sun推荐将以字节为单位的直接型缓冲区allocateDirect用于与大型文件相关并具有较长生命周期的缓冲区. */ ByteBuffer vbb = ByteBuffer.allocateDirect(numberOfVertices *3 *4);//36; // ByteOrder nativeOrder() 返回当前硬件平台的字节序. vbb.order(ByteOrder.nativeOrder());//返回ByteOrder的字节序, 并赋给ByteBuffer. /** 为当前的ByteBuffer创建一个CharBuffer的视图。 * 在该视图buffer中的读写操作会按照ByteBuffer的字节序作用到ByteBuffer中的数据上 */ vertexBuffer = vbb.asFloatBuffer(); ByteBuffer ibb = ByteBuffer.allocateDirect(numberOfVertices *2); ibb.order(ByteOrder.nativeOrder()); indexBuffer = ibb.asShortBuffer(); /** * coords分别定义了三个顶点的座, * 对应为: X, Y, Z * 这里需要注意的是: * 相对于屏幕中, 原点既是在屏幕中的中点(取X/2, Y/2) * 原点: 0, 0, 0 * 其中, Z轴需要以设置场景的深度为准. * 各个座标取值[0, 1]的浮点值. */ float[] coords = {-0.5f, -0.5f, 0f, 0.5f, -0.5f, 0f, 0f, 0.5f, 0.1f}; vertexBuffer.put(coords);// 写入顶点座标到vertexBuffer, 以便下面显示场景. indexBuffer.put(indicesArray); vertexBuffer.position(0);//设置当前的读取起始位置. indexBuffer.position(0); } public void setColor(float red, float green, float blue){ this.red = red; this.green = green; this.blue = blue; } public void setAngle(float an){ this.angle = an; } @Override public void onDrawFrame(GL10 gl) { // TODO Auto-generated method stub /** * RGB + A * 绝大多数人都认为Alpha分量代表材料的透明度。这就是说,alpha值为0.0时所代表的材料是完全透明的。alpha值为1.0时所代表的材料则是完全不透明的。 * 红,绿,蓝和AFA值是在颜色缓冲区被清除之后使用的,并且缺省值全是0.即(0,0,0,0),其实就是设置颜色 */ gl.glClearColor(red, green, blue, 0.0f); gl.glClear(GL10.GL_COLOR_BUFFER_BIT);//表示把整个窗口清除为当前的清除颜色,glClear()的唯一参数表示需要被清除的缓冲区。 /** * 定义旋转轴 * glRotatef(速度, X, Y, Z); */ gl.glRotatef(angle, 0f, 0f, 1f); gl.glColor4f(0.5f, 0f, 0f, 0.5f); gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer); gl.glDrawElements(GL10.GL_TRIANGLES, numberOfVertices, GL10.GL_UNSIGNED_SHORT, indexBuffer); } @Override public void onSurfaceChanged(GL10 gl, int w, int h) { // TODO Auto-generated method stub gl.glViewport(0, 0, w, h); } @Override public void onSurfaceCreated(GL10 gl, EGLConfig cf) { // TODO Auto-generated method stub gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); initTriangle(); } }
添加画圆圈:
package anson.code.openGLDemo1; import java.nio.FloatBuffer; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.opengles.GL10; import android.opengl.GLSurfaceView.Renderer; public class CRenderer implements Renderer { float rotateAngle; float rotateY; float r = 0.5f; //顶点数组,GL ES只能用这个办法画圆吗? private float[] vertices = new float[720]; //度到弧度的转换 public float DegToRad(float deg) { //360 = 2PI float Pi = 3.14159265358979323846f; float Du = 360; float v = deg * (2*Pi) / Du; return v; } public void setAnX(float angle){ rotateAngle -= angle; } public void setAnY(float ay){ rotateY += ay; } public void onDrawFrame(GL10 gl) { // TODO Auto-generated method stub // 进入这个函数第一件要做的事就是清除屏幕和深度缓存 gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT); //画圆形 drawCircle(gl); } public void drawCircle(GL10 gl) { //重置投影矩阵 gl.glLoadIdentity(); // 移动操作,移入屏幕(Z轴)5个像素, x, y , z gl.glTranslatef(0.0f, 0.0f, -1.5f); //旋转, angle, x, y , z gl.glRotatef(rotateAngle, 1.0f, 0f, 0f); gl.glRotatef(rotateY, 0f, 1f, 0f); // 设置当前色为红色, R, G, B, Alpha gl.glColor4f(1.0f, 0.1f, 0.1f, 1.0f); //设置圆形顶点数据,这个是在创建时生成 FloatBuffer verBuffer = FloatBuffer.wrap(vertices); //设置顶点类型为浮点坐标(GL_FLOAT),不设置或者设置错误类型将导致图形不能显示或者显示错误 gl.glVertexPointer(2, GL10.GL_FLOAT, 0, verBuffer); //打开顶点数组 gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); //向OGL发送实际画图指令 /** * GL_TRIANGLE_FAN * GL_LINES * GL_LINES_LOOP */ gl.glDrawArrays(GL10.GL_LINES, 0, 360); //关闭顶点数组功能 gl.glDisableClientState(GL10.GL_VERTEX_ARRAY); //画图结束 gl.glFinish(); //更改旋转角度 //rotateAngle += 0.5; } public void onSurfaceChanged(GL10 gl, int width, int height) { // TODO Auto-generated method stub float ratio = (float) width / height; //设置OpenGL场景的大小 gl.glViewport(0, 0, width, height); //设置投影矩阵,既告诉OPENGL 如何把三维矩阵换为二维显示到界面上. gl.glMatrixMode(GL10.GL_PROJECTION); //重置投影矩阵,初始化. gl.glLoadIdentity(); // 设置视口的大小 /** * glFrustumf(float left, float right, float bottom, float top, float zNear, float zFar) * 设置了显示视口的大小,也就是说,一个可视范围. * 把三维的东西用二维显示出来, 需要知道可以平面有多大 和 能看多近和多远. * 前面四个参数指定视口平面的大小, 后两个参数分别是可以看到的最近和最远. */ //gl.glFrustumf(-ratio, ratio, -1, 1, 1, 10); gl.glFrustumf(-ratio, ratio, 1f, -1f, 1f, 25); // 选择模型观察矩阵 gl.glMatrixMode(GL10.GL_MODELVIEW); // 重置模型观察矩阵 gl.glLoadIdentity(); } public void onSurfaceCreated(GL10 gl, EGLConfig config) { // TODO Auto-generated method stub // 启用阴影平滑 /** glShadeModel函数用于控制opengl中绘制指定两点间其他点颜色的过渡模式。 * 参数一般为GL_SMOOTH(默认),GL_FLAT。OpenGL默认是将制定的两点颜色进行插值,绘制之间的其他点。 * 如果两点的颜色相同,使用两个参数效果相同。 * 如果两点颜色不同,GL_SMOOTH会出现过渡效果,GL_FLAT 则只是以指定的某一点的单一色绘制其他所有点。 */ gl.glShadeModel(GL10.GL_SMOOTH); // 黑色背景 gl.glClearColor(0, 0, 0, 0); // 设置深度缓存 gl.glClearDepthf(1.0f); // 启用深度测试 /** * 在三维空间里一个物体A,在另一个物体B后面,为了不让档住的部分不显示, * 需要告诉OpenGL把被档住的部分隐藏, glEnable(GL10.GL_DEPTH_TEST)就是实现这个功能. */ gl.glEnable(GL10.GL_DEPTH_TEST); /** * 所作深度测试的类型 * 这里我们比较常用的深度测试函数有 GL_LESS 和 GL_LEQUAL * 两者的区别在于当深度相同时是显示新的象素 还是老的象素。 */ gl.glDepthFunc(GL10.GL_LEQUAL); // 告诉系统对透视进行修正 /** * 在OpenGL中,许多细节的实现算法有所不同。 * 这样,可以调用函数glHint()对图像质量和绘制速度之间的权衡作一些控制,但并非所有的实现都采用它。 * 其函数形式为:void glHint(GLenum target,GLenum hint); * 控制OpenGL行为的某些方面。 * 参数target说明控制什么行为 * 参数hint可以是:GL_FASTEST(即给出最有效的选择)、GL_NICEST(即给出最高质量的选择)、GL_DONT_CARE(即没有选择)。 */ gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST); //初始化圆形数据 for (int i = 0; i < 720; i += 2) { // x value if(i%4 ==0) vertices[i] = (float) (Math.cos(DegToRad(i)) * r); // y value if(i%4 ==0) vertices[i+1] = -(float) (Math.sin(DegToRad(i)) * r); } } }
要使圆圈运动起来:
package anson.code.openGLDemo1; import android.content.Context; import android.opengl.GLSurfaceView; import android.util.AttributeSet; import android.view.MotionEvent; public class CView extends GLSurfaceView { CRenderer renderer; float oX = 0f; float oY = 0f; public CView(Context context, AttributeSet attrs) { super(context, attrs); // TODO Auto-generated constructor stub } public CView(Context context) { super(context, null); // TODO Auto-generated constructor stub renderer = new CRenderer(); setRenderer(renderer); } @Override public boolean onTouchEvent(MotionEvent event) { //android.util.Log.d("AnsonLog", "TouchEvent:::::::::"); // TODO Auto-generated method stub switch(event.getAction()){ case MotionEvent.ACTION_DOWN: oX = event.getRawX(); oY = event.getRawY(); break; case MotionEvent.ACTION_MOVE: float cX = event.getRawX(); float cY = event.getRawY(); float disX = cX - oX; float disY = cY - oY; oX = cX; oY = cY; renderer.setAnX(disY/4f); renderer.setAnY(disX/4f); break; case MotionEvent.ACTION_UP: oX = 0f; oY = 0f; break; } return true; } }
http://hi.baidu.com/fairzy/blog/item/959200fcd1b60dfbfc037f9b.html这里的几篇文件不错.
OpenGLDemo1.zip (53.8 KB)
下载次数: 188