OpenGL glUniform1f无法更新顶点着色器

时间:2018-09-26 04:36:21

标签: c opengl glsl vertex-shader

所有教程似乎都表明我在做正确的事情,顶点着色器正常工作,但是它无法通过使用glUniform1f函数来识别主程序中的任何输入更改。我在每行之后检查glGetError,没有错误。我检查了glGetShaderivglGetShaderInfoLog,没有问题。我正在测试SDL报告的OpenGL 2.1版(未知配置文件,但假设使用核心配置文件)。

#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_LoadLibrarySDL_GL_GetProcAddress,我只是在文件顶部手动定义方法签名,并通过链接器导入GL 。我不希望这是一个问题,但我知道,这是唯一一个我尚未调查的问题,它可能会导致我的问题。

2 个答案:

答案 0 :(得分:0)

gl_Position期望剪贴空间坐标,该坐标是大小为[2w,2w,2w,w]的hiper-cube。
对于vec4(x, y, z, w),如果[x,y,z]中的任何一个不在[-w,w]范围内,则顶点将被裁剪。
坐标将由GPU自动转换为片段着色器之前的 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。仅01被传递到GPU。使用当前的顶点数据,只能绘制两对三角形。

第二个问题是frame是值0 <= frame < 100。因此,如果您通过frame而不是frame%2,则对于大多数值aPos.x + i/2都将位于Clip空间之外,并且您只会看到前两个三角形对或其中的一部分。

答案 1 :(得分:0)

因此,您可以这样声明函数:

void glUniform1f();

通过省略任何参数,编译器将假定所有参数的类型均为int。对于大多数其他GL函数,这是偶然的,因为无论如何,这些参数在大多数情况下都是整数类型,但是对于glUniform1f,这意味着将函数参数转换为,但由于该函数GLfloat的实际原型是类似的,因此该函数将该位模式隐式地重新解释glUniform1f

void glUniform1f(int location, GLfloat value);
  

请注意,我不熟悉OpenGL的扩展功能加载问题和例程,例如SDL的SDL_GL_LoadLibrarySDL_GL_GetProcAddress,我只是在文件顶部手动定义方法签名,并通过链接器导入GL

您不应该这样做。您尝试访问的GL函数甚至可能根本没有被库导出。如果您不想手动处理每个函数指针的加载,则可以使用现有的OpenGL loaders之一。