对Android opengl ES世界坐标系和纹理坐标系的理解

初学opengl ES,每一个教你在屏幕上贴图的opengl版hello world都有这么两数组:

    static final float COORD[] = {
            -1.0f, -1.0f,
            1.0f, -1.0f,
            -1.0f, 1.0f,
            1.0f, 1.0f,
    };

    static final float TEXTURE_COORD[] = {
            0.0f, 1.0f,
            1.0f, 1.0f,
            0.0f, 0.0f,
            1.0f, 0.0f,
    };

但是几乎都不解释,所以我学的时候都不明白这些点为什么要这么写,前后顺序有没有什么规律。于是各种查资料试验,终于搞懂了。

1.坐标系

PS:本人学opengl es主要是为了2D贴图,所以不涉及Z轴

如图,图一是opengl的世界坐标系,这个基本没啥问题,主要是很多教程说纹理坐标是左下原点。实践得出在Android上应该是最右边的图那样,以左上为原点。

个人猜测纹理吧其实就是一组颜色点组成的数组,Android由于UI坐标是以左上为原点,所以把数组里颜色点的存储顺序改了一下,于是坐标系就不一样了。

2.示例代码

public class Filter {

    protected static final String VERTEX_SHADER = "" +
            "attribute vec4 position;\n" +
            "attribute vec4 inputTextureCoordinate;\n" +
            " \n" +
            "varying vec2 textureCoordinate;\n" +
            " \n" +
            "void main()\n" +
            "{\n" +
            "    gl_Position = position;\n" +
            "    textureCoordinate = inputTextureCoordinate.xy;\n" +
            "}";
    protected static final String FRAGMENT_SHADER = "" +
            "varying highp vec2 textureCoordinate;\n" +
            " \n" +
            "uniform sampler2D inputImageTexture;\n" +
            " \n" +
            "void main()\n" +
            "{\n" +
            "     gl_FragColor = texture2D(inputImageTexture, textureCoordinate);\n" +
            "}";

    static final float COORD1[] = {
            -1.0f, -1.0f,
            1.0f, -1.0f,
            -1.0f, 1.0f,
            1.0f, 1.0f,
    };

    static final float TEXTURE_COORD1[] = {
            0.0f, 1.0f,
            1.0f, 1.0f,
            0.0f, 0.0f,
            1.0f, 0.0f,
    };

    static final float COORD2[] = {
            -1.0f, 1.0f,
            -1.0f, -1.0f,
            1.0f, 1.0f,
            1.0f, -1.0f,
    };

    static final float TEXTURE_COORD2[] = {
            0.0f, 0.0f,
            0.0f, 1.0f,
            1.0f, 0.0f,
            1.0f, 1.0f,
    };

    static final float COORD3[] = {
            1.0f, -1.0f,
            1.0f, 1.0f,
            -1.0f, -1.0f,
            -1.0f, 1.0f,
    };

    static final float TEXTURE_COORD3[] = {
            1.0f, 1.0f,
            1.0f, 0.0f,
            0.0f, 1.0f,
            0.0f, 0.0f,
    };

    static final float COORD4[] = {
            1.0f, -1.0f,
            1.0f, 1.0f,
            -1.0f, -1.0f,
            -1.0f, 1.0f,
    };

    static final float TEXTURE_COORD4[] = {
            1.0f, 1.0f,
            1.0f, 0.0f,
            0.0f, 1.0f,
            0.0f, 0.0f,
    };

    static final float COORD_REVERSE[] = {
            1.0f, -1.0f,
            1.0f, 1.0f,
            -1.0f, -1.0f,
            -1.0f, 1.0f,
    };

    static final float TEXTURE_COORD_REVERSE[] = {
            1.0f, 0.0f,
            1.0f, 1.0f,
            0.0f, 0.0f,
            0.0f, 1.0f,
    };

    static final float COORD_FLIP[] = {
            1.0f, -1.0f,
            1.0f, 1.0f,
            -1.0f, -1.0f,
            -1.0f, 1.0f,
    };

