zoukankan      html  css  js  c++  java
  • OpenGL ES 详解纹理生成和纹理映射步骤以及函数

    通常一个纹理映射的步骤是:

    1. 创建纹理对象。就是获得一个新的纹理句柄 ID.
    2. 指定纹理。就是将数据赋值给 ID 的纹理对象,在这一步,图像数据正式加载到了 ID 的纹理对象中。
    3. 设定过滤器。定义了opengl现实图像的效果,如纹理放大时的马赛克消除。
    4. 绑定纹理对象。就是将 ID 的纹理作为下面操作的纹理。
    5. 纹理映射。将已绑定纹理的数据绘制到屏幕上去,在这一步,就能看到贴图的效果了。

    一、opengl 中启用纹理映射功能

    在默认设置中,纹理映射是关闭的,启用的参数是 GLTEXTURE2D, 还有其他的参数: GL_TEXTURE_1D, GL_TEXTURE_3D, GL_TEXTURE_CUBE_MAP。我们只用到2D纹理,其他不再赘述。

    gl.glEnable(GL_TEXTURE_2D)
    
    二、创建纹理

    创建纹理,用函数 glGenTextures() 完成,函数返回新创建的纹理的 ID。此函数可以创建 n 个纹理,并将纹理ID 放在 textures 中:

     
    void glGenTextures (int n, IntBuffer textures)

    范例:

    1
    2
    3
    IntBuffer intBuffer = IntBuffer.allocate(1);
    gl.glGenTextures(1, intBuffer);
    int textureId = intBuffer.get(); // 纹理 ID
     指定纹理

    OpenGL 提供了三个函数来指定纹理: glTexImage1D(), glTexImage2D(), glTexImage3D(). 这三个版本用于相应维数的纹理,我们用到的是 2D 版本: glTexImage2D().

     
    void glTexImage2D (int target, int level, int internalformat, int width, int height, int border, int format, int type, Buffer pixels)

    参数过多,可以使用 GLUtils 中的 texImage2D() 函数,好处是直接将 Bitmap 数据作为参数:

     
    void texImage2D (int target, int level, Bitmap bitmap, int border)

    参数:

    target
    操作的目标类型,设为 GL_TEXTURE_2D 即可
    level
    纹理的级别,本节不涉及,设为 0 即可
    bitmap
    图像
    border
    边框,一般设为0
    1
    GLUtils.texImage2D (GL10.GL_TEXTURE_2D, 0, mBitmap, 0);
    删除纹理

    删除纹理, 第三个参数指明了第二个参数 textures 数组中纹理ID 的步长,一般是紧凑顺序存放,设为0即可。

     
    void glDeleteTextures (int n, int[] textures, int offset)

    绑定纹理

    绑定后,此纹理处于活动状态。在第一次绑定一个纹理对象时, 会将一系列初始值来适应你的应用。绑定比较简单,用函数 glBindTexture():

     
    void glBindTexture (int target, int texture)

    第一个参数是纹理类型,我们使用 2D 纹理,参数设为 GL_TEXTURE_2D, 第二个参数是纹理对象的 ID。

    设置过滤器

    有两个版本:float版和int版本。

     
    void glTexParameterf (int target, int pname, float param)  
    void glTexParameterx (int target, int pname, int param)

    一般我们设置两个, 一个放大器的: GL_TEXTURE_MAG_FILTER, 一个缩小器的: GL_TEXTURE_MIN_FILTER.

    下面的两行告诉OpenGL在显示图像时,当它比放大得原始的纹理大 ( GL_TEXTURE_MAG_FILTER )或缩小得比原始得纹理小( GL_TEXTURE_MIN_FILTER )时OpenGL采用的滤波方式。

    通常这两种情况下我都采用 GL_LINEAR 。这使得纹理从很远处到离屏幕很近时都平滑显示。使用 GL_LINEAR 需要CPU和显卡做更多的运算。

    如果您的机器很慢,您也许应该采用 GL_NEAREST 。过滤的纹理在放大的时候,看起来斑驳的很(马赛克)。您也可以结合这两种滤波方式。在近处时使用 GL_LINEAR ,远处时 GL_NEAREST 。

    1
    2
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); // 线形滤波
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); // 线形滤波

     三、纹理映射

    用函数 glTexCoordPointer 指定纹理坐标数组,

     
    void glTexCoordPointer (int size, int type, int stride, Buffer pointer)

    默认这个功能是关闭的,所以需要打开:

    1
    2
    3
    4
    gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
    // ... 
    // 关闭
    gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);

    2 常见的几个问题

     

    2.1 贴图呈现白色

    可能的原因:

    • 未启用 GL_TEXTURE_2D 选项。请使用 glEnable()glDisable() 函数进行开启和关闭。
    • 纹理对象无数据。 使用 GLUtils.texImage2D() 来指定,指定前需 glBindTexture() 激活当前纹理。

    2.2 图像扭曲

    可能的原因:

    • 纹理坐标和顶点坐标对应关系是否正确,调整之
    • 图像的大小不是 2 的次幂, 解决: 内部重新生成一张 2 的次幂的image,调整uv坐标

    3 代码实现

    先定义一个纹理对象,其基本接口有:

    • 创建+指定。 构造函数完成
    • 绑定。
    • 绘制。

    @note: 为了处理 2 的次幂,内部对原始图像不是2的次幂的重新建立了一个图像。详见代码吧。

    public class Texture2D { 
        private int mWidth; 
        private int mHeight; 
        private int mPow2Width; 
        private int mPow2Height; 
        private float maxU = 1.0f; 
        private float maxV = 1.0f; 
          
        private Bitmap mBitmap = null; 
          
        private int textureId = 0; 
          
          
        // 删除纹理数据 
        public void delete(GL10 gl) 
        { 
            if (textureId != 0){ 
                gl.glDeleteTextures(1, new int[]{textureId}, 0); 
                textureId = 0; 
            } 
              
            // bitmap 
            if (mBitmap != null) 
            { 
                if (mBitmap.isRecycled()) 
                    mBitmap.recycle(); 
                mBitmap = null; 
            } 
              
        } 
          
        public static int pow2(int size) 
        { 
            int small = (int)(Math.log((double)size)/Math.log(2.0f)) ; 
            if ( (1 << small) >= size) 
                return 1 << small; 
            else 
                return 1 << (small + 1); 
        } 
          
        // 构建,推迟到第一次绑定时 
        public Texture2D(Bitmap bmp) 
        { 
            // mBitmap = bmp; 
            mWidth = bmp.getWidth(); 
            mHeight = bmp.getHeight(); 
              
            mPow2Height = pow2(mHeight); 
            mPow2Width =pow2(mWidth); 
              
            maxU = mWidth/(float)mPow2Width; 
            maxV = mHeight/(float)mPow2Height; 
              
            Bitmap bitmap = Bitmap.createBitmap(mPow2Width, mPow2Height, 
                    bmp.hasAlpha() ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565); 
            Canvas canvas = new Canvas(bitmap); 
            canvas.drawBitmap(bmp, 0, 0, null); 
            mBitmap = bitmap; 
        } 
          
        // 第一次会加载纹理数据 
        public void bind(GL10 gl) 
        { 
            if (textureId ==0) 
            { 
                int[] textures = new int[1]; 
                gl.glGenTextures(1, textures, 0); 
                textureId = textures[0]; 
                  
                gl.glBindTexture(GL10.GL_TEXTURE_2D, textureId); 
                  
                gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR); 
                gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR); 
                  
                GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, mBitmap, 0); 
                  
                mBitmap.recycle(); 
                mBitmap = null; 
            } 
              
            gl.glBindTexture(GL10.GL_TEXTURE_2D, textureId); 
        } 
          
        // 绘制到屏幕上 
        public void draw(GL10 gl, float x, float y) 
        { 
            gl.glEnable(GL10.GL_TEXTURE_2D); 
            gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY); 
            gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); 
       
            //  绑定 
            this.bind(gl); 
              
            // 映射 
            FloatBuffer verticleBuffer = FloatBuffer.wrap(new float[]{ 
                x,y, 
                x+mWidth, 0, 
                x, y+mHeight, 
                x+mWidth, y+mHeight, 
            }); 
            FloatBuffer coordBuffer = FloatBuffer.wrap(new float[]{ 
                0,0, 
                maxU,0, 
                0,maxV, 
                maxU,maxV, 
            }); 
              
            gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, coordBuffer); 
            gl.glVertexPointer(2, GL10.GL_FLOAT, 0, verticleBuffer); 
            gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP,0,4); 
              
            gl.glDisableClientState(GL10.GL_VERTEX_ARRAY); 
            gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY); 
            gl.glDisable(GL10.GL_TEXTURE_2D); 
        } 
          
        public void draw(GL10 gl, float x, float y, float width, float height) 
        { 
            gl.glEnable(GL10.GL_TEXTURE_2D); 
            gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY); 
            gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); 
              
            //  绑定 
            bind(gl); 
              
            // 映射 
            // 映射 
            FloatBuffer verticleBuffer = FloatBuffer.wrap(new float[]{ 
                x,y, 
                x+width, 0, 
                x, y+height, 
                x+width, y+height, 
            }); 
            FloatBuffer coordBuffer = FloatBuffer.wrap(new float[]{ 
                0,0, 
                maxU,0, 
                0,maxV, 
                maxU,maxV, 
            }); 
              
            gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, coordBuffer); 
            gl.glVertexPointer(2, GL10.GL_FLOAT, 0, verticleBuffer); 
            gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP,0,4); 
              
            gl.glDisableClientState(GL10.GL_VERTEX_ARRAY); 
            gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY); 
            gl.glDisable(GL10.GL_TEXTURE_2D); 
              
            gl.glDisableClientState(GL10.GL_VERTEX_ARRAY); 
            gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY); 
            gl.glDisable(GL10.GL_TEXTURE_2D); 
              
        } 
          
    } 

    4 贴图一个机器人

    代码很简单了,在场景 scene 的 draw() 中绘制一个 texture2D, 具体下载代码看看吧:

    public class AndroidScene extends GlObject{ 
        Texture2D texture; 
          
        public AndroidScene() 
        { 
            super(); 
              
            // 使用 assets 文件夹下的 androida.jpg  
            Bitmap androidBitmap = GameSystem.getInstance().getBitmapFromAssets("androida.jpg"); 
            texture = new Texture2D(androidBitmap); 
        } 
          
        public void draw(GL10 gl) 
        { 
            texture.draw(gl, 0, 0); 
        } 
    } 

    这一节有点枯燥,学习愉快。

  • 相关阅读:
    The Python Standard Library
    Python 中的round函数
    Python文件类型
    Python中import的用法
    Python Symbols 各种符号
    python 一行写多个语句
    免费SSL证书(https网站)申请,便宜SSL https证书申请
    元宇宙游戏Axie龙头axs分析
    OLE DB provider "SQLNCLI10" for linked server "x.x.x.x" returned message "No transaction is active.".
    The operation could not be performed because OLE DB provider "SQLNCLI10" for linked server "xxx.xxx.xxx.xxx" was unable to begin a distributed transaction.
  • 原文地址:https://www.cnblogs.com/Anita9002/p/4581024.html
Copyright © 2011-2022 走看看