GLES2中如何显示图像纹理?

How to display the image texture in GLES2?

如何在GLES2中显示图像纹理。

在初始化 GLES2 显示的下面源代码中,表面 .., 创建离线帧缓冲区, 加载 RGBA 图像到纹理,

正在用蓝色清屏, 尝试显示加载的图像纹理(.. 未能为 GLES2 找到正确的 API) 读取 FBO 并写入文件。

用于显示 glEnableClientState&glVertexPointer API 在 GLES2 中不支持 如何在 GLES2 中显示加载的图像纹理。 在下面的源代码中,从 glReadPixels

获得的缓冲区中只有蓝色
unsigned char *video_raw = loadFile("./video.raw");//RGBA raw image
    int iConfigs;
    EGLConfig eglConfig;
    EGLint ai32ContextAttribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2,EGL_NONE };
    EGLDisplay eglDisplay = eglGetDisplay((EGLNativeDisplayType)0);
    eglInitialize(eglDisplay, 0, 0);
    eglBindAPI(EGL_OPENGL_ES_API);
    EGLint pi32ConfigAttribs[5];
    pi32ConfigAttribs[0] = EGL_SURFACE_TYPE;
    pi32ConfigAttribs[1] = EGL_WINDOW_BIT;
    pi32ConfigAttribs[2] = EGL_RENDERABLE_TYPE;
    pi32ConfigAttribs[3] = EGL_OPENGL_ES2_BIT;
    pi32ConfigAttribs[4] = EGL_NONE;
    eglChooseConfig(eglDisplay, pi32ConfigAttribs, &eglConfig, 1, &iConfigs);
    EGLSurface  eglSurface = eglCreatePbufferSurface(eglDisplay, eglConfig, NULL);
    EGLContext  eglContext = eglCreateContext(eglDisplay, eglConfig, NULL, ai32ContextAttribs);
    eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext);

    GLuint fboId = 0;
    GLuint renderBufferWidth = 960;
    GLuint renderBufferHeight = 540;

    glGenFramebuffers(1, &fboId);
    glBindFramebuffer(GL_FRAMEBUFFER, fboId);

    GLuint renderBuffer;
    glGenRenderbuffers(1, &renderBuffer);
    glBindRenderbuffer(GL_RENDERBUFFER, renderBuffer);

    glRenderbufferStorage(GL_RENDERBUFFER, GL_RGB565, renderBufferWidth, renderBufferHeight);
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderBuffer);

    glClearColor(0.0,0.0,1.0,1.0);
    glClear(GL_COLOR_BUFFER_BIT);

    glEnable(GL_TEXTURE_2D);

    GLuint texture_object_id;
    glGenTextures(1, &texture_object_id);
    glBindTexture(GL_TEXTURE_2D, texture_object_id);

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, renderBufferWidth, renderBufferHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, video_raw);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);


    GLfloat vtx1[] = { -1, -1, 0, -1, 1, 0, 1, 1, 0, 1, -1, 0 };
    GLfloat tex1[] = { 0, 0, 0, 1, 1, 1, 1, 0 };

    /*glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);

    glVertexPointer(3, GL_FLOAT, 0, vtx1);
    glTexCoordPointer(2, GL_FLOAT, 0, tex1);
    glDrawArrays(GL_TRIANGLE_FAN, 0, 4);

    glDisableClientState(GL_VERTEX_ARRAY);
    glDisableClientState(GL_TEXTURE_COORD_ARRAY);*/

    eglSwapBuffers( eglDisplay, eglSurface);

    //read & write to a file
    int size = 4 * renderBufferHeight * renderBufferWidth;
    unsigned char *data2 = new unsigned char[size];
    glReadPixels(0, 0, renderBufferWidth, renderBufferHeight, GL_RGBA, GL_UNSIGNED_BYTE, data2);

    dumptoFile("./read1.raw", size, data2);

编辑 1:

@Rabbid76 , 谢谢回复。当我使用你的顶点着色器时 "in vec3 inPos;\n" 着色器编译失败。我将 "in" 替换为 "uniform".

