我目前需要开发一个使用着色器显示简单纹理(由程序通过现有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代码吗?我很感谢每一个提示。
不要将SDL_Renderer内容与OpenGL混合使用,在这条道路上要经历痛苦和疯狂,at least at this point in time。
我实际上在SDL_Renderer
和OpenGL的结合上取得了成功(不是ES,但从理论上讲也应该很好)。如果您只想将片段着色器应用于SDL_Texture
,则应该可以对代码进行一些调整。
SDL_RenderCopy
或SDL_RenderCopyEx
SDL_RenderPresent
代替SDL_GL_SwapWindow
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的代码不同,请检查其源代码。