我正在开发一个使用 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/