【Android开发学习35】GL_TRIANGLE_STRIP之纹理贴图

一、基础知识:

 

GL_TRIANGLE_STRIP比GL_TRIANLGES 快100% ~ 200%。

建议:尽可能地使用GL_TRIANGLE_STRIP替代GL_TRIANGLES

 

 

 

二、使用方法:

 

1.首先以框架入手,我们一般在Android上画一个3D的图形,需要在MainActivity的OnCreate函数中加入如下代码,用来进入我们的3D场景界面:

       glView = new GLSurfaceView(this);		// 创建一个GLSurfaceView

       glView.setRenderer(new MyGLRenderer(this));	// 使用定制的渲染器

        setContentView(glView);						

其中,glView为GLSurfaceView glView的引用对象,在MainActivity中的成员变量中声明:

private GLSurfaceView glView;	// 使用GLSurfaceView 

 


2.接下来实现3D场景中的绚烂器(GLSurfaceView.Renderer):

public class MyGLRenderer implements  GLSurfaceView.Renderer {

  // 实现代码

}


①构造函数的编写:

	// Constructor with global application context

	public MyGLRenderer(Context context) {

		this.context = context;

		

		// 设置所用图形的数据数组缓冲区

		cube = new TextureCube();

	}


其中,TextureCube 为我们自己的纹理类,需要自己实现,后面会有实现。context和cube分别为成员变量:

	private Context context;	// 应用的上下文句柄

	

	private TextureCube  cube;

 

②重载函数onSurfaceCreated,创建绚烂器时需要初始化的部分皆在此:

// Call back when the surface is first created or re-created

	@Override

	public void onSurfaceCreated(GL10 gl, EGLConfig config)

	{

		// 启用阴影平滑

		gl.glShadeModel(GL10.GL_SMOOTH);

		

		// 设置背景颜色

		gl.glClearColor(0.2f, 0.4f, 0.52f, 1.0f);

		

		// 设置深度缓存

		gl.glClearDepthf(1.0f);

		

		// 启用深度测试

		gl.glEnable(GL10.GL_DEPTH_TEST);

		

		// 所作深度测试的类型

		gl.glDepthFunc(GL10.GL_LEQUAL);

		

		// 告诉系统对透视进行修正

		gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST);

		

		// 禁止抖动以取得更好的性能

		gl.glDisable(GL10.GL_DITHER);

		

		// 设置纹理

		cube.loadTexture(gl, context);		// 加载纹理

		gl.glEnable(GL10.GL_TEXTURE_2D);	// 纹理使能

	}


以上一些功能的打开和声明,都可以在我博客之前的一些文章中找到,不在详述。

最重要的一句就是  cube.loadTexture(gl, context); 加载纹理。

 

③重载函数onSurfaceChanged,当屏幕旋转(横屏变为竖屏)时,调用。当然,在初始化的时候也是要调用的:

	// Call back after onSurfaceCreated() or whenever the window's size changes

	@Override

	public void onSurfaceChanged(GL10 gl, int width, int height)

	{

		if(height == 0)	// 防止被零除

		{

			height = 1;	

		}

		

		// 重置当前的视图区域

		gl.glViewport(0, 0, width, height);

		

		// 选择投影矩阵

		gl.glMatrixMode(GL10.GL_PROJECTION);

		

		// 重置投影矩阵

		gl.glLoadIdentity();

		

		// 设置视图区域的大小

		GLU.gluPerspective(gl, 45.0f, (float)width/(float)height,0.1f,100.0f);

		

		// 选择模型观察矩阵

		gl.glMatrixMode(GL10.GL_MODELVIEW);

		

		// 重置模型观察矩阵

		gl.glLoadIdentity();

	}


④重载函数onDrawFrame,此为一个回调函数,用来更新场景中的各个对象:

// Call back to draw the current frame.

	@Override

	public void onDrawFrame(GL10 gl)

	{

		// 清除屏幕和深度缓存

		gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);

			

		// 重置当前的模型观察矩阵

		gl.glLoadIdentity();

		gl.glTranslatef(0.0f, 0.0f, -5.0f); // 向屏幕里移动5个单位

		gl.glScalef(0.8f, 0.8f, 0.8f);	// 缩小80%

		// 绕X轴旋转立方体 

		gl.glRotatef(xrot, 1.0f, 0.0f, 0.0f);

		// 绕Y轴旋转立方体

		gl.glRotatef(yrot, 0.0f, 1.0f, 0.0f);

		// 绕Z轴旋转立方体

		gl.glRotatef(zrot, 0.0f, 0.0f, 1.0f);

		

	     // 正方体

		cube.draw(gl);

		

		// 每次刷新之后更新旋转角度

		xrot += 0.3f;

		yrot += 0.2f;

		zrot += 0.4f;

	}

 

 

 

3.接下来实现3D场景中绚烂器的纹理类(TextureCube):

// 生成一个带纹理的立方体

// 这里指定义一个面的顶点,立方体的其他面通过平移和旋转这个面来渲染

public class TextureCube {

// 实现代码

}



