OpenGL glUniform1f не обновляет вершинный шейдер - PullRequest
0 голосов
/ 26 сентября 2018

Кажется, что все уроки указывают на то, что я все делаю правильно, вершинный шейдер работает, однако он не может распознать любые входные изменения из основной программы с помощью функции glUniform1f.Я проверяю glGetError после каждой строки, ошибок нет.Я проверяю glGetShaderiv и glGetShaderInfoLog, проблем нет.Я тестирую с OpenGL версии 2.1 (неизвестный профиль, но предполагающий профиль ядра), как сообщает SDL.

#if defined(__WINDOWS__) || defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(__TOS_WIN__)\
    || defined(__CYGWIN__)
    /* Compiling for Windows */
    #ifndef __WINDOWS__
        #define __WINDOWS__
    #endif
    #include <windows.h>
#endif/* Predefined Windows macros */

#include <SDL2/SDL.h>
#include <GL/GL.h>
#include <stdlib.h>
#include <stdio.h>
#include <error.h>

//return type not verified
void glGenBuffers();
void glBindBuffer();
void glBufferData();
unsigned int glCreateShader();
void glShaderSource();
void glCompileShader();
void glGetShaderiv();
void glGetShaderInfoLog();
unsigned int glCreateProgram();
void glAttachShader();
void glLinkProgram();
void glGetProgramiv();
void glGetProgramInfoLog();
void glVertexAttribPointer();
void glEnableVertexAttribArray();
void glUseProgram();
void glDeleteShader();
void glGenVertexArrays();
void glBindVertexArray();
GLint glGetUniformLocation();
void glUniform1f();
void glDeleteProgram();
void glDeleteBuffers();

