使用OpenGL ES绘制3D图形

本文介绍了使用OpenGL ES绘制3D图形的关键步骤,包括理解Android的三维坐标系、设置图形的参照原点、利用顶点和颜色数据绘制3D形状,如三棱锥和正方体,并通过手势监听实现图形的旋转效果。示例代码展示了如何创建和绘制这两个3D形状,以及如何处理触摸事件以改变旋转角度。
使用OpenGL ES绘制3D图形需要注意的几点是:

1. Android的三维坐标系默认原点位于屏幕中央。

2. 绘制3D图形时,各个顶点的坐标是以原点为参照的,比如顶点坐标为(0.5,0,0),    表示顶点在正x轴的二分之一处。

3. 绘制前需调用glTranslatef(x, y, z) 函数设置图形的参照原点。

4. OpenGL ES绘制的图形都是由若干个三角形组合起来的。

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import android.opengl.GLSurfaceView.Renderer;

public class MyRenderer implements Renderer {
	
	float[] taperVertices = new float[]{//三棱锥的四个顶点
			0.0f,0.4f,0.0f,
			-0.4f,-0.4f,-0.4f,
			0.4f,-0.4f,-0.4f,
			0.0f,-0.4f,0.4f
	};
	int[] taperColors = new int[]{//三棱锥的四个顶点的颜色
			655335,0,0,0,
			0,655335,0,0,
			0,0,655335,0,
			655335,655335,0,0,
	};
	private byte[] taperFacets = new byte[]{//三棱锥的四个面
			0,1,2,
			0,1,3,
			1,2,3,
			0,2,3
	};
	float[] cubeVertices = new float[]{//正方体的8个顶点
			0.4f,0.4f,0.4f,
			0.4f,-0.4f,0.4f,
			-0.4f,-0.4f,0.4f,
			-0.4f,0.4f,0.4f,
			0.4f,0.4f,-0.4f,
			0.4f,-0.4f,-0.4f,
			-0.4f,-0.4f,-0.4f,
			-0.4f,0.4f,-0.4f,			
	};
	
	private byte[] cubFacets = new byte[]{//正方体的6个矩形面(12个三角面)
			0,1,2,
			0,2,3,
			2,3,7,
			2,6,7,
			0,3,7,
			0,4,7,
			4,5,6,
			4,6,7,
			0,1,4,
			1,4,5,
			1,2,6,
			1,5,6
	};
	
	FloatBuffer taperVerticesBuffer;
	IntBuffer taperColorBuffer;
	ByteBuffer taperFacesBuffer;
	
	FloatBuffer cubeVerticesBuffer;
	ByteBuffer cubeFacesBuffer;
	
	private float rotateX = 0;
	private float rotateY = 0;
	
	
	
	
	public void setRotateX(float rotateX) {
		this.rotateX = this.rotateX + rotateX;
	}

	public void setRotateY(float rotateY) {
		this.rotateY = this.rotateY + rotateY;
	}

	public MyRenderer() {
		
		taperVerticesBuffer = floteBufferUtil(taperVertices);
		taperColorBuffer = intBufferUtil(taperColors);
		taperFacesBuffer = ByteBuffer.wrap(taperFacets);
		
		cubeVerticesBuffer = floteBufferUtil(cubeVertices);
		cubeFacesBuffer = ByteBuffer.wrap(cubFacets);					
	}
	
	private IntBuffer intBufferUtil(int[] arr) {
		IntBuffer  mBuffer;
		//初始化ByteBuffer,长度是arr数组的4倍,因为一个int占4字节
		ByteBuffer qbb = ByteBuffer.allocateDirect(arr.length * 4);
		//数组排列用nativeOrder
		qbb.order(ByteOrder.nativeOrder());
		mBuffer = qbb.asIntBuffer();
		mBuffer.put(arr);
		mBuffer.position(0);
		return mBuffer;
	}
	
	private FloatBuffer floteBufferUtil(float[] arr) {
		FloatBuffer  mBuffer;
		//初始化ByteBuffer,长度是arr数组的4倍,因为一个flote占4字节
		ByteBuffer qbb = ByteBuffer.allocateDirect(arr.length * 4);
		//数组排列用nativeOrder
		qbb.order(ByteOrder.nativeOrder());
		mBuffer = qbb.asFloatBuffer();
		mBuffer.put(arr);
		mBuffer.position(0);
		return mBuffer;
	}

	@Override
	public void onDrawFrame(GL10 arg0) {
		arg0.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);//清除屏幕缓存和深度缓存
		arg0.glEnableClientState(GL10.GL_VERTEX_ARRAY);//启用顶点坐标数据
		arg0.glEnableClientState(GL10.GL_COLOR_ARRAY);//启用顶点颜色数据
		arg0.glMatrixMode(GL10.GL_MODELVIEW);//设置当前矩阵模式为模型视图
		/////////////////////////////绘制第一个图形//////////////////////////////////////////////////////////////////
		arg0.glLoadIdentity();
		arg0.glTranslatef(0.0f, 0.5f, 0.0f);
		arg0.glRotatef(rotateY, 0.0f, 1.0f, 0.0f);//沿着Y轴旋转
		arg0.glRotatef(rotateX, 1.0f, 0.0f, 0.0f);
		