    static final float TEXTURE_COORD_FLIP[] = {
            0.0f, 1.0f,
            0.0f, 0.0f,
            1.0f, 1.0f,
            1.0f, 0.0f,
    };

    private String mVertexShader;
    private String mFragmentShader;

    private FloatBuffer mCubeBuffer;
    private FloatBuffer mTextureCubeBuffer;

    protected int mProgId;
    protected int mAttribPosition;
    protected int mAttribTexCoord;
    protected int mUniformTexture;

    public Filter() {
        this(VERTEX_SHADER, FRAGMENT_SHADER);
    }

    public Filter(String vertexShader, String fragmentShader) {
        mVertexShader = vertexShader;
        mFragmentShader = fragmentShader;
    }

    public void init() {
        loadVertex();
        initShader();
        GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE_MINUS_SRC_ALPHA);
    }

    public void loadVertex() {
        float[] coord = COORD1;
        float[] texture_coord = TEXTURE_COORD1;

        mCubeBuffer = ByteBuffer.allocateDirect(coord.length * 4)
                .order(ByteOrder.nativeOrder())
                .asFloatBuffer();
        mCubeBuffer.put(coord).position(0);

        mTextureCubeBuffer = ByteBuffer.allocateDirect(texture_coord.length * 4)
                .order(ByteOrder.nativeOrder())
                .asFloatBuffer();
        mTextureCubeBuffer.put(texture_coord).position(0);
    }

    public void initShader() {
        mProgId = GLHelper.loadProgram(mVertexShader, mFragmentShader);
        mAttribPosition = GLES20.glGetAttribLocation(mProgId, "position");
        mUniformTexture = GLES20.glGetUniformLocation(mProgId, "inputImageTexture");
        mAttribTexCoord = GLES20.glGetAttribLocation(mProgId,
                "inputTextureCoordinate");
    }

    public void drawFrame(int glTextureId) {
        if (!GLES20.glIsProgram(mProgId)) {
            initShader();
        }
        GLES20.glUseProgram(mProgId);

        mCubeBuffer.position(0);
        GLES20.glVertexAttribPointer(mAttribPosition, 2, GLES20.GL_FLOAT, false, 0, mCubeBuffer);
        GLES20.glEnableVertexAttribArray(mAttribPosition);

        mTextureCubeBuffer.position(0);
        GLES20.glVertexAttribPointer(mAttribTexCoord, 2, GLES20.GL_FLOAT, false, 0,
                mTextureCubeBuffer);
        GLES20.glEnableVertexAttribArray(mAttribTexCoord);

        if (glTextureId != GLHelper.NO_TEXTURE) {
            GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
            GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, glTextureId);
            GLES20.glUniform1i(mUniformTexture, 0);
        }
        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);

        GLES20.glDisableVertexAttribArray(mAttribPosition);
        GLES20.glDisableVertexAttribArray(mAttribTexCoord);
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);

        GLES20.glDisable(GLES20.GL_BLEND);

    }
}

其中

GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);

由于openglES本身就是opengl的缩略版,所以能直接画的形状就只有三角形,别的复杂的都要由三角形来组成。GLES20.GL_TRIANGLE_STRIP指的就是一种三角形的绘制模式,对应这个顶点数组:

  static final float COORD[] = {
            -1.0f, -1.0f,  //1
            1.0f, -1.0f,   //2
            -1.0f, 1.0f,   //3
            1.0f, 1.0f,    //4
    };

实际绘制的就是顶点1,2,3组成的三角形和顶点2,3,4组成的三角形合并成的一个矩形,如果有更多点,依次类推(比如有5个点,就是1,2,3 2,3,4 3,4,5三个三角形组成的图案)。如下图:

3.纹理顶点顺序

