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干货,源码分析,欢迎关注我的微信公众号,扫一扫下方二维码或者长按识别二维码,即可关注。

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

时间: 2024-08-25 18:56:06

OpenGL ES总结(三)OpenGL通过计算纹理坐标来显示一张图片的相关文章

OpenGL ES 的三种变量类型(uniform,attribute和varying)

1.uniform变量 uniform变量是外部application程序传递给(vertex和fragment)shader的变量.因此它是application通过函数glUniform**()函数赋值的.在(vertex和fragment)shader程序内部,uniform变量就像是C语言里面的常量(const ),它不能被shader程序修改.(shader只能用,不能改) 如果uniform变量在vertex和fragment两者之间声明方式完全一样,则它可以在vertex和frag

iOS实现图形编程可以使用三种API(UIKIT、Core Graphics、OpenGL ES及GLKit)

这些api包含的绘制操作都在一个图形环境中进行绘制.一个图形环境包含绘制参数和所有的绘制需要的设备特定信息,包括屏幕图形环境.offscreen 位图环境和PDF图形环境,用来在屏幕表面.一个位图或一个pdf文件中进行图形和图像绘制.在屏幕图形环境中进行的绘制限定于在一个UIView类或其子类的实例中绘制,并直接在屏幕显示,在offscreen位图或PDF图形环境中进行的绘制不直接在屏幕上显示. 一.UIKIT API UIKIT是一组Objective-C API,为线条图形.Quartz图像

Android OpenGL ES零基础系列(一):理解GLSurfaceView,GLSurfaceView.Render的基本用法

转载请注明出处 前言 OpenGL ES是OpenGL的一个子集,是针对手机.PDA和游戏主机等嵌入式设备而设计的.该API由Khronos集团定义推广,Khronos是一个图形软硬件行业协会,该协会主要关注图形和多媒体方面的开放标准. 因此OpenGL ES作为第三方库被应用在android中. 到目前为止,OpenGL ES已经发展有了3个版本,OpenGL ES 1.0 , OpenGL ES 2.0 , OpenGL ES 3.0.其中OpenGL ES 1.0 是以OpenGL 1.3

OpenGL ES着色器语言之语句和结构体(官方文档第六章)内建变量(官方文档第七、八章)

OpenGL ES着色器语言之语句和结构体(官方文档第六章) OpenGL ES着色器语言的程序块基本构成如下: 语句和声明 函数定义 选择(if-else) 迭代(for, while, do-while) 跳跃(discard, return, break, continue) 6.1函数定义   着色器是由一系列全局声明和函数定义组成的.函数声明规范如下: // prototype returnType functionName (type0 arg0, type1 arg1, ...,

OpenGL ES 2.0 渲染管线 学习笔记

图中展示整个OpenGL ES 2.0可编程管线 图中Vertex Shader和Fragment Shader 是可编程管线: Vertex Array/Buffer objects 顶点数据来源,这时渲染管线的顶点输入,通常使用 Buffer objects效率更好. Vertex Shader 顶点着色器通过矩阵变换位置.计算照明公式来生成逐顶点颜色已经生成或变换纹理坐标等基于顶点的操作. Primitive Assembly 图元装配经过着色器处理之后的顶点在图片装配阶段被装配为基本图元

OpenGL ES总结(一)OpenGL 初识

转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/61615215 OpenGL是在图形图像中,非常优秀的渲染库,文中Demo下载地址:https://github.com/hejunlin2013/OpenGL31,看下今天的Agenda: OpenGL是什么? OpenGL主要功能是什么? OpenGL ES是什么? Android中如何描述OpenGL ES版本 映射坐标绘制对

cocos2d 2.x在opengl es 2.0 下自定义着色器来创建特别酷的特效(译)

cocos2d 2.x在opengl es 2.0 下自定义着色器来创建特别酷的特效(译) (2012-12-24 13:22:17) 转载▼ 标签: it cocos2d opengl 着色器 渲染 翻译:弹涂鱼 PS:欢迎加入开发群:285275050 本文翻译自:http://www.raywenderlich.com/10862/how-to-create-cool-effects-with-custom-shaders-in-opengl-es-2-0-and-cocos2d-2-x#

[转载]OpenGL ES着色器语言之内建函数(官方文档第八章)

OpenGL ES着色语言为标量和向量操作定义了一套内建便利函数.有些内建函数可以用在多个类型的着色器中,有些是针对固定硬件的,所以这部分只能用在某个特定的着色器上. 内建函数基本上可以分为一下三类: (1)它们使用一些简便的方式提供必要的硬件功能,如材质贴图.这些函数单独通过着色器是无法模拟出来的. (2)它们展示了一些可以常简单的写入的繁琐操作(clamp, mix等),但是这些操作非常普遍,并且提供直接对硬件的支持.对于编译器来说,将表达式映射到复杂的装配线指令上是非常困难的. (3)它们

[iTyran原创]iPhone中OpenGL ES显示3DS MAX模型之一:OBJ格式分析

[iTyran原创]iPhone中OpenGL ES显示3DS MAX模型之一:OBJ文件格式分析作者:yuezang - iTyran 在iOS的3D开发中常常需要导入通过3DS MAX之类的3D设计软件生成的模型.因为OpenGL ES是不能直接读取这些文件的,所以常常需要开发人员增加接口来导入.通常的做法是在建模软件中建立3D模型之后在OpenGL ES中导入并进行控制.    3DS MAX通常的保存格式有*.max(现在生成的版本的格式),*.3ds(低版本的3ds Max生成的格式)