		arg0.glVertexPointer(3, GL10.GL_FLOAT, 0, taperVerticesBuffer);//设置顶点位置数据
		arg0.glColorPointer(4, GL10.GL_FIXED, 0, taperColorBuffer);//设置顶点颜色数据
		arg0.glDrawElements(GL10.GL_TRIANGLE_STRIP, taperFacesBuffer.remaining(), GL10.GL_UNSIGNED_BYTE, taperFacesBuffer);//按taperFacesBuffer指定的面绘制三角形
		
        /////////////////////////////绘制第二个图形//////////////////////////////////////////////////////////////////
		
		arg0.glLoadIdentity();
		arg0.glTranslatef(0.0f, -0.5f, 0.0f);
		arg0.glRotatef(rotateY, 0.0f, 1.0f, 0.0f);
		arg0.glRotatef(rotateX, 1.0f, 0.0f, 0.0f);
		arg0.glVertexPointer(3, GL10.GL_FLOAT, 0, cubeVerticesBuffer);
		arg0.glDrawElements(GL10.GL_TRIANGLE_STRIP, cubeFacesBuffer.remaining(), GL10.GL_UNSIGNED_BYTE, cubeFacesBuffer);
		//绘制结束
		arg0.glFinish();
		arg0.glDisableClientState(GL10.GL_VERTEX_ARRAY);//禁用顶点坐标数据
		arg0.glDisableClientState(GL10.GL_COLOR_ARRAY);//禁用顶点颜色数据
		rotateX+=0.5;
		rotateY+=0.5;
		

	}

	@Override
	public void onSurfaceChanged(GL10 arg0, int arg1, int arg2) {
		arg0.glViewport(0, 0, arg1, arg2);//设置3D视窗的大小及位置
		arg0.glMatrixMode(GL10.GL_PROJECTION);//设置当前矩阵模式为投影模式
		arg0.glLoadIdentity();//初始化单位矩阵
		float ratio = (float)arg1/arg2;
		arg0.glFrustumf(ratio, ratio, -1, 1, 1, 10);//设置透视视窗的空间大小
	}

	@Override
	public void onSurfaceCreated(GL10 arg0, EGLConfig arg1) {
		
		arg0.glDisable(GL10.GL_DITHER);//关闭抗抖动
		arg0.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST);//设置系统对透视进行修正
		arg0.glClearColor(0, 0, 0, 0);
		arg0.glShadeModel(GL10.GL_SMOOTH);//设置平滑模式
		arg0.glEnable(GL10.GL_DEPTH_TEST);//启用深度测试
		arg0.glDepthFunc(GL10.GL_LEQUAL);//设置深度测试的类型
	}

}
////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////
import android.opengl.GLSurfaceView;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.GestureDetector;
import android.view.GestureDetector.OnGestureListener;
import android.view.MotionEvent;

public class MainActivity extends ActionBarActivity {

	MyRenderer renderer;
	GestureDetector gestureDetector;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		GLSurfaceView surfaceView = new GLSurfaceView(this);
		renderer = new MyRenderer();
		surfaceView.setRenderer(renderer);
		setContentView(surfaceView);

		gestureDetector = new GestureDetector(new MyGestureDetectorListener());
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {

		return gestureDetector.onTouchEvent(event);
	}

	public class MyGestureDetectorListener implements OnGestureListener {

		@Override
		public boolean onDown(MotionEvent arg0) {
			// TODO Auto-generated method stub
			return false;
		}

		@Override
		public boolean onFling(MotionEvent arg0, MotionEvent arg1, float arg2,
				float arg3) {

			arg2 = arg2 > 2000 ? 2000 : arg2;
			arg2 = arg2 < -2000 ? -2000 : arg2;

			arg3 = arg3 > 2000 ? 2000 : arg3;
			arg3 = arg3 < -2000 ? -2000 : arg3;

			renderer.setRotateX(arg3);
			renderer.setRotateY(arg2);

			return true;
		}

		@Override
		public void onLongPress(MotionEvent arg0) {
			// TODO Auto-generated method stub

		}

		@Override
		public boolean onScroll(MotionEvent arg0, MotionEvent arg1, float arg2,
				float arg3) {
			// TODO Auto-generated method stub
			return false;
		}

		@Override
		public void onShowPress(MotionEvent arg0) {
			// TODO Auto-generated method stub

		}

		@Override
		public boolean onSingleTapUp(MotionEvent arg0) {
			// TODO Auto-generated method stub
			return false;
		}

	}

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值