纹理的点和世界坐标的点之间是对应的:

    static final float COORD1[] = {
            -1.0f, -1.0f,
            1.0f, -1.0f,
            -1.0f, 1.0f,
            1.0f, 1.0f,
    };

    static final float TEXTURE_COORD1[] = {
            0.0f, 1.0f,
            1.0f, 1.0f,
            0.0f, 0.0f,
            1.0f, 0.0f,
    };

显示结果如图:

如图中箭头,opengl会把纹理中颜色顶点绘到对应的世界坐标顶点上,中间的点则按一定的规律取个平均值什么的,所以可见实际显示的图被上下拉伸了,因为原图是1:1,而在该程序里

GLES20.glViewport(0, 0, width, height);

赋予的显示区域是高大于宽的(这里涉及到opengl世界坐标和屏幕坐标的映射,和本文主旨关系不大就不多说了)。

其实也就是只要世界坐标和纹理坐标数组里的点能够对的上,顺序不是问题

代码里的四组坐标的显示效果都是一样的:

 static final float COORD1[] = {
            -1.0f, -1.0f,
            1.0f, -1.0f,
            -1.0f, 1.0f,
            1.0f, 1.0f,
    };

    static final float TEXTURE_COORD1[] = {
            0.0f, 1.0f,
            1.0f, 1.0f,
            0.0f, 0.0f,
            1.0f, 0.0f,
    };

    static final float COORD2[] = {
            -1.0f, 1.0f,
            -1.0f, -1.0f,
            1.0f, 1.0f,
            1.0f, -1.0f,
    };

    static final float TEXTURE_COORD2[] = {
            0.0f, 0.0f,
            0.0f, 1.0f,
            1.0f, 0.0f,
            1.0f, 1.0f,
    };

    static final float COORD3[] = {
            1.0f, -1.0f,
            1.0f, 1.0f,
            -1.0f, -1.0f,
            -1.0f, 1.0f,
    };

    static final float TEXTURE_COORD3[] = {
            1.0f, 1.0f,
            1.0f, 0.0f,
            0.0f, 1.0f,
            0.0f, 0.0f,
    };

    static final float COORD4[] = {
            1.0f, -1.0f,
            1.0f, 1.0f,
            -1.0f, -1.0f,
            -1.0f, 1.0f,
    };

    static final float TEXTURE_COORD4[] = {
            1.0f, 1.0f,
            1.0f, 0.0f,
            0.0f, 1.0f,
            0.0f, 0.0f,
    };

不信的可以在这里都替换了试试:

      float[] coord = COORD1;
      float[] texture_coord = TEXTURE_COORD1;

为了加深理解,甚至可以玩点花样出来,比如这样

    static final float COORD_REVERSE[] = {
            1.0f, -1.0f,
            1.0f, 1.0f,
            -1.0f, -1.0f,
            -1.0f, 1.0f,
    };

    static final float TEXTURE_COORD_REVERSE[] = {
            1.0f, 0.0f,
            1.0f, 1.0f,
            0.0f, 0.0f,
            0.0f, 1.0f,
    };
  。。。。。。。。。。。。。。。。
      float[] coord = COORD_REVERSE;
      float[] texture_coord = TEXTURE_COORD_REVERSE;

结果如下图:

4.Demo源码地址

https://github.com/yellowcath/GLCoordDemo.git

时间: 2024-10-10 20:56:46

对Android opengl ES世界坐标系和纹理坐标系的理解的相关文章

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

初学Android OpenGL ES之使用纹理 八十三

在网上发现这些讲纹理的文章,非常不错 android 游戏导引(4. 简单纹理贴图) http://www.cnblogs.com/shengdoushi/archive/2011/01/13/1934181.html Android OpenGL es 纹理坐标设定与贴图规则 http://blog.csdn.net/cjkwin/article/details/6016224 Android OpenGL | ES给立方体进行纹理映射 http://www.ourunix.org/andro

Android OpenGL ES 应用(二) 纹理

