[SDL + OpenGL ES 2.0以使用着色器显示纹理

问题描述 投票:2回答:2

我目前需要开发一个使用着色器显示简单纹理(由程序通过现有SDL2代码生成的纹理)的程序。现在,要了解结合OpenGL ES 2.0和SDL(在树莓派pi帧缓冲区上)的工作方式,我创建了此示例程序(对不起,它缺少一些错误检查并作为示例)。现在,它应该仅显示使用SDL2_image从文件“ land.png”加载的纹理。

#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>

#define GL_GLEXT_PROTOTYPES 1
#include <SDL2/SDL_opengles2.h>

#include <iostream>

static const char * vertex = 
"attribute vec4 position;"
"attribute vec4 inputTextureCoordinate;"
""
"varying vec2 textureCoordinate;"
""
"void main()"
"{"
"    gl_Position = position;"
"    textureCoordinate = inputTextureCoordinate.xy;"
"}"
"";

static const char * fragment =
"varying highp vec2 textureCoordinate;"
""
"uniform sampler2D videoFrame;"
""
"void main()"
"{"
"    gl_FragColor = texture2D(videoFrame, textureCoordinate);"
"}"
"";

unsigned int program_id = 0;

GLuint TextureID  = 0;

bool compile_program()
{
    unsigned int vertex_id = 0;
    unsigned int fragment_id = 0;
    char infoLog[512];
    int success;
    vertex_id = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertex_id, 1, &vertex, NULL);
    glCompileShader(vertex_id);
    glGetShaderiv(vertex_id, GL_COMPILE_STATUS, &success);
    if(!success)
    {
        glGetShaderInfoLog(vertex_id, 512, NULL, infoLog);
        std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
        glDeleteShader(vertex_id);
        vertex_id = 0;
        return false;
    }
    std::cout << "Vertex shader compiled successfully! Id = " << vertex_id << std::endl;

    fragment_id = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragment_id, 1, &fragment, NULL);
    glCompileShader(fragment_id);
    glGetShaderiv(fragment_id, GL_COMPILE_STATUS, &success);
    if(!success)
    {
        glGetShaderInfoLog(fragment_id, 512, NULL, infoLog);
        std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
        glDeleteShader(vertex_id);
        glDeleteShader(fragment_id);
        vertex_id = 0;
        return false;
    }
    std::cout << "Fragment shader compiled successfully! Id = " << fragment_id << std::endl;


    program_id = glCreateProgram();
    glAttachShader(program_id, vertex_id);
    glAttachShader(program_id, fragment_id);
    glLinkProgram(program_id);

    glGetProgramiv(program_id, GL_LINK_STATUS, &success);
    if(!success)
    {
        glGetProgramInfoLog(program_id, 512, NULL, infoLog);
        std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;
        glDeleteShader(vertex_id);
        glDeleteShader(fragment_id);
        return false;
    }

    TextureID = glGetUniformLocation(program_id, "videoFrame");

    glDeleteShader(vertex_id);
    glDeleteShader(fragment_id);

    return true;
}

int main()
{
    if (SDL_Init(SDL_INIT_EVERYTHING | SDL_VIDEO_OPENGL_ES2) != 0){
        std::cerr << "SDL_Init failed: " << SDL_GetError() << std::endl;
        return 1;
    }

    SDL_Window *win = SDL_CreateWindow("AnyGlobe", SDL_WINDOWPOS_CENTERED,
        SDL_WINDOWPOS_CENTERED, 480, 480, 0);

    SDL_SetHint(SDL_HINT_RENDER_DRIVER, "opengles2");

    SDL_Renderer *renderer = SDL_CreateRenderer(win, -1,
        SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE);

    SDL_RendererInfo rendererInfo;
    SDL_GetRendererInfo(renderer, &rendererInfo);

    std::cout << "Renderer: " << rendererInfo.name << std::endl;
    if(!strncmp(rendererInfo.name, "opengles2", 9)) {
        std::cout << "We have OpenGL ES 2.0" << std::endl;
        compile_program();
    }

    SDL_Texture *land = IMG_LoadTexture(renderer, "land.png");
    if (!land)
    {
        abort();
    }

    int done = 0;
    float position = 0.0;

    SDL_Texture *texTarget = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888,
        SDL_TEXTUREACCESS_TARGET, 480, 480);

   static const GLfloat squareVertices[] = {
        -1.0f, -1.0f,
        1.0f, -1.0f,
        -1.0f,  1.0f,
        1.0f,  1.0f,
    };

    static const GLfloat textureVertices[] = {
        1.0f, 1.0f,
        1.0f, 0.0f,
        0.0f,  1.0f,
        0.0f,  0.0f,
    };

    while ( ! done ) {
        //Render to the texture
        SDL_SetRenderTarget(renderer, texTarget);
        SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
        SDL_RenderClear(renderer);


        SDL_RenderCopy(renderer, land, NULL, NULL);

        SDL_SetRenderTarget(renderer, NULL);
        SDL_SetRenderDrawColor(renderer, 0, 255, 255, 255);
        SDL_RenderClear(renderer);

        GLint old_program = 0;

        if(program_id != 0) {
                glGetIntegerv(GL_CURRENT_PROGRAM, &old_program);
                glUseProgram(program_id);
        }


        glActiveTexture(GL_TEXTURE0);
        SDL_GL_BindTexture(texTarget, NULL, NULL);

        glUniform1i(TextureID, 0);

        glVertexAttribPointer(0, 2, GL_FLOAT, 0, 0, squareVertices);
        glEnableVertexAttribArray(0);
        glVertexAttribPointer(1, 2, GL_FLOAT, 0, 0, textureVertices);
        glEnableVertexAttribArray(1);
        glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

        SDL_GL_SwapWindow(win);

        if(program_id != 0) {
            glUseProgram(old_program);
        }

        SDL_Event event;
        while ( SDL_PollEvent(&event) ) {
            if ( event.type == SDL_QUIT ) {
                done = 1;
            }
            if ( event.type == SDL_KEYDOWN ) {
                if ( event.key.keysym.sym == SDLK_ESCAPE ) {
                    done = 1;
                }
            }
        }
    }

    return 0;
}

当前状态是仅显示彩色背景(由SDL中的RendererDrawColor定义),但不显示纹理,我不能将手指放在上面,为什么它不能正常工作。有人可以特别看一下OpenGL ES代码吗?我很感谢每一个提示。

c++ opengl-es-2.0 raspberry-pi3 sdl-2
2个回答
1
投票

不要将SDL_Renderer内容与OpenGL混合使用,在这条道路上要经历痛苦和疯狂,at least at this point in time


0
投票

我实际上在SDL_Renderer和OpenGL的结合上取得了成功(不是ES,但从理论上讲也应该很好)。如果您只想将片段着色器应用于SDL_Texture,则应该可以对代码进行一些调整。

  1. 而不是自己制作顶点几何图形,请使用SDL_RenderCopySDL_RenderCopyEx
  2. 使用SDL_RenderPresent代替SDL_GL_SwapWindow
  3. 您已经正确使用了SDL_GL_BindTexture,但是您缺少SDL_GL_UnbindTexture

我不知道OpenGL ES,但这是我要执行此操作时使用的OpenGL顶点着色器:

varying vec4 v_color;
varying vec2 v_texCoord;

void main()
{
    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
    v_color = gl_Color;
    v_texCoord = vec2(gl_MultiTexCoord0);
}

此代码直接来自SDL2源代码,因此,如果用于OpenGL ES / ES2的代码不同,请检查其源代码。

© www.soinside.com 2019 - 2024. All rights reserved.