Android OpenGL ES (2) -- 纹理

来源:互联网 发布:js正则表达式\< 编辑:程序博客网 时间:2024/04/27 22:27
 五颜六色的立方体并算是什么太有意思的事情,看上去太假,没什么感觉。 解决办法就是纹理贴图了。

OpenGL 中使用纹理要先用 glEnable 来启用相关功能
gl.glEnable(GL10.GL_TEXTURE_2D);
然后先准备一张图片作为纹理贴图,需要注意的是,有些设备对图片的尺寸有要求,我手上这个G7就只支持方形的纹理图片,其它可能的限制还有长宽必须是 2 的 n 次幂,最大尺寸不能超过256或1024等等。弄好图片之后,把它放到 res/drawable 文件夹中,然后通过资源加载到纹理 。
private void loadTexture(GL10 gl) {InputStream bitmapStream = null;Bitmap bitmap = null;try {bitmapStream = context.getResources().openRawResource(R.drawable.tree);bitmap = BitmapFactory.decodeStream(bitmapStream); int[] textures = new int[1];gl.glGenTextures(1, textures, 0);texture = textures[0]; gl.glBindTexture(GL10.GL_TEXTURE_2D, texture); 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); gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S,GL10.GL_REPEAT);gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T,GL10.GL_REPEAT); GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0); } finally {if (bitmap != null)bitmap.recycle(); if (bitmapStream != null)try {bitmapStream.close();} catch (IOException e) {}}}

BitmapFactory.decodeStream 从流中加载并解码图片并生成Bitmap对象。令人不解的是更解法的 decodeResource 方法在虚拟机中工作良好,但到我的手机中就不行了。

glGenTextures 生成一组纹理并把纹理的ID存入数组参数中。这里只生成了一个。

glBindTexture 将指定ID的纹理绑定到指定的目标中去,接下来对目录所作的操作将针对该纹理进行。

glTexParameterf 设置纹理参数,这里设置了4个参数:

GL_TEXTURE_MIN_FILTER 和 GL_TEXTURE_MAG_FILTER 指定纹理在被缩小或放大时使用的过滤方式,LINEAR (线性插值?)效果要比 NEAREST(最近点?)好但也更需要更多运算。
GL_TEXTURE_WRAP_S 和 GL_TEXTURE_WRAP_T 表示当贴图坐标不在 0.0-1.0 之间时如何处理,这里使用 REPEAT 即平铺贴图。

GLUtils.texImage2D 辅助方法用于将 Bitmap 对象设置到纹理目录中,设置完后 Bitmap 对象即不再需要,可以丢弃。

最后,在 onSurfaceCreated 中调用 loadTexture 加载纹理。将在 HelloWorldRenderer 构造方法中将参数 Main Activity 存入成员变量 context 中以便在 loadTexture 中用于访问资源。

在绘制图元之前,使用 glBindTexture 将纹理绑定到目标中,在接下来的绘制中纹理将自动应用。但在此之前,还需要设置好纹理坐标

    private float[] data_tvertices = { 1.0000f, 1.0000f, 1.0000f, 0.0000f,0.0000f, 0.0000f, 0.0000f, 0.0000f, 0.0000f, 1.0000f, 1.0000f,1.0000f, 0.0000f, 1.0000f, 1.0000f, 1.0000f, 1.0000f, 0.0000f,1.0000f, 0.0000f, 0.0000f, 0.0000f, 0.0000f, 1.0000f, 0.0000f,1.0000f, 1.0000f, 1.0000f, 1.0000f, 0.0000f, 1.0000f, 0.0000f,0.0000f, 0.0000f, 0.0000f, 1.0000f, 0.0000f, 1.0000f, 1.0000f,1.0000f, 1.0000f, 0.0000f, 1.0000f, 0.0000f, 0.0000f, 0.0000f,0.0000f, 1.0000f, 0.0000f, 1.0000f, 1.0000f, 1.0000f, 1.0000f,0.0000f, 1.0000f, 0.0000f, 0.0000f, 0.0000f, 0.0000f, 1.0000f,0.0000f, 1.0000f, 1.0000f, 1.0000f, 1.0000f, 0.0000f, 1.0000f,0.0000f, 0.0000f, 0.0000f, 0.0000f, 1.0000f, };