上一篇讲了基础入门 OpenGL (一) ,这一次主要学习OpenGL 纹理基本学习总结 要是做复杂的OpenGL应用程序,一定会用到纹理技术.纹理说白了就是把图片或者视频图像绘制到OpenGL空间中. 因此纹理也有坐标系,称ST坐标,或者UV 上面是纹理坐标空间,但没有固定的方向 下面演示加载一张image作为纹理贴图. public class TextureUtils { public static int createTexture(InputStream ins) { int[] te

Android OpenGL ES(十二):三维坐标系及坐标变换初步 .

OpenGL ES图形库最终的结果是在二维平面上显示3D物体(常称作模型Model)这是因为目前的打部分显示器还只能显示二维图形.但我们在构造3D模型时必须要有空间现象能力,所有对模型的描述还是使用三维坐标.也就是使用3D建模,而有OpenGL ES库来完成从3D模型到二维屏幕上的显示. 这个过程可以分成三个部分: 坐标变换,坐标变换通过使用变换矩阵来描述,因此学习3D绘图需要了解一些空间几何,矩阵运算的知识.三维坐标通常使用齐次坐标来定义.变换矩阵操作可以分为视角(Viewing),模型(Mo

Android OpenGL ES零基础系列(三):OpenGL ES的渲染管道及VertexShader与FragmentShader

前言 在前2篇文章中,我们都说到着色器,且在第二篇中正式说到,这着色器只能用在OpenGL ES2.x等可编程管道里面,而在OpenGL ES1.x是不能用的.但我们一直没有说这是为什么,两者有什么区别.那这篇我们就一起来学习下OpenGL ES中的渲染管道. 正文 管道,英文名叫Pipeline,相信用过FaceBook图片加载库的同学对这个管道并不陌生,因为SimpleImageDrawee里面也是用的管道来对图片进行的一个处理.由于其底层也是C,因此我可以大胆的猜想,FaceBook图片加

Android OpenGL ES 开发教程 从入门到精通

From:http://blog.csdn.net/mapdigit/article/details/7526556 Android OpenGL ES 简明开发教程 Android OpenGL ES 简明开发教程一:概述 Android OpenGL ES 简明开发教程二:构造OpenGL ES View Android OpenGL ES 简明开发教程三:3D绘图基本概念 Android OpenGL ES 简明开发教程四:3D 坐标变换 Android OpenGL ES 简明开发教程五

[工作记录] Android OpenGL ES 2.0: square texture not supported on some device

npot texture: non-power-of-two texture.rectangle texture: non-square (height != wdith) 在测试Samsumg Galaxy S4的时候, 发现rectangle texture支持不好, 虽然创建成功, 但是绘制有问题. 不同的模块出现类似的情况: 纹理采样出的颜色是(0,0,0,1). 在排除了所有可能的runtime问题以后, 尝试性改了纹理格式无果, 又尝试性的改了下尺寸, 竟然好了. 我擦... 而Ga

[转]Android OpenGL ES 开发教程 从入门到精通

本文转自:http://blog.csdn.net/mapdigit/article/details/7526556 Android OpenGL ES 简明开发教程 Android OpenGL ES 简明开发教程一:概述 Android OpenGL ES 简明开发教程二:构造OpenGL ES View Android OpenGL ES 简明开发教程三:3D绘图基本概念 Android OpenGL ES 简明开发教程四:3D 坐标变换 Android OpenGL ES 简明开发教程五

Android OpenGL ES(八)绘制点Point ..

上一篇介绍了OpenGL ES能够绘制的几种基本几何图形:点,线,三角形.将分别介绍这几种基本几何图形的例子.为方便起见,暂时在同一平面上绘制这些几何图形,在后面介绍完OpenGL ES的坐标系统和坐标变换后,再介绍真正的3D图形绘制方法. 在Android OpenGL ES(六):创建实例应用OpenGLDemos程序框架 创建了示例应用的程序框架,并提供了一个“Hello World”示例. 为避免一些重复代码,这里定义一个所有示例代码的基类OpenGLESActivity,其定义如下: