我正在尝试学习图形编程,我编写了一个简单的OpenGL程序,它绘制了一个三角形并且应该将其涂成红色,但是当我为片段着色器调用函数glShaderSource
时会导致段错误。
我不知道它为什么会导致段错误,因为spec page没有说明导致段错误的函数,并且任何关于着色器被加载到内存中的错误都不是它,因为顶点着色器以相同的方式加载,当我调用glGetShaderInfoLog
并打印日志时,它表示顶点着色器编译正常。
无论如何,我的代码加载着色器并链接着色程序......
int LoadShader(char* Filename, GLchar* ShaderSource) //dont call this function by itself as it doesnt free its own memory
{
FILE* z;
z = fopen(Filename, "rb");
if(z == NULL) {printf("Error: file \"%s\" does not exist...\n", Filename); return -1;}
unsigned long len = 0;
//get file length
fseek(z, 0, SEEK_END);
len = ftell(z);
rewind(z);
if(len == 0) {printf("Error reading file \"%s\"\n", Filename); return -1;}
ShaderSource = (char*)malloc((sizeof(char)) * len + 1); //allocate enough bytes for the file
if(ShaderSource == NULL) {puts("Memory Error"); return -1;}
size_t result = fread(ShaderSource, 1, len, z);
if( result != len)
{
puts("Reading Error");
free(ShaderSource);
ShaderSource = NULL;
return -1;
}
ShaderSource[len] = 0; //make it null terminated
puts(ShaderSource); //debbugging
fclose(z);
return 1;
}
//----------------------------------------------------------------------
GLuint MakeProgram(char* VSpath, char* FSpath){
GLuint VertexShaderID = glCreateShader(GL_VERTEX_SHADER);
GLuint FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);
GLchar* VSsource;
GLchar* FSsource;
if(!LoadShader(VSpath, VSsource))
return -1;
if(!LoadShader(FSpath, FSsource))
return -1;
GLint Result = GL_FALSE;
int InfoLogLength;
//compile shaders
const char* VS = VSsource; // glShaderSource needs a const char
glShaderSource(VertexShaderID, 1, &VS, NULL); //we use NULL for length becuase the source is null-terminated
glCompileShader(VertexShaderID);
//check
glGetShaderiv(VertexShaderID, GL_COMPILE_STATUS, &Result);
glGetShaderiv(VertexShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
char* VSerr;
VSerr = (char*)malloc(sizeof(char) * InfoLogLength);
glGetShaderInfoLog(VertexShaderID, InfoLogLength, NULL, &VSerr[0]);
printf("%s\n", VSerr);
free(VSerr);
VSerr = NULL;
//fragment shader
const char* FS = FSsource;
glShaderSource(FragmentShaderID, 1, &FS, NULL);
glCompileShader(FragmentShaderID);
//check
glGetShaderiv(FragmentShaderID, GL_COMPILE_STATUS, &Result);
glGetShaderiv(FragmentShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
char* FSerr;
FSerr = (char*)malloc(sizeof(char) * InfoLogLength);
glGetShaderInfoLog(FragmentShaderID, InfoLogLength, NULL, &FSerr[0]);
printf("%s\n", FSerr);
free(FSerr);
FSerr = NULL;
//link program
GLuint ProgramID = glCreateProgram();
glAttachShader(ProgramID, VertexShaderID);
glAttachShader(ProgramID, FragmentShaderID);
glLinkProgram(ProgramID);
//check program
glGetProgramiv(ProgramID, GL_LINK_STATUS, &Result);
glGetProgramiv(ProgramID, GL_INFO_LOG_LENGTH, &InfoLogLength);
char* err;
err = (char*)malloc(sizeof(char) * InfoLogLength);
glGetProgramInfoLog(ProgramID, InfoLogLength, NULL, &err[0]);
printf("%s\n", err);
free(err);
//free the shaders
free(VSsource);
VSsource = NULL;
free(FSsource);
FSsource = NULL;
glDeleteShader(VertexShaderID);
glDeleteShader(FragmentShaderID);
return ProgramID;
}
答案 0 :(得分:2)
仔细查看您对VSsource
(未初始化),FSsource
(未初始化)和LoadShader (...)
实施的实际声明。因为这是C并且您没有通过引用传递任何内容,所以对ShaderSource
函数内的LoadShader (...)
指针所做的任何更改都不会在函数外部传播。
简而言之,您错误地实施了LoadShader (...)
。你需要实际更改存储在传递它的指针中的地址(因为你在函数内部分配了这个内存),但你不能这样做,因为你当前传递的是GLchar*
。
至于为什么GL接受第一次拨打glShaderSource (...)
的未初始化指针,我不能说。也许你非常幸运?无论如何,您可以通过更改LoadShader
代替GLchar**
来更正您的问题。我将在下面说明必要的更改:
/* Originally, you made a copy of an uninitialized pointer and then proceeded to
re-assign this copy a value when you called malloc (...) - you actually need
to pass a pointer to your pointer so you can update the address outside of
this function!
*/
int LoadShader(char* Filename, GLchar** pShaderSource) //dont call this function by itself as it doesnt free its own memory
{
[...]
*pShaderSource = (GLchar *)malloc((sizeof(GLchar)) * len + 1); //allocate enough bytes for the file
GLchar* ShaderSource = *pShaderSource;
[...]
}
GLuint MakeProgram(char* VSpath, char* FSpath){
[...]
GLchar* VSsource; /* Uninitialized */
GLchar* FSsource; /* Uninitialized */
if(!LoadShader(VSpath, &VSsource)) /* Pass the address of your pointer */
return -1;
if(!LoadShader(FSpath, &FSsource)) /* Pass the address of your pointer */
return -1;
/*
* Now, since you did not pass copies of your pointers, you actually have
* *VALID* initialized memory addresses !
*/
[...]
}
或者,您可以简单地修改函数以返回您分配的字符串的地址。您可以返回 NULL ,而不是像现在一样在失败时返回 -1 。如果您选择走这条路线,您的功能界面就会如此简单:GLchar* LoadShader (char* Filename)
。