【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 contextpublic 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@Overridepublic 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@Overridepublic 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.@Overridepublic 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);}
备注说明:
在纹理映射的时候,特别要注意顶点数组和图像纹理数组的数值和顺序,如果顺序不对的话,很可能出现画出来的是个三角形,或者图像是很怪的那种。
三、效果展示:
四、代码下载地址:http://download.csdn.net/detail/ypist/5242701
参考文章: http://blog.csdn.net/seniorwizard/article/details/7816179
本文博客源地址:http://blog.csdn.net/ypist
更多相关文章
- Android(安卓)RadialGradient 放射渲染
- Kotlin For Android介绍
- Android-SQLite使用总结
- android opengl es添加纹理,绘制立方体纹理,立方体使用不同纹理
- [Android]【安卓】Json数据的快速拼装和解析
- Android(安卓)Donut Makefile分析之一 (build/envsetup.sh)
- Android培训班(83)Dalvik虚拟机的初始化
- Message Looper Handler三者之间的关联
- Android(安卓)Zygote源码分析