【问题标题】:Why won't CG shaders work with GL 3.2?为什么 CG 着色器不能与 GL 3.2 一起使用?
【发布时间】:2012-12-26 08:38:22
【问题描述】:

我已尽一切努力让 OpenGL 3.2 在我的游戏引擎中使用 CG 着色器进行渲染,但我没有运气。所以我决定做一个简单的最小项目,但着色器仍然无法工作。理论上,我的测试项目应该只渲染一个红色三角形,但它是白色的,因为着色器没有做任何事情。

我会把代码贴在这里:

#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;
}

我做错了什么?

【问题讨论】:

  • 对于我所知道的 CG = Nvidia 着色器。 OpenGL 也支持 GLSL 作为着色语言而不是 CG。
  • @user1797612 CG 可以与 OpenGL 和 Direct3D 一起使用。

标签: opengl sdl nvidia glew cg-toolkit


【解决方案1】:

我编译了代码并得到了相同的结果。所以我添加了CG error handler 以获得更多信息:

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

cgSetPassStatecgResetPassState 被调用时,我收到以下错误消息:

技术未通过验证。

当然,信息量不是很大。所以我使用GLIntercept 将所有 OpenGL 调用跟踪到一个日志文件。

这一次,当glewInit 被调用时,我在日志文件中收到以下错误消息:

glGetString(GL_EXTENSIONS)=NULL glGetError() = GL_INVALID_ENUM

根据 OpenGL 文档,不得使用 GL_EXTENSIONS 调用 glGetString,在 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 不兼容。

经过一番互联网挖掘,我发现您可以使用 SDL 创建这种兼容的 OpenGL 上下文,只需在代码中添加这一行:

SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY);

恕我直言,CG Toolkit 需要这种类型的兼容性配置文件。

【讨论】:

  • 我不想创建兼容性配置文件。我已经知道我能做到。我用 GL3 头试了一下,还是不行。我不认为问题出在 GL_EXTENSIONS 但听起来你可能正在处理“技术未通过验证”的问题。我需要一个使用纯核心配置文件的解决方案。
  • @SteveDeFacto 对我来说,出现“技术未通过验证”错误是因为 GLEW 库失败,然后 glCreateProgram, glCreateShader, ... 永远不会被调用。您可以使用cgIsTechniqueValidated 函数对其进行测试。要使用核心配置文件,我需要下载 GLEW 源代码,应用补丁并再次测试。顺便问一下,您是否尝试过 GLIntercept 或类似的?
  • 试试这个而不是 glew:opengl.org/registry/api/gl3.h 它是为 OpenGL 核心配置文件制作的,但仍然不起作用。
  • @SteveDeFacto 我已经测试了 gl3.h(以及最近的 glcorearb.h)来得到同样的错误,但是这次来自 CG,而不是来自 GLEW。恕我直言,CG Toolkit 需要这种类型的兼容性配置文件才能工作。我已经更新了答案。
  • @SteveDeFacto:“为什么需要兼容性配置文件?”因为 NVIDIA 讨厌 核心配置文件。他们直言不讳地反对从 OpenGL 中删除东西的想法,并告诉他们 SDK 中的人们使用兼容性配置文件。这样的公司极不可能做出任何努力来确保其外部 Cg 编译器核心配置文件的安全。
【解决方案2】:

“Cg 3.1 上下文还不支持向前兼容的 OpenGL 上下文!”

来源: http://3dgep.com/introduction-to-shader-programming-with-cg-3-1/

由于 Cg 项目似乎被放弃了,它也不太可能发生。

【讨论】:

    最近更新 更多