Почему эта простая программа OpenGL ES 2.0/SDL 2 не позволяет мне изменять размер точечного спрайта?

Я работал над простой программой OpenGL ES 2.0 (вместе с SDL 2, чтобы немного упростить ситуацию) и решил опробовать точечные спрайты. Мне удалось заставить их рисовать успешно, но я не смог изменить их размер, выведя gl_PointSize из вершинного шейдера. Теоретически, это должно быть все, что я должен сделать.

Следующий фрагмент кода является очень урезанной версией моего кода на языке C++ (вообще без проверки ошибок, но это потому, что в этом нет ничего плохого), который демонстрирует, как я пытаюсь изменить размер моих точечных спрайтов., Он был протестирован на двух довольно разных компьютерах с похожими результатами (Linux, но 32-битный / программный рендеринг по сравнению с 64-битным / дискретным GPU) и может быть скомпилирован с использованием g++ с g++ main.cpp -lSDL2 -Wall -D_REENTRANT -lGLESv2,

#include <GLES2/gl2.h>
#include <SDL2/SDL.h>

struct myData {
    SDL_Window *window;
    SDL_GLContext context;
};

const GLchar vertex[] =
    "#version 100\n"
    "precision mediump float;\n"
    "void main()\n"
    "{\n"
    "   gl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n"
    "   gl_PointSize = 128.0;\n"
    "}\0";

const GLchar fragment[] =
    "#version 100\n"
    "precision mediump float;\n"
    "void main()\n"
    "{\n"
    "   gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
    "}\0";

GLuint loadShader(GLuint program, GLenum type, const GLchar *shaderSrc) {
    GLuint shader;
    shader = glCreateShader(type);
    glShaderSource(shader, 1, &shaderSrc, NULL);
    glCompileShader(shader);
    glAttachShader(program, shader);
    return 0;
}

int sdlInit(myData *data) {
    SDL_Init(SDL_INIT_VIDEO);
    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
    SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);

    data->window = SDL_CreateWindow("Demo", 0, 0, 512, 512, SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN);
    data->context = SDL_GL_CreateContext(data->window);

    return 0;
}

int glInit(myData *data) {
    GLuint programObject;
    programObject = glCreateProgram();
    loadShader(programObject, GL_VERTEX_SHADER, vertex);
    loadShader(programObject, GL_FRAGMENT_SHADER, fragment);
    glLinkProgram(programObject);
    glUseProgram(programObject);

    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    glViewport(0, 0, 512, 512);

    return 0;
}

int loopFunc(myData *data) {
    SDL_Event event;
    while (SDL_PollEvent(&event)) {
        if (event.type == SDL_QUIT) {
            return 1;
        }
    }

    glClear(GL_COLOR_BUFFER_BIT);
    glDrawArrays(GL_POINTS, 0, 1);
    SDL_GL_SwapWindow(data->window);

    return 0;
}

void sdlQuit(myData *data) {
    SDL_GL_DeleteContext(data->context);
    SDL_DestroyWindow(data->window);
    SDL_Quit();
    return;
}

int main() {
    myData data;

    sdlInit(&data);

    glInit(&data);

    while (!loopFunc(&data));

    sdlQuit(&data);

    return 0;
}

При запуске программа должна создать точечный спрайт размером 128 пикселей в соответствии со значением, которое я установил в вершинном шейдере. Однако при фактическом выполнении размер спрайта точек в центре окна составляет ровно один пиксель. Что я делаю неправильно?

1 ответ

Пара вещей:

  • Как отметил jumapico, убедитесь, что вы действительно запрашиваете контекст ES 2.0 из SDL, в противном случае вы можете получить обычный контекст OpenGL для настольного компьютера, который поддерживает OpenGL ES. #version 100 Код GLSL; OpenGL рабочего стола требует, чтобы вы включили gl_PointSize с помощью glEnable(GL_PROGRAM_POINT_SIZE),
  • Убедитесь, что ваша реализация GL на самом деле поддерживает gl_PointSize из 128.0 проверяя GL_ALIASED_POINT_SIZE_RANGE; спецификация требует только того, чтобы реализации поддерживали диапазон от 1,0 до 1,0, все, что выше, является необязательным.

Отлично работает на этой коробке Debian Buster:


Информация о SDL/OpenGL ES:

SDL compiled version: 2.0.9
SDL linked version  : 2.0.9
GL_VENDOR   : X.Org
GL_RENDERER : AMD Radeon (TM) R9 Fury Series (FIJI, DRM 3.27.0, 4.19.0-2-amd64, LLVM 7.0.1)
GL_VERSION  : OpenGL ES 3.2 Mesa 18.3.4
GLSL version: OpenGL ES GLSL ES 3.20
gl_PointSize min: 1
gl_PointSize max: 2048

Код:

// g++ `pkg-config --cflags sdl2 glesv2` main.cpp `pkg-config --libs sdl2 glesv2`
#include <SDL.h>
#include <SDL_opengles2.h>
#include <iostream>

void CheckStatus( GLuint obj, bool isShader )
{
    GLint status = GL_FALSE, log[ 1 << 11 ] = { 0 };
    ( isShader ? glGetShaderiv : glGetProgramiv )( obj, isShader ? GL_COMPILE_STATUS : GL_LINK_STATUS, &status );
    if( status == GL_TRUE ) return;
    ( isShader ? glGetShaderInfoLog : glGetProgramInfoLog )( obj, sizeof( log ), NULL, (GLchar*)log );
    std::cerr << (GLchar*)log << "\n";
    std::exit( EXIT_FAILURE );
}

void AttachShader( GLuint program, GLenum type, const char* src )
{
    GLuint shader = glCreateShader( type );
    glShaderSource( shader, 1, &src, NULL );
    glCompileShader( shader );
    CheckStatus( shader, true );
    glAttachShader( program, shader );
    glDeleteShader( shader );
}

const char* const vert = 1 + R"GLSL(
#version 100
precision mediump float;
void main()
{
    gl_Position = vec4( 0.0, 0.0, 0.0, 1.0 );
    gl_PointSize = 128.0;
}
)GLSL";

const char* const frag = 1 + R"GLSL(
#version 100
precision mediump float;
void main()
{
    gl_FragColor = vec4( 1.0, 0.0, 0.0, 1.0 );
}
)GLSL";

int main( int argc, char** argv )
{
    SDL_Init( SDL_INIT_VIDEO );
    SDL_GL_SetAttribute( SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES );
    SDL_GL_SetAttribute( SDL_GL_CONTEXT_MAJOR_VERSION, 2 );
    SDL_GL_SetAttribute( SDL_GL_CONTEXT_MINOR_VERSION, 0 );
    SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
    SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 24 );
    SDL_Window *window = SDL_CreateWindow( "SDL2", 0, 0, 640, 480, SDL_WINDOW_OPENGL );
    SDL_GLContext context = SDL_GL_CreateContext( window );

    // SDL info
    SDL_version compiled;
    SDL_version linked;
    SDL_VERSION( &compiled );
    SDL_GetVersion( &linked );
    std::cout << "SDL compiled version: " << (int)compiled.major << "." << (int)compiled.minor << "." << (int)compiled.patch << "\n";
    std::cout << "SDL linked version  : " << (int)linked.major << "." << (int)linked.minor << "." << (int)linked.patch << "\n";

    // GL info
    std::cout << "GL_VENDOR   : " << glGetString( GL_VENDOR ) << "\n";
    std::cout << "GL_RENDERER : " << glGetString( GL_RENDERER ) << "\n";
    std::cout << "GL_VERSION  : " << glGetString( GL_VERSION ) << "\n";
    std::cout << "GLSL version: " << glGetString( GL_SHADING_LANGUAGE_VERSION ) << "\n";
    float pointSizeRange[2] = { -1.0, -1.0 };
    glGetFloatv( GL_ALIASED_POINT_SIZE_RANGE, pointSizeRange );
    std::cout << "gl_PointSize min: " << pointSizeRange[0] << "\n";
    std::cout << "gl_PointSize max: " << pointSizeRange[1] << "\n";

    GLuint prog = glCreateProgram();
    AttachShader( prog, GL_VERTEX_SHADER, vert );
    AttachShader( prog, GL_FRAGMENT_SHADER, frag );
    glLinkProgram( prog );
    CheckStatus( prog, false );
    glUseProgram( prog );

    bool running = true;
    while( running )
    {
        SDL_Event ev;
        while( SDL_PollEvent( &ev ) )
        {
            if( ev.type == SDL_QUIT )
            {
                running = false;
            }
        }

        glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
        glClear( GL_COLOR_BUFFER_BIT );
        glDrawArrays( GL_POINTS, 0, 1 );
        SDL_GL_SwapWindow( window );
    }

    SDL_GL_DeleteContext( context ); 
    SDL_DestroyWindow( window );
    SDL_Quit();
    return EXIT_SUCCESS;
}

Я думаю, что вы забыли инициализировать контекст opengles2.

SDL_Init(SDL_INIT_VIDEO);

SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);

SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
Другие вопросы по тегам