c++ - 运行时的 glsl 着色器编译问题

标签 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 平台上。

最佳答案

你犯了别人犯过的错误。这是 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 .因为那是糟糕的编码。

关于c++ - 运行时的 glsl 着色器编译问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8024433/

相关文章:

windows - 将 Redis DB docker 容器暴露给 NodeJS docker 容器

python - 如何使用 Python 从 Windows 操作系统中的窗口标题获取 PID?

c++ - OpenCV 从正方形 vector 中提取图像区域

c++ - 如何在 C++ 中编写单元测试?

c++ - 如何用 Boost::python 包装派生模板类?

c++ - 3D 空间中的 OpenGL 2D 文本 [C++/GLM] 矩阵乘法

opengl - OpenGL中的深度缓冲区

c++ - 陷入 while 循环 C++

c++ - Windows下是宽字符还是UTF-8?

c++ - OpenGL glGetIntegerv GL_MAX_VERTEX_ATTRIBS 分割错误