zoukankan      html  css  js  c++  java
  • Android OpenGL ES(二)纹理

    五颜六色的立方体并算是什么太有意思的事情,看上去太假,没什么感觉。 解决办法就是纹理贴图了。

    OpenGL 中使用纹理要先用 glEnable 来启用相关功能

    1
    gl.glEnable(GL10.GL_TEXTURE_2D);

    然后先准备一张图片作为纹理贴图,需要注意的是,有些设备对图片的尺寸有要求,我手上这个G7就只支持方形的纹理图片,其它可能的限制还有长宽必须是 2 的 n 次幂,最大尺寸不能超过256或1024等等。弄好图片之后,把它放到 res/drawable 文件夹中,比如 leftcode.png,然后通过资源加载到纹理

    private void loadTexture(GL10 gl) {
        InputStream bitmapStream = null;
        Bitmap bitmap = null;
        try {
            // 打开图片资源流
            bitmapStream = context.getResources().openRawResource(
                    R.drawable.leftcode);
            // 解码图片生成 Bitmap 实例
            bitmap = BitmapFactory.decodeStream(bitmapStream);
      
            // 生成一个纹理对象,并将其ID保存到成员变量 texture 中
            int[] textures = new int[1];
            gl.glGenTextures(1, textures, 0);
            texture = textures[0];
      
            // 将生成的空纹理绑定到当前2D纹理通道
            gl.glBindTexture(GL10.GL_TEXTURE_2D, texture);
      
            // 设置2D纹理通道当前绑定的纹理的属性
            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);
      
            // 将bitmap应用到2D纹理通道当前绑定的纹理中
            GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);
      
        } finally {
            // 释放资源
            // BTW: 期待 android 早日支持 Java 新的 try-with-resource 语法
      
            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 对象即不再需要,可以丢弃。

    最后,将在 HelloWorldRenderer 构造方法中将参数 Main Activity 存入成员变量 context 中以便在 loadTexture 中用于访问资源。并在 onSurfaceCreated 中调用 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);
      
    // 设置正面
    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);


       

    修改投景变换矩阵以显示这个稍大些的立方体

    GLU.gluLookAt(gl, 30f, 30f, 30f, 0f, 0f, 0f, 0, 1, 0);


       

    好, 运行一下,看上去还不错

    android-opengles-2-screenshot

    最终代码: android-opengles-2.zip   

  • 相关阅读:
    2018 秋招找工作总结
    Java 实现 LRU 缓存
    历时2个月,星云链DApp开发总结
    Java 版快速排序 + 最挫的优化
    MacOS 下防止 rm 命令误删
    Java使用Log日志系统(common-logging和log4j)
    IDEA+Maven+Spring+SpringMVC+SpringJDBC整合Demo
    Java简单实现并发编程
    设计模式学习笔记——单例模式
    Java获取网页内容
  • 原文地址:https://www.cnblogs.com/xieyuan/p/3787309.html
Copyright © 2011-2022 走看看