int fixSDLconsole() {
    FILE *console = freopen("stdout.txt", "a",stdout);
    if (console == NULL) {return errno;}
    console = freopen("stdout.txt", "a",stderr);
    if (console == NULL) {return errno;}
    return 0;
}
void printGLVersionNumber() {
    int majorVersion;
    int minorVersion;
    int profile;
    SDL_GL_GetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, &majorVersion);
    SDL_GL_GetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, &minorVersion);
    SDL_GL_GetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, &profile);
    fprintf(stderr,"GL version %d.%d ",majorVersion,minorVersion);
    switch (profile) {
        case SDL_GL_CONTEXT_PROFILE_CORE: fprintf(stderr,"core (%d)\n",profile);break;
        case SDL_GL_CONTEXT_PROFILE_COMPATIBILITY: fprintf(stderr,"compatibility (%d)\n",profile);break;
        case SDL_GL_CONTEXT_PROFILE_ES: fprintf(stderr,"E.S. (%d)\n",profile);break;
        default: fprintf(stderr, "unknown profile: %d\n",profile);break;
    }
    return;
}
#define checkGlError(label) {int error = glGetError();if (error != GL_NO_ERROR) {error_at_line(0,0,__FILE__,__LINE__,"error=%d", error);goto label;}}
int main(int argc, char **argv) {
    SDL_Window *window = NULL;
    SDL_GLContext context = NULL;
    GLuint verticesGlIds[] = {0,0};
    GLuint vertexShaderGlId = 0;
    GLuint shaderProgramGlId = 0;
    if (fixSDLconsole()) {
        return errno;
    }
    if (SDL_Init(SDL_INIT_VIDEO) != 0) {
        error_at_line(1,0,__FILE__,__LINE__,"Unable to initialize SDL: %s",SDL_GetError());
        goto error;
    }
    printGLVersionNumber();

    window = SDL_CreateWindow("Window Title",SDL_WINDOWPOS_UNDEFINED,SDL_WINDOWPOS_UNDEFINED,640,640,SDL_WINDOW_OPENGL);
    if (window == NULL) {
        error_at_line(0,0,__FILE__,__LINE__,"Could not create window: %s", SDL_GetError());
        goto error;
    }
    context = SDL_GL_CreateContext(window);
    if (context == NULL) {
        error_at_line(0,0,__FILE__,__LINE__,"Could not create OpenGL context: %s", SDL_GetError());
        goto error;
    }

    glViewport(0,0,640,640);checkGlError(error);
    glClearColor(.9f,.9f,.9f,1.f);checkGlError(error);
    glEnableClientState(GL_VERTEX_ARRAY);checkGlError(error);
    glEnableClientState(GL_COLOR_ARRAY);checkGlError(error);

    float vertices[] = {
        -.5f,0.f,0.f,
        0.f,.5f,0.f,
        0.f,-.5f,0.f,
        0.f,.5f,0.f,
        .5f,.5f,0.f,
        0.f,0.f,0.f
    };
    float colors[] = {
        1.f,0.f,0.f,//red
        .5f,0.f,0.f,//red
        0.f,1.f,0.f,//green
        0.f,.5f,0.f,//green
        0.f,0.f,1.f,//blue
        0.f,0.f,.5f//blue
    };
    glGenBuffers(2, &verticesGlIds);checkGlError(error);

    glBindBuffer(GL_ARRAY_BUFFER, verticesGlIds[0]);checkGlError(error);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);checkGlError(error);

    glBindBuffer(GL_ARRAY_BUFFER, verticesGlIds[1]);checkGlError(error);
    glBufferData(GL_ARRAY_BUFFER,sizeof(colors),colors, GL_STATIC_DRAW);checkGlError(error);

    char *vertexShader =
        "#version 120\n"\
        "attribute vec3 aPos;\n"\
        "uniform float i;\n"\
        "void main() {\n"\
        "gl_FrontColor=gl_Color;\n"\
        "gl_Position = vec4(aPos.x+i/2,aPos.y,aPos.z,1.0);\n"\
        "}\n";
    vertexShaderGlId = glCreateShader(GL_VERTEX_SHADER);checkGlError(error);
    if (vertexShaderGlId == 0) {error_at_line(0,0,__FILE__,__LINE__,"vertex shader could not be created");goto error;}
    glShaderSource(vertexShaderGlId, 1, &vertexShader, NULL);checkGlError(error);
    glCompileShader(vertexShaderGlId);checkGlError(error);
    {
        GLint success;
        glGetShaderiv(vertexShaderGlId, GL_COMPILE_STATUS, &success);checkGlError(error);
        if (success == GL_FALSE) {
            char infoLog[512];
            glGetShaderInfoLog(vertexShaderGlId, 512, NULL, infoLog);checkGlError(error);
            error_at_line(0,0,__FILE__,__LINE__,"Vertex Shader problem: %s", infoLog);
            goto error;
        }
    }

    shaderProgramGlId = glCreateProgram();checkGlError(error);
    if (shaderProgramGlId == 0) {error_at_line(0,0,__FILE__,__LINE__,"shader program could not be created");goto error;}
    glAttachShader(shaderProgramGlId, vertexShaderGlId);checkGlError(error);
    glLinkProgram(shaderProgramGlId);checkGlError(error);
    {
        int success;
        glGetProgramiv(shaderProgramGlId, GL_LINK_STATUS, &success);checkGlError(error);
        if (!success) {
            char infoLog[512];
            glGetProgramInfoLog(shaderProgramGlId, 512, NULL, infoLog);checkGlError(error);
            error_at_line(0,0,__FILE__,__LINE__,"Shader program problem: %s", infoLog);
        }
    }

    glDeleteShader(vertexShaderGlId);checkGlError(error);

    GLint iLocation = glGetUniformLocation(shaderProgramGlId, "i");checkGlError(error);
    if (iLocation == -1) {error_at_line(0,0,__FILE__,__LINE__,"uniform i not found in shader");goto error;}
    error_at_line(0,0,__FILE__,__LINE__,"iLocation: %d", iLocation);

    for (int frame = 0; frame < 100; ++frame) {
        glClear(GL_COLOR_BUFFER_BIT);checkGlError(error);
        glUseProgram(shaderProgramGlId);checkGlError(error);

        glBindBuffer(GL_ARRAY_BUFFER, verticesGlIds[0]);    checkGlError(error);
        glVertexPointer(3,GL_FLOAT,0,0);    checkGlError(error);
        glBindBuffer(GL_ARRAY_BUFFER, verticesGlIds[1]);    checkGlError(error);
        glColorPointer(3,GL_FLOAT,0,0); checkGlError(error);
        glUniform1f(iLocation, (float) (frame%2));  checkGlError(error);
        glDrawArrays(GL_TRIANGLES, 0,sizeof(vertices)/sizeof(float)/3); checkGlError(error);
        glBindBuffer(GL_ARRAY_BUFFER, 0);   checkGlError(error);
        SDL_GL_SwapWindow(window);
        SDL_Delay(100);
    }
    glDeleteProgram(shaderProgramGlId);
    glDeleteShader(vertexShaderGlId);
    glDeleteBuffers(sizeof(verticesGlIds)/sizeof(GLuint), verticesGlIds);
    SDL_GL_DeleteContext(context);
    SDL_Delay(3000);
    SDL_DestroyWindow(window);
    SDL_Quit();
    return EXIT_SUCCESS;
    error:
    glDeleteProgram(shaderProgramGlId);
    glDeleteShader(vertexShaderGlId);
    glDeleteBuffers(sizeof(verticesGlIds)/sizeof(GLuint), verticesGlIds);
    if (context != NULL) SDL_GL_DeleteContext(context);
    if (window != NULL) SDL_DestroyWindow(window);
    SDL_Quit();
    return EXIT_FAILURE;
}
#if defined(__WINDOWS__)
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) {
    char *argv[1] = {(char *) 0};
    return main(0, argv);
}
#endif

