【问题标题】:Is there anything wrong with my glsl shader loading code?我的 glsl 着色器加载代码有什么问题吗?
【发布时间】:2012-06-21 12:58:59
【问题描述】:

问题在于,着色器(非常简单的,因为我正在学习 OpenGL)无法以看似随机的方式编译(并给出随机错误消息 * )。 然而,相同的着色器在大约 3 或 4 次尝试后编译。 代码如下:

Shader::Shader(GLenum Type,std::string filename)
{
    shader_type = Type;

    std::ifstream ifs(filename);
    if(!ifs)
        throw(std::runtime_error("File:"+filename+" not opened."));
    std::ostringstream stream;
    stream<<ifs.rdbuf();

    const GLchar* data = stream.str().c_str();

    handle = glCreateShader(shader_type);
    glShaderSource(handle,1,static_cast<const GLchar**>(&data),0);

    glCompileShader(handle);

    int status;
    glGetShaderiv(handle,GL_COMPILE_STATUS,&status);
    if(status == GL_FALSE)
    {
        int loglength;
        glGetShaderiv(handle,GL_INFO_LOG_LENGTH,&loglength);

        auto data = new char[loglength];

        glGetShaderInfoLog(handle,loglength,&loglength,data);

        std::string strdata(data);
        delete [] data;

        throw(std::runtime_error(strdata));
    }
}

请注意,着色器最后不会缺少换行符,在最后一个分号后有一个额外的空格,并且使用制表符而不是空格。 (正如互联网上各种旧帖子中所建议的那样!)。

  • 这里是由同一个顶点着色器产生的两条错误消息,不是同时产生的:

#version 330
in vec2 Position;
uniform mat4 transform;
void main()
{
    gl_Position = transform*vec4(Position,0.0f,1.0f);

}

错误:

0(1) : error C0000: syntax error, unexpected $undefined at token "<undefined>"


0(6) : error C0000: syntax error, unexpected '!', expecting ',' or ')' at token "!"

有时它确实有效! 是我的驱动程序有问题吗? (我在 Arch Linux 64 位上使用最近的 302.x 稳定版 nvidia 二进制驱动程序,并带有一张陈旧的 9600 GSO 卡)

P.S:只要着色器正确编译,代码就会按预期工作,所以我认为它应该是正确的。 如果无法从中找到问题并且有人想看一下,我很乐意将工作(有时!)示例作为 zip 文件发布。

【问题讨论】:

  • 着色器编译器很可能看到垃圾字符。确保输入符合您的预期。
  • 输入?就像在存储着色器的文本文件中一样?
  • 不,你传入glShaderSource的实际数据。可能是因为在const GLchar* data = stream.str().c_str(); 之后流被破坏了,您传递给它的数据是垃圾。
  • @Bart 是对的,您需要在提交到 glShaderSource(...) 时记录着色器源并生成错误消息(如果有)。
  • 启动调试器。调用glShaderSource时查看data的内容。大概率是垃圾。

标签: c++ opengl compiler-errors glsl shader


【解决方案1】:
const GLchar* data = stream.str().c_str();

这很糟糕。如果你想要字符串的数据,你需要存储它str 将返回缓冲区的副本,然后您可以使用c_str 获得指向该缓冲区的指针。一旦该临时对象被销毁(在这一行的末尾),该指针将指向您不再有权访问的内存。

正确的代码是这样的:

std::string dataString = stream.str();
const GLchar *data = reinterpret_cast<GLchar*>(dataString.c_str());

【讨论】:

  • 谢谢,好像可以了。你能建议一种方法来防止数据被复制这么多次吗(文件-> istream-> ostringstream-> 字符串-> char*-> OpenGL 采用它的任何地方)。我正在考虑诸如内存映射文件之类的东西,但不确定它是否会起作用。
  • @manasij7479:其中一半没有复制。 File->istream 会发生,无论您使用流、内存映射文件等。这称为 加载文件。 复制到 string-stream 不是绝对必要的;您可以从一对 istream 迭代器构造 std::string。所以你真的不需要stringstream。转换为char* 可能不会复制任何内容。 OpenGL 会以一种或另一种方式复制它。
  • 是这样想的,所以在尝试过早优化之前询问。有没有办法直接从 ifstream 的缓冲区(filebuf,iirc)获取 char 数组的地址?这可以消除构造字符串。
  • @manasij7479:ifstream 实际上还没有拥有字符。就像我说的,从流中读取称为“将文件加载到内存中”。您必须先将文件加载到内存中,然后才能从中读取。
  • 我试过你的代码@manasij7479 但reinterpret_cast 无法将const *char 转换为GLchar*
猜你喜欢
  • 2018-05-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-12
相关资源
最近更新 更多