我正在构建简单的“hello triangle”程序,从OpenGL-ES 2.0开发开始,我遇到了这个棘手的错误。它显示我无法链接着色器。我在RenderMonkey上测试了着色器编译,没关系。但在我的实际应用中,它无法链接。
void COpenGLWidget::initializeGL()
{
const size_t nMaxLength = 255;
glClearColor(1.0f, 0.0f, 0.0, 1.0f);
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
char lpszVertexBuffer[][nMaxLength] =
{
"uniform mat4 g_MatViewProjection;\n",
"attribute vec4 rm_Vertex;\n",
"void main(void)\n",
"{\n",
"gl_Position = rm_Vertex;\n",
"}"
};
char lpszFragmentBuffer[][nMaxLength] =
{
"precision mediump float; \n",
"void main(void)\n",
"{\n",
"gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0 );\n",
"}\n"
};
m_nVertexShader = glCreateShader(GL_VERTEX_SHADER);
m_nPixelShader = glCreateShader(GL_FRAGMENT_SHADER);
int iVertexShaderLength = 6;
int iPixelShaderLength = 5;
glShaderSource(m_nVertexShader, 1, (const char**)lpszVertexBuffer, &iVertexShaderLength);
glShaderSource(m_nPixelShader, 1, (const char**)lpszFragmentBuffer, &iPixelShaderLength);
glCompileShader(m_nVertexShader);
int iIsOk = 0;
glGetShaderiv(m_nVertexShader, GL_COMPILE_STATUS, &iIsOk);
if(!iIsOk)
{
GLint infoLen = 0;
glGetShaderiv(m_nVertexShader, GL_INFO_LOG_LENGTH, &infoLen);
if(infoLen > 1)
{
char* infoLog = (char*)malloc(sizeof(char) * infoLen);
glGetShaderInfoLog(m_nVertexShader, infoLen, NULL, infoLog);
QMessageBox::warning(this, QString("Error"),
QString(infoLog), QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Yes);
free(infoLog);
}
glDeleteShader(m_nVertexShader);
return;
}
glCompileShader(m_nPixelShader);
glGetShaderiv(m_nPixelShader, GL_COMPILE_STATUS, &iIsOk);
if(!iIsOk)
{
GLint infoLen = 0;
glGetShaderiv(m_nPixelShader, GL_INFO_LOG_LENGTH, &infoLen);
if(infoLen > 1)
{
char* infoLog = (char*)malloc(sizeof(char) * infoLen);
glGetShaderInfoLog(m_nPixelShader, infoLen, NULL, infoLog);
QMessageBox::warning(this, QString("Error"),
QString(infoLog), QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Yes);
free(infoLog);
}
glDeleteShader(m_nPixelShader);
return;
}
m_nProgram = glCreateProgram();
glAttachShader(m_nProgram, m_nVertexShader);
glAttachShader(m_nProgram, m_nPixelShader);
glBindAttribLocation(m_nProgram, 0, "rm_Vertex");
glLinkProgram(m_nProgram);
glGetProgramiv(m_nProgram, GL_LINK_STATUS, &iIsOk);
// Fail to pass status validation
if(!iIsOk)
{
GLint infoLen = 0;
glGetProgramiv(m_nProgram, GL_INFO_LOG_LENGTH, &infoLen);
if(infoLen > 1)
{
char* infoLog = (char*)malloc(sizeof(char) * infoLen);
glGetProgramInfoLog(m_nProgram, infoLen, NULL, infoLog);
QMessageBox::warning(this, QString("Error"),
QString(infoLog), QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Yes);
free(infoLog);
}
glDeleteProgram(m_nProgram);
return;
}
glUseProgram(m_nProgram);
connect(&m_Timer, SIGNAL(timeout()), this, SLOT(update()));
m_Timer.start(1);
}
答案 0 :(得分:1)
您的着色器源代码的数据结构完全错误。 glShaderSource
接受指针数组到char*
,因此是一系列字符串。您将着色器源代码存储在二维数组char
中。与一个常见的神话相反,数组不是C / C ++中的指针。
此外,您告诉GL有一个单行,长度为6 个字符(分别为片段着色器为5)。着色器编译器只能看到源代码的第一部分,因此报告它找不到main
函数。
目前还不清楚为什么你甚至试图将着色器源分成几个字符串。这样做并没有任何好处,因为你没有重新组合不同的点点滴滴。我建议你只使用单个字符串,所以行
const char *source=
"uniform mat4 g_MatViewProjection;\n"
"attribute vec4 rm_Vertex;\n"
"void main(void)\n"
"{\n"
"gl_Position = rm_Vertex;\n"
"}";
在C / C ++中,你可以通过简单地将它们相互连接来连接字符串,这也适用于各行。
然后,您只需使用source
指针的地址并将其输入GL:
glShaderSource(shaderName, 1, &source, NULL);
也没有必要预先计算任何长度,GL也会处理0终止的C字符串。
如果您真的想要使用不同源字符串的路径,我强烈建议您首先学习数组,指针,指针数组和多维数组的基础知识。