обратите внимание, что я не знаком с проблемами загрузки функций OpenGL и процедурами, такими как SDL SDL_GL_LoadLibrary и SDL_GL_GetProcAddress Я просто вручную определяю сигнатуры методов в верхней части файла и импортирую GL через компоновщик.Я не ожидаю, что это будет проблемой, но я знаю, что это единственная проблема, которую я не изучал, которая может вызывать мои проблемы.

Ответы [ 2 ]

0 голосов
/ 05 октября 2018

Итак, вы объявляете функцию следующим образом:

void glUniform1f();

Опуская любые параметры, компилятор будет считать, что все аргументы имеют тип int.Для большинства других функций GL это работает случайно, поскольку в большинстве случаев эти аргументы являются просто целочисленными типами, но для glUniform1f это будет означать, что аргумент функции преобразуется в целое число, но в результатебитовый шаблон неявно повторно интерпретируется как GLfloat функцией, поскольку фактический прототип для glUniform1f выглядит примерно так

void glUniform1f(int location, GLfloat value);

обратите внимание, что я не являюсьзнакомы с проблемами и функциями загрузки функций расширения OpenGL, такими как SDL SDL_GL_LoadLibrary и SDL_GL_GetProcAddress. Я просто вручную определяю сигнатуры методов в верхней части файла и импортирую GL через компоновщик.

Вы не должныне делай этого.Функции GL, к которым вы пытаетесь получить доступ, могут даже не быть экспортированы библиотекой вообще.Если вы не хотите вручную загружать каждый указатель на функцию, вы можете использовать один из существующих загрузчиков OpenGL .

0 голосов
/ 05 октября 2018

gl_Position ожидает координаты пространства-клипа координаты, которые представляют собой куб-хипер размером [2w, 2w, 2w, w].
Для vec4(x, y, z, w), если какой-либо из [x, y, z] находится за пределами диапазона [-w,w], вершина обрезается.
Координаты будут автоматически преобразованы графическим процессором в NDC-пробел x/w, y/w, z/w, 1 (он же "перспективное деление") перед фрагментным шейдером.

Ваш код GLSL gl_Position = vec4(aPos.x+i/2,aPos.y,aPos.z,1.0); используетуниформа i.
Вы обновляете его по glUniform1f(iLocation, (float) (frame%2));

Первый выпуск - frame%2.Только 0 или 1 передается в графический процессор.С вашими текущими данными о вершинах нужно нарисовать только две пары треугольников.

Вторая проблема заключается в том, что frame - это значение 0 <= frame < 100.Таким образом, если вы передадите frame вместо frame%2, то для большинства значений aPos.x + i/2 выйдет за пределы пространства Clip, и вы увидите только первые две пары треугольников или их части.

...