Почему шейдеры компьютерной графики не работают с GL 3.2?

Я пробовал все, чтобы OpenGL 3.2 отображался с шейдерами компьютерной графики в моем игровом движке, но мне не повезло. Поэтому я решил сделать голый минимальный проект, но шейдеры все равно не будут работать. Теоретически мой тестовый проект должен просто отображать красный треугольник, но он белый, потому что шейдер ничего не делает.

Выложу код сюда:

#include <stdio.h>
#include <stdlib.h>
#include <vector>
#include <string>
#include <GL/glew.h>
#include <Cg/cg.h>
#include <Cg/cgGL.h>
#include <SDL2/SDL.h>

int main()
{
    SDL_Window *mainwindow;
    SDL_GLContext maincontext;

    SDL_Init(SDL_INIT_VIDEO);

    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
    SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);

    mainwindow = SDL_CreateWindow("Test", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 512, 512, SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN);

    maincontext = SDL_GL_CreateContext(mainwindow);

    glewExperimental = GL_TRUE;
    glewInit();

    _CGcontext* cgcontext;
    cgcontext = cgCreateContext();
    cgGLRegisterStates(cgcontext);

    CGerror error;
    CGeffect effect;
    const char* string;
    std::string shader;

    shader =
            "struct VS_INPUT"
            "{"
            "   float3 pos              : ATTR0;"
            "};"

            "struct FS_INPUT"
            "{"
            "   float4 pos                  : POSITION;"
            "   float2 tex                  : TEXCOORD0;"
            "};"

            "struct FS_OUTPUT"
            "{"
            "   float4 color                : COLOR;"
            "};"

            "FS_INPUT VS( VS_INPUT In )"
            "{"
            "   FS_INPUT Out;"
            "   Out.pos = float4( In.pos, 1.0f );"
            "   Out.tex = float2( 0.0f, 0.0f );"
            "   return Out;"
            "}"

            "FS_OUTPUT FS( FS_INPUT In )"
            "{"
            "   FS_OUTPUT Out;"
            "   Out.color = float4(1.0f, 0.0f, 0.0f, 1.0f);"
            "   return Out;"
            "}"

            "technique t0"
            "{"
            "   pass p0"
            "   {"
            "      VertexProgram = compile gp4vp VS();"
            "      FragmentProgram = compile gp4fp FS();"
            "   }"
            "}";

    effect = cgCreateEffect(cgcontext, shader.c_str(), NULL);
    error = cgGetError();
    if(error)
    {
        string = cgGetLastListing(cgcontext);
        fprintf(stderr, "Shader compiler: %s\n", string);
    }

    glClearColor ( 0.0, 0.0, 1.0, 1.0 );
    glClear ( GL_COLOR_BUFFER_BIT );

    float* vert = new float[9];

    vert[0] = 0.0; vert[1] = 0.5; vert[2] =-1.0;
    vert[3] =-1.0; vert[4] =-0.5; vert[5] =-1.0;
    vert[6] = 1.0; vert[7] =-0.5; vert[8]= -1.0;

    unsigned int m_vaoID;
    unsigned int m_vboID;

    glGenVertexArrays(1, &m_vaoID);
    glBindVertexArray(m_vaoID);

    glGenBuffers(1, &m_vboID);

    glBindBuffer(GL_ARRAY_BUFFER, m_vboID);
    glBufferData(GL_ARRAY_BUFFER, 9 * sizeof(GLfloat), vert, GL_STATIC_DRAW);

    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
    glEnableVertexAttribArray(0);

    CGtechnique tech = cgGetFirstTechnique( effect );
    CGpass pass = cgGetFirstPass(tech);
    while (pass)
    {
        cgSetPassState(pass);
        glDrawArrays(GL_TRIANGLES, 0, 3);
        cgResetPassState(pass);
        pass = cgGetNextPass(pass);
    }

    glDisableVertexAttribArray( 0 );

    glBindVertexArray(0);

    delete[] vert;

    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glDeleteBuffers(1, &m_vboID);
    glDeleteVertexArrays(1, &m_vaoID);

    SDL_GL_SwapWindow(mainwindow);
    SDL_Delay(2000);

    SDL_GL_DeleteContext(maincontext);
    SDL_DestroyWindow(mainwindow);
    SDL_Quit();

    return 0;
}

Что я делаю неправильно?


person SteveDeFacto    schedule 26.12.2012    source источник
comment
для того, что я знаю, CG = шейдеры Nvidia. Также OpenGL поддерживает GLSL как язык затенения, а не CG.   -  person user1797612    schedule 26.12.2012
comment
@ user1797612 CG можно использовать как с OpenGL, так и с Direct3D.   -  person Michael IV    schedule 26.12.2012


Ответы (2)


Я скомпилировал код и получил тот же результат. Поэтому я добавил обработчик ошибок CG, чтобы получить немного больше информации:

void errorHandler(CGcontext context, CGerror error, void * appdata) {
    fprintf(stderr, "%s\n", cgGetErrorString(error));
}
...
cgSetErrorHandler(&errorHandler, NULL);

Когда были вызваны cgSetPassState и cgResetPassState, я получил следующее сообщение об ошибке:

Техника не прошла валидацию.

