OpenGL ES 的问题,为何图像仅显示在手机屏幕右上第一象限? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
Sign Up Now
For Existing Member  Sign In
begeekmyfriend

OpenGL ES 的问题,为何图像仅显示在手机屏幕右上第一象限?

  •  
  •   begeekmyfriend Oct 24, 2016 12899 views
    This topic created in 3471 days ago, the information mentioned may be changed or developed.

    大家好,我是安卓直播端开源项目 yasea 作者,目前可以通过 OpenGL ES 2.0 将来自摄像头的图像进行滤镜渲染,基本功能已经实现: https://github.com/begeekmyfriend/yasea/tree/gpuimage

    然而是对于磨皮,原来使用 glVertexAttribPointer 直接传递顶点数组的效率太差,导致输出帧率下降。幸好 GLES 2.0 支持 VBO ,我将代码改进如下,基本满足要求: https://github.com/begeekmyfriend/yasea/tree/gpuimage-vbo

    问题是 VBO 替代后,渲染图像仅出现在屏幕右上第一象限中,大小为全屏四分之一。百思不得其解,我并没有改变顶点数组和纹理数组,也没有改变 glViewport 。请大家帮忙。

    P.S.出于兼容性的原因,目前不考虑 GLES 3.0 ,而且 2.0 里的 VBO 基本满足性能问题。

    Supplement 1    Oct 25, 2016

    res/raw/default_vertex.glsl

    attribute vec4 position; attribute vec4 inputTextureCoordinate; varying vec2 textureCoordinate; uniform mat4 textureTransform; void main() { textureCoordinate = (textureTransform * inputTextureCoordinate).xy; gl_Position = position; } 

    渲染代码在此

    7 replies    2016-10-25 19:59:20 +08:00
    jukka
        1
    jukka  
       Oct 25, 2016
    - -# 你直接贴代码上来吧,还要去你的仓库里翻代码。

    你问题提供的信息太少了啊。
    vertex shader 怎么写的?
    你的顶点数据的坐标系是怎么设置的?(-1, 1) normalized 的么?
    begeekmyfriend
        2
    begeekmyfriend  
    OP
       Oct 25, 2016
    @jukka 附言里添加了信息,还需要啥尽管说
    jukka
        3
    jukka  
       Oct 25, 2016
    @begeekmyfriend 运行的截图可以贴么,

    大致看了下代码,
    mGLCubeBuffer = ByteBuffer.allocateDirect(TextureRotationUtil.CUBE.length * 4)
    .order(ByteOrder.nativeOrder())
    .asFloatBuffer();
    mGLCubeBuffer.put(TextureRotationUtil.CUBE).position(0);

    可以先检查一下这些数值。 mGLCubeBuffer
    begeekmyfriend
        4
    begeekmyfriend  
    OP
       Oct 25, 2016
    @jukka 数据源 Cube 应该没有错,因为没有改动过,就是说

    GLES20.glVertexAttribPointer(mGLAttribPosition, 2, GLES20.GL_FLOAT, false, 4 * 2, mGLCubeBuffer)是全屏的。
    GLES20.glVertexAttribPointer(mGLAttribPosition, 2, GLES20.GL_FLOAT, false, 4 * 2, 0)就变成右上角 1/4 了。

    所以我想看看 default_vertex.glsl 的数据有何区别,比如用 vec4 还是 vec2 ( vec4 是否在 VBO 里面哪些分量变成 0 了导致全屏左下角对应到屏幕中心去了)。可惜无法调试,只能一步一步试了。

    另外 V2EX 上我也不知道怎么上图。
    jukka
        5
    jukka  
       Oct 25, 2016
    稍微仔细看了一下你的代码。错误应该是在在这里。

    GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mGLCubeBuffers[0]);
    GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mGLTextureBuffers[0]);

    你可以把 TextureBuffers 的数据改成(-1, -1) 你的画面位置应该就对了。
    或者简单的条换一下这两个函数的调用顺序也可以。

    OpenGL Client 接口是一个状态机。
    OpenGL Client 接口是一个状态机。
    OpenGL Client 接口是一个状态机。

    在 issue 一个 drawcall 之前只能 bind 一个 buffer 。
    你这样写相当于只有一个 buffer 被 bind 了。

    以下是修改建议,

    在 OpenGL ES 上,最好使用 packed 的 vertex 。
    可以参考以下文档。
    https://developer.apple.com/library/content/documentation/3DDrawing/Conceptual/OpenGLES_ProgrammingGuide/TechniquesforWorkingwithVertexData/TechniquesforWorkingwithVertexData.html#//apple_ref/doc/uid/TP40008793-CH107-SW1

    也就是说只使用一个 vbo ,而不是给每一个 buffer 都建立一个 vbo 。

    举个例子,

    struct vertex {
    GLfloat pos[2];
    GLfloat uv[2];
    }

    glVertexAttribPointer(loc_pos, 2, GL_FLOAT, GL_FALSE, sizeof(struct vertex), offsetof(struct vertex, pos)); glVertexAttribPointer(loc_uv, 2, GL_FLOAT, GL_FALSE, sizeof(struct vertex), offsetof(struct vertex, uv));

    offsetof(struct vertex, uv) -> 的值应该是 8
    begeekmyfriend
        6
    begeekmyfriend  
    OP
       Oct 25, 2016
    果然你说的对!我查了一下《 OpenGL ES 3.0 编程指南》,它的写法是

    ```java
    GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mGLCubeBuffers[0]);
    GLES20.glEnableVertexAttribArray(mGLAttribPosition);
    GLES20.glVertexAttribPointer(mGLAttribPosition, 4, GLES20.GL_FLOAT, false, 4 * 4, 0);

    GLES20.lBindBuffer(GLES20.GL_ARRAY_BUFFER, mGLTextureBuffers[0]);
    GLES20.glEnableVertexAttribArray(mGLAttribTextureCoordinate);
    GLES20.glVertexAttribPointer(mGLAttribTextureCoordinate, 4, GLES20.GL_FLOAT, false, 4 * 4, 0);
    ```

    也就是说,我错误的写法相当于只有一个 buffer 被 bind 了。

    另外,除了你所说的 packed 顶点属性,还有一种是每个属性一个 VBO 的写法。文中这样解释:

    每个顶点属性可以顺序方式读取,最有可能造成高效内存访问模式。缺点在于如果顶点属性的一个自己需要修改,将造成缓冲区跨距更新。当顶点属性缓冲区为 VBO 形式,需要重新加载整个缓冲区,可以将动态的顶点属性保存在单独缓冲区避免这种效率低下的情况。

    当然我的顶点属性是静态的,可以考虑用你的方式修改。

    不管怎样,原因找到了,非常感谢您!
    jukka
        7
    jukka  
       Oct 25, 2016 via iPhone   1
    :) 这个 issue 可以关闭了(手动滑稽
    About     Help     Advertise     Blog     API     FAQ     Solana     3619 Online   Highest 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 29ms UTC 04:37 PVG 12:37 LAX 21:37 JFK 00:37
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86