①构造函数的编写:

	private float[] vertices = { // 定义一个面的顶点坐标

		-1.0f, -1.0f, 0.0f,  // 0. 左-底-前

		1.0f, -1.0f, 0.0f,   // 1. 右-底-前

		-1.0f,  1.0f, 0.0f,  // 2. 左-顶-前

		1.0f,  1.0f, 0.0f    // 3. 右-顶-前

	};

	

	float[] texCoords = { // 定义上面的面的纹理坐标

        0.0f, 1.0f,  // A. 左-下

        1.0f, 1.0f,  // B. 右-下 

        0.0f, 0.0f,  // C. 左-上 

        1.0f, 0.0f   // D. 右-上

    };



	int[] textureIDs = new int[1]; // 纹理-ID数组

	

	// 构造函数,设置缓冲区

	public TextureCube()

	{

		// 设置顶点数组,顶点数据为浮点数据类型。一个浮点类型的数据长度为四个字节

	    ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4);

	    vbb.order(ByteOrder.nativeOrder()); // 使用原生字节顺序

	    vertexBuffer = vbb.asFloatBuffer(); // 将字节类型缓冲区转换成浮点类型

	    vertexBuffer.put(vertices);         // 将数据复制进缓冲区

	    vertexBuffer.position(0);           // 定位到初始位置

	 

	    // 设置纹理坐标数组缓冲区,数据类型为浮点数据

	    ByteBuffer tbb = ByteBuffer.allocateDirect(texCoords.length * 4);

	    tbb.order(ByteOrder.nativeOrder());

	    texBuffer = tbb.asFloatBuffer();

	    texBuffer.put(texCoords);

	    texBuffer.position(0);

	}


②加载图像函数的实现(loadTexture):

// 加载一个图像到GL纹理

	public void loadTexture(GL10 gl, Context context) {

		gl.glGenTextures(1, textureIDs, 0);	// 生成纹理ID数组

		

		gl.glBindTexture(GL10.GL_TEXTURE_2D, textureIDs[0]);	// 绑定到纹理ID

		// 设置纹理过滤方式

		gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST);

		gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);

		

		// 构造一个输入流来加载纹理文件"res/drawable/nehe.bmp"

		InputStream ins = context.getResources().openRawResource(R.drawable.nehe);

		Bitmap bmp;

		try {

			// 读取并将输入流解码成位图

			bmp = BitmapFactory.decodeStream(ins);

		} finally {

			try {

				ins.close();

			}catch(IOException e) {}

		}

		

		// 根据加载的位图为当前绑定的纹理ID建立纹理

		GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bmp, 0);

	}


③绘图函数的实现(draw):

	// 绘图

	public void draw(GL10 gl){

		gl.glFrontFace(GL10.GL_CCW);    // 正前面为逆时针方向

	    gl.glEnable(GL10.GL_CULL_FACE); // 使能剔除面

	    gl.glCullFace(GL10.GL_BACK);    // 剔除背面(不显示)

	    

	    gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);

	    gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);

	    gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);  // 使能纹理坐标数组

	    gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, texBuffer); // 定义纹理坐标数组缓冲区

	    

	    // 前

	    gl.glPushMatrix();

	    gl.glTranslatef(0.0f, 0.0f, 1.0f);

	    gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);

	    gl.glPopMatrix();

	    

	    // 左

	    gl.glPushMatrix();

	    gl.glRotatef(270.0f, 0.0f, 1.0f, 0.0f);

	    gl.glTranslatef(0.0f, 0.0f, 1.0f);

	    gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);

	    gl.glPopMatrix();

	    

	    // 后

	    gl.glPushMatrix();

	    gl.glRotatef(180.0f, 0.0f, 1.0f, 0.0f);

	    gl.glTranslatef(0.0f, 0.0f, 1.0f);

	    gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);

	    gl.glPopMatrix();



	    // 右

	    gl.glPushMatrix();

	    gl.glRotatef(90.0f, 0.0f, 1.0f, 0.0f);

	    gl.glTranslatef(0.0f, 0.0f, 1.0f);

	    gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);

	    gl.glPopMatrix();



	    // 顶

	    gl.glPushMatrix();

	    gl.glRotatef(270.0f, 1.0f, 0.0f, 0.0f);

	    gl.glTranslatef(0.0f, 0.0f, 1.0f);

	    gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);

	    gl.glPopMatrix();



	    // 底

	    gl.glPushMatrix();

	    gl.glRotatef(90.0f, 1.0f, 0.0f, 0.0f);

	    gl.glTranslatef(0.0f, 0.0f, 1.0f);

	    gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);

	    gl.glPopMatrix();

	    

	    // 恢复原来的状态

	    gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY); 

	    gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);

	    gl.glDisable(GL10.GL_CULL_FACE);

	}

 

备注说明:

在纹理映射的时候,特别要注意顶点数组和图像纹理数组的数值和顺序,如果顺序不对的话,很可能出现画出来的是个三角形,或者图像是很怪的那种。

 

三、效果展示:

【Android开发学习35】GL_TRIANGLE_STRIP之纹理贴图

 

 

四、代码下载地址:http://download.csdn.net/detail/ypist/5242701

 

 

参考文章: http://blog.csdn.net/seniorwizard/article/details/7816179

 

本文博客源地址:http://blog.csdn.net/ypist

 

 

 

你可能感兴趣的:(Android开发)