Не очень информативно, конечно. Поэтому я использовал GLIntercept для отслеживания всех вызовов OpenGL в файл журнала.

На этот раз, когда был вызван glewInit, я получил следующее сообщение об ошибке в файле журнала:

glGetString(GL_EXTENSIONS)=NULL glGetError() = GL_INVALID_ENUM

Согласно документации OpenGL, glGetString нельзя вызывать с GL_EXTENSIONS, он устарел в версии 3.0 и glGetStringi вместо этого следует использовать.

Наконец, я нашел проблему в библиотеке GLEW: http://sourceforge.net/p/glew/bugs/120/

Я удалил зависимость от GLEW и протестировал gl3.h (и более поздние glcorearb.h). Я получил ту же ошибку, но на этот раз, когда был вызван cgGLRegisterStates.

Я также попробовал использовать CG trace.dll, чтобы получить ту же ошибку (7939 = 0x1F03 = GL_EXTENSIONS):

glGetString
  {
  input:
    name = 7939
  output:
    return = NULL
  }

Затем я протестировал OpenGL 3.1 (SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);) и обнаружил, что он работает нормально:

glGetString(GL_EXTENSIONS)="GL_AMD_multi_draw_indirec..."

То есть контекст 3.1 был совместим с предыдущими версиями OpenGL, а 3.2 — нет.

Немного покопавшись в Интернете, я обнаружил, что вы можете создать этот тип совместимого контекста OpenGL с SDL, просто добавив эту строку в код:

SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY);

ИМХО, CG Toolkit нуждается в таком профиле совместимости.

person Juan Mellado    schedule 28.12.2012
comment
Я не хочу создавать профиль совместимости. Я уже знал, что могу это сделать. Пробовал с заголовком GL3, все равно не работает. Я не думаю, что проблема в GL_EXTENSIONS, но похоже, что вы, возможно, что-то знаете о методе, который не прошел проверку. Мне нужно решение, использующее чистый профиль ядра. - person SteveDeFacto; 29.12.2012
comment
@SteveDeFacto Для меня ошибка «Техника не прошла проверку» появляется из-за сбоя библиотеки GLEW, а затем glCreateProgram, glCreateShader, ... никогда не вызываются. Вы можете проверить это с помощью функции cgIsTechniqueValidated. Чтобы использовать основной профиль, мне нужно загрузить исходный код GLEW, применить исправление и снова протестировать. Кстати, вы пробовали GLIntercept или что-то подобное? - person Juan Mellado; 29.12.2012
comment
Попробуйте это вместо glew: opengl.org/registry/api/gl3.h Он был сделан для основного профиля OpenGL и до сих пор не работает. - person SteveDeFacto; 29.12.2012
comment
@SteveDeFacto Я протестировал gl3.h (и более поздний glcorearb.h), чтобы получить ту же ошибку, но на этот раз от CG, а не от GLEW. ИМХО, для работы CG Toolkit нужен профиль совместимости такого типа. Я обновил ответ. - person Juan Mellado; 29.12.2012
comment
Где вы прочитали, что для CG нужен профиль совместимости? CG может компилироваться до версии шейдера 5. Зачем ему профиль совместимости? - person SteveDeFacto; 30.12.2012
comment
@SteveDeFacto Я сказал ИМХО, [я думаю, что] ..., я не читал это ..., вот ссылка. Во всяком случае, я не нашел никакой ссылки на glGetStringi внутри cgGL.dll, и все официальные примеры CG, похоже, используют профиль совместимости от перенасыщения. Взгляните на слайд номер 97 этой разговорной конференции NVIDIA. - person Juan Mellado; 30.12.2012
comment
@SteveDeFacto: Зачем ему нужен профиль совместимости? Потому что NVIDIA ненавидит профиль ядра. Они были откровенны против идеи удаления чего-либо из OpenGL и говорят людям в своем SDK использовать профиль совместимости. Маловероятно, что такая компания приложит какие-либо усилия для обеспечения безопасности своего внешнего профиля ядра Cg-компилятора. - person Nicol Bolas; 31.12.2012
comment
Мне трудно поверить, что CG нигде в Интернете не требует профиля совместимости. Можно было бы подумать, что по крайней мере несколько человек пожаловались бы на мою проблему. Это больше похоже на дикую догадку, основанную на небольшом количестве доказательств. Если кто-нибудь сможет найти официальное заявление или хотя бы несколько сообщений на форуме, жалующихся на эту проблему, я буду считать профиль совместимости решением. А пока я надеюсь, что Хуан ошибается. - person SteveDeFacto; 31.12.2012
comment
Я пытался найти вариант компилятора для cgc, чтобы компилировать шейдеры, которые работают с основным профилем OpenGL 3.2, но мне не повезло. На данный момент, даже если Nvidia CG может работать с основным профилем, это не так, потому что недостаточно документации, чтобы кто-нибудь знал, как это сделать. Я просто собираюсь вознаградить Хуана этой наградой за то, что он пытался найти ответ. - person SteveDeFacto; 01.01.2013

«Контекст Cg 3.1 еще не поддерживает прямо совместимые контексты OpenGL!»

Источник: http://3dgep.com/introduction-to-shader-programming-with-cg-3-1/

Поскольку проект Cg кажется заброшенным, это также маловероятно.

person darklon    schedule 23.10.2014