当前位置: 代码迷 >> Android >> 对Android opengl ES世界坐标系跟纹理坐标系的理解
  详细解决方案

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

热度:97   发布时间:2016-04-28 00:23:15.0
对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

  相关解决方案