OpenGL着色器加载失败

4
我在我的着色器加载代码上遇到了问题。令我困惑的奇怪事情是,它可能只有5次中的一次才能工作,但然后只在某种程度上起作用。例如,它会加载frag着色器,但是纹理不会正常工作(它会在几何体上绘制纹理的奇怪外观)。我认为问题出在加载代码上,所以我的问题就是这个。是否有人能够在下面的代码中发现我没有发现的错误?
char* vs, * fs;

vertexShaderHandle   = glCreateShader(GL_VERTEX_SHADER);
fragmentShaderHandle = glCreateShader(GL_FRAGMENT_SHADER);

long sizeOfVShaderFile = getSizeOfFile(VERTEX_SHADER_FILE_NAME);
long sizeOfFShaderFile = getSizeOfFile(FRAGMENT_SHADER_FILE_NAME);

if(sizeOfVShaderFile == -1)
{
    cerr << VERTEX_SHADER_FILE_NAME<<" is null!  Exiting..." << endl;
    return;
}
if(sizeOfFShaderFile == -1)
{
    cerr << FRAGMENT_SHADER_FILE_NAME<<" is null!  Exiting..." << endl;
    return;
}

vs = readFile(VERTEX_SHADER_FILE_NAME);
fs = readFile(FRAGMENT_SHADER_FILE_NAME);

const char* vv = vs, *ff = fs;

glShaderSource(vertexShaderHandle  , 1, &vv, NULL);

cout << "DEBUGGING SHADERS" << endl;
cout << "VERTEX SHADER:  ";
printShaderInfoLog(vertexShaderHandle);
cout << endl;

glShaderSource(fragmentShaderHandle, 1, &ff, NULL);

cout << "FRAGMENT SHADER:  ";
printShaderInfoLog(fragmentShaderHandle);
cout << endl;


glCompileShader(vertexShaderHandle);

cout << "VERTEX SHADER:  ";
printShaderInfoLog(vertexShaderHandle);
cout << endl;

glCompileShader(fragmentShaderHandle);

cout << "FRAGMENT SHADER:  ";
printShaderInfoLog(fragmentShaderHandle);
cout << endl;


programHandle = glCreateProgram();

cout << "DEBUGGING PROGRAM" << endl;

glAttachShader(programHandle, vertexShaderHandle);

printProgramInfoLog(programHandle);

glAttachShader(programHandle, fragmentShaderHandle);

printProgramInfoLog(programHandle);


glLinkProgram(programHandle);

printProgramInfoLog(programHandle);

glUseProgram(programHandle);

printProgramInfoLog(programHandle);


delete[] vs; delete[] fs;

以下是readFile函数:

char* readFile(const char* path)
{
    unsigned int fileSize = getSizeOfFile(path);

    char* file_data = new char[fileSize];

    ifstream input_stream;

    input_stream.open(path, ios::binary);

    input_stream.read(file_data, fileSize);

    input_stream.close();
    //this is deleted at the end of the shader code
    return file_data;
}

以下所有信息均来自同一个可执行文件(未重新构建)。
以下是第一个可能的错误信息:
BallGLWidget::initializeGL called
DEBUGGING SHADERS
VERTEX SHADER:  
FRAGMENT SHADER:  
VERTEX SHADER:  ERROR: 0:17: '<' : syntax error syntax error


FRAGMENT SHADER:  
DEBUGGING PROGRAM
ERROR: One or more attached shaders not successfully compiled

ERROR: One or more attached shaders not successfully compiled

glGetError enum value:  GL_NO_ERROR

可能出现的另一种错误消息:
BallGLWidget::initializeGL called
DEBUGGING SHADERS
VERTEX SHADER:  
FRAGMENT SHADER:  
VERTEX SHADER:  ERROR: 0:17: 'tt' : syntax error syntax error


FRAGMENT SHADER:  ERROR: 0:33: '?' : syntax error syntax error


DEBUGGING PROGRAM
ERROR: One or more attached shaders not successfully compiled

ERROR: One or more attached shaders not successfully compiled

以下是成功运行时的输出(可能仅在5到6次中出现一次)。
BallGLWidget::initializeGL called
DEBUGGING SHADERS
VERTEX SHADER:  
FRAGMENT SHADER:  
VERTEX SHADER:  
FRAGMENT SHADER:  
DEBUGGING PROGRAM
Image format is GL_RGB
Checking textures...
glGetError enum value:  GL_NO_ERROR

我严重怀疑它不是着色器本身的问题,因为它们有时候会工作...而报告的错误信息是无用的。

如果需要更多信息,我很乐意提供。

编辑:这里是着色器

顶点着色器:

attribute vec2 a_v_position;
attribute vec2 a_tex_position;

varying   vec2 tex_coord_output;


void main()
{
    tex_coord_output = a_tex_position;

    gl_Position = vec4(a_v_position, 0.0, 1.0);
}

片段着色器:

varying vec2 tex_coord_output;

uniform sampler2D ballsampler;


void main()
{
        gl_FragColor = texture2D(ballsampler, tex_coord_output);
}

1
我们能看一下实际的着色器吗? - Robert Rouhani
当然,我已经在编辑中发布了它们。 - Prime
你能检查一下 ifstream.read() 调用的返回值,确保你读取的数据是实际数据,并且不会因为某些原因而失败吗?从表面上看,你的初始化似乎是正确的,但错误提示似乎表明它可能正在从流中读取垃圾数据(我会再次检查你的代码,以防我的假设是错误的)。 - Jesus Ramos
2个回答

4
你的问题与读取GLSL文件时得到垃圾字符是重复的,这里是我的答案
您正在使用C++,因此我建议您充分利用它。而不是读入自分配的字符数组, 我建议你读入std::string:
#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));
}

非常感谢您提供的代码片段!这为我节省了大量的工作! - newprogrammer

3

您正在阅读文件,但据我所见,您没有对文本进行零终止。尝试分配 filesize+1 并将最后一个字符设置为零。


谢谢!就是这样!太好了,我从来没有想过那个。 - Prime
要么使用零终止符,要么在提供glShaderSource时附带数据的长度。 - datenwolf

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接