OpenGL ES总结OpenGL通过计算纹理坐标来显示一张图片

Posted 码农突围

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OpenGL ES总结OpenGL通过计算纹理坐标来显示一张图片相关的知识,希望对你有一定的参考价值。

转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/62444395

通过OpenGL来显示一张汽车图片,图片可以看做一个矩形,所以我们先来画一个矩形

OpenGL的基本形状是三角形,一个矩形可以看成由4个三角形构成,如果我们一个一个画,那需要12个顶点,36个坐标,效率不高,所以我们采用另外一种方式——顶点索引与glDrawElements配合使用。

什么是顶点索引呢?顶点索引就是给出顶点的下标而不给出具体的顶点坐标,如下声明:

private final float[] mVertexData = {
        0f,0f,0f,
        1f,1f,0f,
        -1f,1f,0f,
        -1f,-1f,0f,
        1f,-1f,0f
};

private final short[] mIndexData = {
        0,1,2,
        0,2,3,
        0,3,4,
        0,4,1
};

我们的绘制区域是(-1,-1)到(1,1)的平面区域,mVertexData给出了5个顶点,mIndexData给出了4个三角形的【号位点,如打球时,有1号位,2号位】描述,如下图所示:

这里写图片描述

声明一个ShortBuffer ,用来存放顶点的索引数据

private ShortBuffer mIndexBuffer;

mIndexBuffer= ByteBuffer.allocateDirect(mIndexData.length * 2)
        .order(ByteOrder.nativeOrder())
        .asShortBuffer()
        .put(indexData);
mIndexBuffer.position(0);

这个就是开始站好位置。

然后,使用GLES30.glDrawElements把三角形画出来

GLE30.glDrawElements(GLES30.GL_TRIANGLES,mIndexData.length,GLES30.GL_UNSIGNED_SHORT,mIndexBuffer);

接着创建一个纹理

public class CustomTexture {

    private static final String TAG = CustomTexture.class.getSimpleName();

    public static int loadTexture(Context context, int resourceId) {

        final int[] textureObjectIds = new int[1];
        GLES30.glGenTextures(1, textureObjectIds, 0);
        if (textureObjectIds[0] == 0) {
            Log.d(TAG, ">> create texture fail");
            return 0;
        }

        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inScaled = false;
        Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), resourceId, options);

        if (bitmap == null) {
            Log.d(TAG, ">> load bitmap fail");
            GLES30.glDeleteTextures(1, textureObjectIds, 0);
            return 0;
        }

        GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, textureObjectIds[0]);
        GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MIN_FILTER, GLES30.GL_LINEAR_MIPMAP_LINEAR);
        GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MAG_FILTER, GLES30.GL_LINEAR);
        GLUtils.texImage2D(GLES30.GL_TEXTURE_2D, 0, bitmap, 0);
        bitmap.recycle();

        //与target相关联的纹理图像生成一组完整的mipmap
        GLES30.glGenerateMipmap(GLES30.GL_TEXTURE_2D);
        GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, 0);
        return textureObjectIds[0];
    }
}

一张图,看清纹理坐标及OpenGL坐标

这里写图片描述

配置顶点shader(着色器)
vertex_shader.glsl

attribute vec4 aPosition;
attribute vec2 aTexCoord;
varying vec2 vTexCoord;
uniform mat4 uMatrix;
void main() {
    vTexCoord=aTexCoord;
    gl_Position = uMatrix*aPosition;
}

aTexCoord是一个二维向量,表示纹理的坐标,
varying这个变量是用来在vertex_shader和fragment_shader之间传递值用的,所以名称要相同,我们把aTexCoord赋值给vTexCoord,然后来看car_shader的配置

car_shader.glsl

precision mediump float;
varying vec2 vTexCoord;
uniform sampler2D sTexture;
void main() {
    gl_FragColor = texture2D(sTexture,vTexCoord);
}

在car_shader中,我们声明了一个uniform常量,类型是sampler2D,这个类型是指一个二维的纹理数据数组 ,使用texture2D来处理被插值的纹理坐标vTexCoord和纹理数据sTexture,得到的颜色值就是要显示的颜色,交给gl_FragColor

然后通过glAttachShader,link到program.
 
一般进程获取一个链接的着色器对象包括6个步骤

  • 1、创建顶点着色器和片段着色器
  • 2、将源码附加在每个着色器对象中
  • 3、编译着色器对象
  • 4、创建程序对象
  • 5、将编译的着色器对象附加到程序对象中
  • 6、链接程序对象

