运行时glsl着色器编译问题

时间:2011-11-06 00:41:02

标签: c++ windows opengl glsl

我正在开发一个使用OpenGL 4.0着色器的项目。

我必须向glShaderSource()调用一个char数组数组,它​​代表着色器的来源。

着色器编译失败,出现以下错误:

(0) : error C0206: invalid token "<null atom>" in version line
(0) : error C0000: syntax error, unexpected $end at token "<EOF>"

这是我的(hello world)着色器 - 直接来自OpenGL 4.0着色语言食谱

#version 400

in  vec3        VertexPosition;
in  vec3        VertexColor;
out vec3        Color;

void main()
{
    Color       = VertexColor;
    gl_Position = vec4( VertexColor, 1.0 );
}

这是我的代码,用于将着色器文件读入我的C ++代码,并在运行时编译着色器:

const int       nMaxLineSize    = 1024;
char            sLineBuffer[nMaxLineSize];
ifstream        stream;
vector<string>  vsLines;
GLchar**        ppSrc;
GLint*          pnSrcLineLen;
int             nNumLines;


stream.open( m_sShaderFile.c_str(), std::ios::in );

while( (stream.good()) && (stream.getline(sLineBuffer, nMaxLineSize)) )
{
    if( strlen(sLineBuffer) > 0 )
        vsLines.push_back( string(sLineBuffer) );
}

stream.close();


nNumLines       = vsLines.size();
pnSrcLineLen    = new GLint[nNumLines];
ppSrc           = new GLchar*[nNumLines];

for( int n = 0; n < nNumLines; n ++ )
{
    string &    sLine       = vsLines.at(n);
    int         nLineLen    = sLine.length();
    char *      pNext       = new char[nLineLen+1];

    memcpy( (void*)pNext, sLine.c_str(), nLineLen );                
    pNext[nLineLen] = '\0'; 

    ppSrc[n]        = pNext;
    pnSrcLineLen[n] = nLineLen+1;
}
vsLines.clear();

// just for debugging purposes (lines print out just fine..)
for( int n = 0; n < nNumLines; n ++ )           
    ATLTRACE( "line %d: %s\r\n", n, ppSrc[n] );

// Create the shader
m_nShaderId = glCreateShader( m_nShaderType );

// Compile the shader
glShaderSource( m_nShaderId, nNumLines, (const GLchar**)ppSrc, (GLint*) pnSrcLineLen );
glCompileShader( m_nShaderId );

// Determine compile status
GLint nResult = GL_FALSE;
glGetShaderiv( m_nShaderId, GL_COMPILE_STATUS, &nResult );

C ++代码按预期执行,但着色器编译失败。谁能发现我可能做错了什么?

我有一种感觉,这可能与某些行尾字符有关,但由于这是我第一次尝试着色器编译,我被卡住了!

我已经在着色器编译中阅读了其他SO答案,但它们似乎特定于Java /其他语言,而不是C ++。如果它有帮助,我就在win32平台上。

3 个答案:

答案 0 :(得分:15)

你犯了别人犯过的错误。这是glShaderSource

的定义
void glShaderSource(GLuint shader,  GLsizei count,  const GLchar **string,  const GLint *length);

string是一个字符串数组。 旨在成为着色器中行的数组。编译器解释这个字符串数组的方式是将它们连接在一起。没有换行符。

由于stream.getline\n字符放入字符串中,因此您生成的每个着色器字符串最后都不会有换行符。因此,当glShaderSource编译它们时,您的着色器将如下所示:

#version 400in  vec3        VertexPosition;in  vec3        VertexColor;out vec3        Color;...

那不是合法的GLSL。

执行此操作的正确方法是将文件作为字符串加载。

std::ifstream shaderFile(m_sShaderFile.c_str());
if(!shaderFile)
  //Error out here.
std::stringstream shaderData;
shaderData << shaderFile.rdbuf();  //Loads the entire string into a string stream.
shaderFile.close();
const std::string &shaderString = shaderData.str(); //Get the string stream as a std::string.

然后你可以轻松地将它传递给glShaderSource

m_nShaderId = glCreateShader( m_nShaderType );
const char *strShaderVar = shaderString.c_str();
GLint iShaderLen = shaderString.size();
glShaderSource( m_nShaderId, 1, (const GLchar**)&strShaderVar, (GLint*)&iShaderLen );
glCompileShader( m_nShaderId );

如果您从某处复制了此加载代码,我强烈建议您找到different place to learn about OpenGL。因为这是可怕的编码。

答案 1 :(得分:3)

  

glShaderSource(m_nShaderId,nNumLines,(const GLchar **)ppSrc,(GLint *)pnSrcLineLen);

我知道glShaderSource的签名看起来很容易分别发送着色器的每一行。但现在这就是它的意义所在。能够发送的点是多个阵列,以便可以将多个原始着色器源混合到单个着色器中,类似于包含文件。理解这一点,使得在着色器文件中读取更加简单 - 并避免这种令人讨厌的错误。

使用C ++可以做得更好更清洁。我已经在Getting garbage chars when reading GLSL files

中写了下面的内容

你正在使用C ++,所以我建议你利用它。我建议您读入std :: string:

,而不是读入自我分配的char数组
#include <string>
#include <fstream>

std::string loadFileToString(char const * const fname)
{
    std::ifstream ifile(fname);
    std::string filetext;

    while( ifile.good() ) {
        std::string line;
        std::getline(ifile, line);
        filetext.append(line + "\n");
    }

    return filetext;
}

自动处理所有内存分配和正确分隔 - 关键字是RAII:资源分配是初始化。稍后您可以使用类似

的内容上传着色器源
void glcppShaderSource(GLuint shader, std::string const &shader_string)
{
    GLchar const *shader_source = shader_string.c_str();
    GLint const shader_length = shader_string.size();

    glShaderSource(shader, 1, &shader_source, &shader_length);
}

您可以像这样使用这两个功能:

void load_shader(GLuint shaderobject, char * const shadersourcefilename)
{
    glcppShaderSource(shaderobject, loadFileToString(shadersourcefilename));
}

答案 2 :(得分:1)

快点预感:

您是否尝试使用NULL作为长度参数调用glShaderSource?在这种情况下,OpenGL将假设您的代码为空终止。

(由于愚蠢而编辑)