添加了您的输入后,从以下来源获取黑屏。

static const GLuint WIDTH = 960;
static const GLuint HEIGHT = 540;

static const GLchar* vertex_shader_source =
        "#version 100\n"
        "precision mediump float;\n"
        "uniform vec3 inPos;\n"
        "uniform vec2 inUV;\n"
        "varying vec2 vUV;\n"
        "void main(){\n"
        "    vUV = inUV;\n"
        "    gl_Position = vec4(inPos, 1.0);\n"
        "}\n";

static const GLchar* fragment_shader_source =
        "#version 100\n"
        "precision mediump float;\n"
        "varying vec2 vUV;\n"
        "uniform sampler2D u_texture;\n"
        "void main(){\n"
        "    gl_FragColor = texture2D(u_texture, vUV);\n"
        "}\n";

int main(int argc, char **argv)
{
    unsigned char *video_raw = loadFile("./video.raw");

    int iConfigs;
    EGLConfig eglConfig;
    EGLint ai32ContextAttribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
    EGLDisplay eglDisplay = eglGetDisplay((EGLNativeDisplayType) 0);
    eglInitialize(eglDisplay, 0, 0);
    eglBindAPI(EGL_OPENGL_ES_API);
    EGLint pi32ConfigAttribs[5];
    pi32ConfigAttribs[0] = EGL_SURFACE_TYPE;
    pi32ConfigAttribs[1] = EGL_WINDOW_BIT;
    pi32ConfigAttribs[2] = EGL_RENDERABLE_TYPE;
    pi32ConfigAttribs[3] = EGL_OPENGL_ES2_BIT;
    pi32ConfigAttribs[4] = EGL_NONE;
    eglChooseConfig(eglDisplay, pi32ConfigAttribs, &eglConfig, 1, &iConfigs);
    EGLSurface eglSurface = eglCreatePbufferSurface(eglDisplay, eglConfig, NULL);
    EGLContext eglContext = eglCreateContext(eglDisplay, eglConfig, NULL, ai32ContextAttribs);
    eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext);

    GLuint shader_program, framebuffer, renderBuffer;

    glGenRenderbuffers(1, &renderBuffer);
    glBindRenderbuffer(GL_RENDERBUFFER, renderBuffer);
    glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA, WIDTH, HEIGHT);

    glGenFramebuffers(1, &framebuffer);
    glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderBuffer);

    glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);

    glViewport(0, 0, WIDTH, HEIGHT);
    glEnable(GL_TEXTURE_2D);

    shader_program = common_get_shader_program(vertex_shader_source, fragment_shader_source);

    GLint vert_inx = glGetAttribLocation(shader_program, "inPos");
    GLint uv_inx = glGetAttribLocation(shader_program, "inUV");
    GLint tex_loc = glGetUniformLocation(shader_program, "u_texture");

    GLuint texture_object_id;
    glGenTextures(1, &texture_object_id);
    glBindTexture(GL_TEXTURE_2D, texture_object_id);

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, WIDTH, HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, video_raw);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

    GLfloat vtx1[] = { -1, -1, 0, -1, 1, 0, 1, 1, 0, 1, -1, 0 };
    GLfloat tex1[] = { 0, 0, 0, 1, 1, 1, 1, 0 };

    glVertexAttribPointer(vert_inx, 3, GL_FLOAT, GL_FALSE, 0, vtx1);
    glEnableVertexAttribArray(vert_inx);
    glVertexAttribPointer(uv_inx, 2, GL_FLOAT, GL_FALSE, 0, tex1);
    glEnableVertexAttribArray(uv_inx);

    glViewport(0,0,renderBufferWidth,renderBufferHeight);

    glUseProgram(shader_program);
    glUniform1i(tex_loc, 0);
    glDrawArrays( GL_TRIANGLE_FAN, 0, 4);

    glFlush();

    int size = 4 * WIDTH * HEIGHT;
    unsigned char *data2 = new unsigned char[size];
    glReadPixels(0, 0, WIDTH, HEIGHT, GL_RGBA, GL_UNSIGNED_BYTE, data2);
    dumptoFile("./read1.raw", size, data2);

    return EXIT_SUCCESS;
}