如果链接成功,我们就可以随时绘制。下面详细介绍执行这些进程的API

  创建并编译着色器

  GLuint glCreareShader(GLenum type) type :着色器类型【GL_VERTEX_SHADER,GL_FRAGMENT_SHADER】,返回对象为新着色器对象的句柄

  void glDeleteShader(GLuint shader): shader 删除该着色器对象(如果一个着色器对象在删除前已经链接到程序对象中,那么当执行glDeleteShader函数时不会立即被删除,而是该着色器对象将被标记为删除,器内存被释放一次,它不再链接到其他任何程序对象)。

GLES30.glAttachShader(program, vertexShader);
checkGlError("glAttachShader");
GLES30.glAttachShader(program, pixelShader);
checkGlError("glAttachShader");
GLES30.glLinkProgram(program);
int[] linkStatus = new int[1];
GLES30.glGetProgramiv(program, GLES30.GL_LINK_STATUS, linkStatus, 0);
if (linkStatus[0] != GLES30.GL_TRUE) {
       Log.e(TAG, "Could not link program: ");
       Log.e(TAG, GLES30.glGetProgramInfoLog(program));
       GLES30.glDeleteProgram(program);
       program = 0;
}

当我要显示一张1072*768的图示,由于它不是正方形,需要重新对其计算坐标

这里写图片描述

如图,红色就是对应的纹理坐标

于是我们有

    // 5个点,三角形显示区域
    private final float[] mVertexData = {
             0f,    0f,    0f,
             1.0f,  0.75f, 0f,
            -1.0f,  0.75f, 0f,
            -1.0f, -0.75f, 0f,
             1.0f, -0.75f, 0f
    };

    private final short[] mIndexData = {
            0, 1, 2, // 0号点,1号点,2号点组成一个三角形
            0, 2, 3, // 0号点,2号点,3号点组成一个三角形
            0, 3, 4, // 0号点,3号点,4号点组成一个三角形
            0, 4, 1 // 0号点, 4号点,1号点组成一个三角形
    };

    //纹理坐标
    private final float[] mTextureVertexData = {
            0.5f,0.375f,
            1f,0f,
            0f,0f,
            0f,0.75f,
            1f,0.75f
    };

最后在onDrawFrame中

    public void onDrawFrame(GL10 gl) {
        GLES30.glClear(GLES30.GL_DEPTH_BUFFER_BIT | GLES30.GL_COLOR_BUFFER_BIT);
        GLES30.glUseProgram(mProgramId);
        GLES30.glUniformMatrix4fv(mMatrix, 1, false, projectionMatrix, 0);
        GLES30.glEnableVertexAttribArray(mPosition);
        GLES30.glVertexAttribPointer(mPosition, 3, GLES30.GL_FLOAT, false,
                12, mVertexBuffer);

        GLES30.glEnableVertexAttribArray(aTextureCoordHandle);
        GLES30.glVertexAttribPointer(aTextureCoordHandle, 2, GLES30.GL_FLOAT, false, 8, mTextureVertexBuffer);

        GLES30.glActiveTexture(GLES30.GL_TEXTURE0);
        GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, textureId);

        GLES30.glUniform1i(uTextureSamplerHandle, 0);

        GLES30.glDrawElements(GLES30.GL_TRIANGLES, mIndexData.length, GLES30.GL_UNSIGNED_SHORT, mIndexBuffer);
    }

实现效果如图:

这里写图片描述

第一时间获得博客更新提醒,以及更多android干货,源码分析,欢迎关注我的微信公众号,扫一扫下方二维码或者长按识别二维码,即可关注。

这里写图片描述
如果你觉得好,随手点赞,也是对笔者的肯定,也可以分享此公众号给你更多的人,原创不易

以上是关于OpenGL ES总结OpenGL通过计算纹理坐标来显示一张图片的主要内容,如果未能解决你的问题,请参考以下文章

我的OpenGL学习进阶之旅关于OpenGL ES 绘制纹理,因为加载纹理坐标设置错误,导致纹理无法渲染的问题

我的OpenGL学习进阶之旅关于OpenGL ES 绘制纹理,因为加载纹理坐标设置错误,导致纹理无法渲染的问题

OPENGL ES 2.0 知识串讲 (10) ——OPENGL ES 详解IV(纹理优化)

OPENGL ES 2.0 知识串讲 (10) ——OPENGL ES 详解IV(纹理优化)

iOS OpenGL ES简单绘制纹理

OpenGL ES iOS 入门实例