以上坐标是由3ds max 场景中导出,除此之外将原有的顶点坐标及顶点索引数组的内容也一并更新,也是从同一 3ds max 场景中导出(该场景只有一个立方体)
    private float[] data_vertices = { -5.0f, -5.0f, -5.0f, -5.0f, 5.0f, -5.0f,5.0f, 5.0f, -5.0f, 5.0f, 5.0f, -5.0f, 5.0f, -5.0f, -5.0f, -5.0f,-5.0f, -5.0f, -5.0f, -5.0f, 5.0f, 5.0f, -5.0f, 5.0f, 5.0f, 5.0f,5.0f, 5.0f, 5.0f, 5.0f, -5.0f, 5.0f, 5.0f, -5.0f, -5.0f, 5.0f,-5.0f, -5.0f, -5.0f, 5.0f, -5.0f, -5.0f, 5.0f, -5.0f, 5.0f, 5.0f,-5.0f, 5.0f, -5.0f, -5.0f, 5.0f, -5.0f, -5.0f, -5.0f, 5.0f, -5.0f,-5.0f, 5.0f, 5.0f, -5.0f, 5.0f, 5.0f, 5.0f, 5.0f, 5.0f, 5.0f, 5.0f,-5.0f, 5.0f, 5.0f, -5.0f, -5.0f, 5.0f, 5.0f, -5.0f, -5.0f, 5.0f,-5.0f, -5.0f, 5.0f, 5.0f, -5.0f, 5.0f, 5.0f, 5.0f, 5.0f, 5.0f,5.0f, 5.0f, -5.0f, -5.0f, 5.0f, -5.0f, -5.0f, -5.0f, -5.0f, -5.0f,-5.0f, 5.0f, -5.0f, -5.0f, 5.0f, -5.0f, 5.0f, 5.0f, -5.0f, 5.0f,-5.0f, };    private byte[] data_triangles = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,30, 31, 32, 33, 34, 35, };

在 createBuffers 中添加
            tvertices = ByteBuffer.allocateDirect(data_tvertices.length * 4);            tvertices.order(ByteOrder.nativeOrder());            tvertices.asFloatBuffer().put(data_tvertices);            tvertices.position(0);
最后在绘制代码中添加纹理及纹理坐标设置的代码
            // 启用顶点数组、法向量、纹理坐标数组            gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);            gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);             // 设置顶点数组指针为 ByteBuffer 对象 vertices            // 第一个参数为每个顶点包含的数据长度(以第二个参数表示的数据类型为单位)            gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertices);            gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, tvertices);            // 绑定纹理            gl.glBindTexture(GL10.GL_TEXTURE_2D, texture);             // 绘制 triangles 表示的三角形            gl.glDrawElements(GL10.GL_TRIANGLES, triangles.remaining(),                    GL10.GL_UNSIGNED_BYTE, triangles);             // 禁用顶点、法向量、纹理坐标数组            gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);            gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
修改投景变换矩阵以显示这个稍大此的立方体
GLU.gluLookAt(gl, -20f, -20f, 20f, 0f, 0f, 0f, 0, 0, 1);
运行,这次立方体的六个面都贴上了同一张图片。

最终代码:

// file : HelloWorldRenderer.java package com.leftart.android.HelloWorld; import java.nio.*;import javax.microedition.khronos.egl.*;import javax.microedition.khronos.opengles.*;import android.content.Context;import android.graphics.*;import android.opengl.GLSurfaceView.Renderer;import android.opengl.*; public class HelloWorldRenderer implements Renderer {public HelloWorldRenderer(Main main) {this.context = main;createBuffers();} public void onSurfaceCreated(GL10 gl, EGLConfig config) {gl.glDisable(GL10.GL_DITHER); // 颜色抖动据说可能严重影响性能,禁用gl.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);// 设置清除颜色缓冲区时用的RGBA颜色值 gl.glEnable(GL10.GL_DEPTH_TEST);gl.glDepthFunc(GL10.GL_LEQUAL);gl.glClearDepthf(1f); gl.glEnable(GL10.GL_TEXTURE_2D);loadTexture(gl);} public void onSurfaceChanged(GL10 gl, int width, int height) {// 宽高比float aspect = (float) width / (float) (height == 0 ? 1 : height); // 设置视口gl.glViewport(0, 0, width, height); // 设置当前矩阵堆栈为投影矩阵,并将矩阵重置为单位矩阵gl.glMatrixMode(GL10.GL_PROJECTION);gl.glLoadIdentity(); GLU.gluPerspective(gl, 45.0f, aspect, 0.1f, 200.0f);GLU.gluLookAt(gl, -20f, -20f, 20f, 0f, 0f, 0f, 0, 0, 1);} public void onDrawFrame(GL10 gl) {// 清除颜色缓冲gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT); // 设置当前矩阵堆栈为模型堆栈,并重置堆栈,// 即随后的矩阵操作将应用到要绘制的模型上gl.glMatrixMode(GL10.GL_MODELVIEW);gl.glLoadIdentity(); // 将旋转矩阵应用到当前矩阵堆栈上,即旋转模型gl.glRotatef(anglez, 0, 0, 1);gl.glRotatef(angley, 0, 1, 0);gl.glRotatef(anglex, 1, 0, 0);anglex += 0.1; // 递增角度值以便每次以不同角度绘制angley += 0.2;anglez += 0.3; // 启用顶点数组、法向量、纹理坐标数组gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY); // 设置正面gl.glFrontFace(GL10.GL_CW);// 设置顶点数组指针为 ByteBuffer 对象 vertices// 第一个参数为每个顶点包含的数据长度(以第二个参数表示的数据类型为单位)gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertices);gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, tvertices);// 绑定纹理gl.glBindTexture(GL10.GL_TEXTURE_2D, texture); // 绘制 triangles 表示的三角形gl.glDrawElements(GL10.GL_TRIANGLES, triangles.remaining(),GL10.GL_UNSIGNED_BYTE, triangles); // 禁用顶点、法向量、纹理坐标数组gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);} private void createBuffers() {// 创建顶点缓冲,顶点数组使用 float 类型,每个 float 长4个字节vertices = ByteBuffer.allocateDirect(data_vertices.length * 4);// 设置字节顺序为本机顺序vertices.order(ByteOrder.nativeOrder());// 通过一个 FloatBuffer 适配器,将 float 数组写入 ByteBuffer 中vertices.asFloatBuffer().put(data_vertices);// 重置Buffer的当前位置vertices.position(0); // 创建索引缓冲,索引使用 byte 类型,所以无需设置字节顺序,也无需写入适配。triangles = ByteBuffer.allocateDirect(data_triangles.length * 2);triangles.put(data_triangles);triangles.position(0); normals = ByteBuffer.allocateDirect(data_normals.length * 4);normals.order(ByteOrder.nativeOrder());normals.asFloatBuffer().put(data_normals);normals.position(0); tvertices = ByteBuffer.allocateDirect(data_tvertices.length * 4);tvertices.order(ByteOrder.nativeOrder());tvertices.asFloatBuffer().put(data_tvertices);tvertices.position(0);} private void loadTexture(GL10 gl) {InputStream bitmapStream = null;Bitmap bitmap = null;try {bitmapStream = context.getResources().openRawResource(R.drawable.tree);bitmap = BitmapFactory.decodeStream(bitmapStream); int[] textures = new int[1];gl.glGenTextures(1, textures, 0);texture = textures[0]; gl.glBindTexture(GL10.GL_TEXTURE_2D, texture); 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); gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S,GL10.GL_REPEAT);gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T,GL10.GL_REPEAT); GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0); } finally {if (bitmap != null)bitmap.recycle(); if (bitmapStream != null)try {bitmapStream.close();} catch (IOException e) {}}}private Context context;private ByteBuffer vertices;private ByteBuffer triangles;private ByteBuffer normals;private ByteBuffer tvertices;private int texture; private float anglex = 0f;private float angley = 0f;private float anglez = 0f; private float[] data_vertices = { -5.0f, -5.0f, -5.0f, -5.0f, 5.0f, -5.0f,5.0f, 5.0f, -5.0f, 5.0f, 5.0f, -5.0f, 5.0f, -5.0f, -5.0f, -5.0f,-5.0f, -5.0f, -5.0f, -5.0f, 5.0f, 5.0f, -5.0f, 5.0f, 5.0f, 5.0f,5.0f, 5.0f, 5.0f, 5.0f, -5.0f, 5.0f, 5.0f, -5.0f, -5.0f, 5.0f,-5.0f, -5.0f, -5.0f, 5.0f, -5.0f, -5.0f, 5.0f, -5.0f, 5.0f, 5.0f,-5.0f, 5.0f, -5.0f, -5.0f, 5.0f, -5.0f, -5.0f, -5.0f, 5.0f, -5.0f,-5.0f, 5.0f, 5.0f, -5.0f, 5.0f, 5.0f, 5.0f, 5.0f, 5.0f, 5.0f, 5.0f,-5.0f, 5.0f, 5.0f, -5.0f, -5.0f, 5.0f, 5.0f, -5.0f, -5.0f, 5.0f,-5.0f, -5.0f, 5.0f, 5.0f, -5.0f, 5.0f, 5.0f, 5.0f, 5.0f, 5.0f,5.0f, 5.0f, -5.0f, -5.0f, 5.0f, -5.0f, -5.0f, -5.0f, -5.0f, -5.0f,-5.0f, 5.0f, -5.0f, -5.0f, 5.0f, -5.0f, 5.0f, 5.0f, -5.0f, 5.0f,-5.0f, };private float[] data_normals = {  -5.0f, -5.0f, -5.0f, -5.0f, 5.0f, -5.0f,5.0f, 5.0f, -5.0f, 5.0f, 5.0f, -5.0f, 5.0f, -5.0f, -5.0f, -5.0f,-5.0f, -5.0f, -5.0f, -5.0f, 5.0f, 5.0f, -5.0f, 5.0f, 5.0f, 5.0f,5.0f, 5.0f, 5.0f, 5.0f, -5.0f, 5.0f, 5.0f, -5.0f, -5.0f, 5.0f,-5.0f, -5.0f, -5.0f, 5.0f, -5.0f, -5.0f, 5.0f, -5.0f, 5.0f, 5.0f,-5.0f, 5.0f, -5.0f, -5.0f, 5.0f, -5.0f, -5.0f, -5.0f, 5.0f, -5.0f,-5.0f, 5.0f, 5.0f, -5.0f, 5.0f, 5.0f, 5.0f, 5.0f, 5.0f, 5.0f, 5.0f,-5.0f, 5.0f, 5.0f, -5.0f, -5.0f, 5.0f, 5.0f, -5.0f, -5.0f, 5.0f,-5.0f, -5.0f, 5.0f, 5.0f, -5.0f, 5.0f, 5.0f, 5.0f, 5.0f, 5.0f,5.0f, 5.0f, -5.0f, -5.0f, 5.0f, -5.0f, -5.0f, -5.0f, -5.0f, -5.0f,-5.0f, 5.0f, -5.0f, -5.0f, 5.0f, -5.0f, 5.0f, 5.0f, -5.0f, 5.0f,-5.0f, }; private float[] data_tvertices = { 1.0000f, 1.0000f, 1.0000f, 0.0000f,0.0000f, 0.0000f, 0.0000f, 0.0000f, 0.0000f, 1.0000f, 1.0000f,1.0000f, 0.0000f, 1.0000f, 1.0000f, 1.0000f, 1.0000f, 0.0000f,1.0000f, 0.0000f, 0.0000f, 0.0000f, 0.0000f, 1.0000f, 0.0000f,1.0000f, 1.0000f, 1.0000f, 1.0000f, 0.0000f, 1.0000f, 0.0000f,0.0000f, 0.0000f, 0.0000f, 1.0000f, 0.0000f, 1.0000f, 1.0000f,1.0000f, 1.0000f, 0.0000f, 1.0000f, 0.0000f, 0.0000f, 0.0000f,0.0000f, 1.0000f, 0.0000f, 1.0000f, 1.0000f, 1.0000f, 1.0000f,0.0000f, 1.0000f, 0.0000f, 0.0000f, 0.0000f, 0.0000f, 1.0000f,0.0000f, 1.0000f, 1.0000f, 1.0000f, 1.0000f, 0.0000f, 1.0000f,0.0000f, 0.0000f, 0.0000f, 0.0000f, 1.0000f, }; private byte[] data_triangles = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,30, 31, 32, 33, 34, 35, };}

原创粉丝点击