您必须使用着色器程序,并定义通用顶点属性数据的数组。另见 Vertex Specification.

创建、编译并link一个非常简单的着色器程序,如下所示:

const char *sh_vert =
"#version 100\n"\
"precision mediump float;\n"\
"attribute vec3 inPos;\n"\
"attribute vec2 inUV;\n"\
"varying vec2 vUV;\n"\
"void main()\n"\
"{\n"\
"    vUV = inUV;\n"\
"    gl_Position = vec4(inPos, 1.0);\n"\
"}";

const char *sh_frag =
"#version 100\n"\
"precision mediump float;\n"\
"varying vec2 vUV;\n"\
"uniform sampler2D u_texture;\n"\
"void main()\n"\
"{\n"\
"    gl_FragColor = texture2D(u_texture, vUV);\n"\
"}";

GLuint v_sh = glCreateShader( GL_VERTEX_SHADER );
glShaderSource( v_sh, 1, &sh_vert, nullptr );
glCompileShader( v_sh );
GLint status = GL_TRUE;
glGetShaderiv( v_sh, GL_COMPILE_STATUS, &status );
if ( status == GL_FALSE )
{
    // compile error
}

GLuint f_sh = glCreateShader( GL_FRAGMENT_SHADER );
glShaderSource( f_sh, 1, &sh_frag, nullptr );
glCompileShader( f_sh );
status = GL_TRUE;
glGetShaderiv( f_sh, GL_COMPILE_STATUS, &status );
if ( status == GL_FALSE )
{
    // compile error
}

GLuint prog = glCreateProgram();
glAttachShader( prog, v_sh );
glAttachShader( prog, f_sh );
glLinkProgram( prog );
status = GL_TRUE;
glGetProgramiv( prog, GL_LINK_STATUS, &status );
if ( status == GL_FALSE )
{
    // link error
}

获取纹理采样器统一的属性索引和位置:

GLint vert_inx = glGetAttribLocation( prog, "inPos" );
GLint uv_inx   = glGetAttribLocation( prog, "inUV" );
GLint tex_loc  = glGetUniformLocation( prog, "u_texture" );

然后通过(glVertexAttribPointer) and enable them by glEnableVertexAttribArray:

定义通用顶点属性数据的数组
GLfloat vtx1[] = { -1, -1, 0, -1, 1, 0, 1, 1, 0, 1, -1, 0 };
GLfloat tex1[] = { 0, 0, 0, 1, 1, 1, 1, 0 };

glVertexAttribPointer( vert_inx, 3, GL_FLOAT, GL_FALSE, 0, vtx1);
glEnableVertexAttribArray( vert_inx );
glVertexAttribPointer( uv_inx, 2, GL_FLOAT, GL_FALSE, 0, tex1);
glEnableVertexAttribArray( uv_inx );

设置渲染缓冲区和帧缓冲区并调整视口:

glGenFramebuffers(1, &fboId);
glBindFramebuffer(GL_FRAMEBUFFER, fboId);

GLuint renderBuffer;
glGenRenderbuffers(1, &renderBuffer);
glBindRenderbuffer(GL_RENDERBUFFER, renderBuffer);

glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA, renderBufferWidth, renderBufferHeight);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderBuffer);

glViewport(0,0,renderBufferWidth,renderBufferHeight);
glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);

使用该程序,统一设置纹理采样器并绘制几何图形:

// use the program
glUseProgram( prog );
glUniform1i( tex_loc, 0 ); // 0 == texture unit 0

// draw the geometry
glDrawArrays( GL_TRIANGLE_FAN, 0, 4 );

glUseProgram( 0 );

终于可以读图了:

int size = 4 * renderBufferHeight * renderBufferWidth;
unsigned char *data2 = new unsigned char[size];
glReadPixels(0, 0, renderBufferWidth, renderBufferHeight, GL_RGBA, GL_UNSIGNED_BYTE, data2);