我开始学习如何使用OpenGL,我绝对讨厌在main()之前将我的着色器声明为全局变量。
我认为制作一个可以从项目目录中的文件中读取着色器的结构或类会很酷。文件读取工作完全正常,但由于某种原因,它实际上输出的图像就像我在主要之前声明了着色器一样。这是我的例子。
着色器阅读结构:
#include "allHeader.h"
struct shaderReader
{
shaderReader::shaderReader(std::string);
const GLchar* source;
};
shaderReader::shaderReader(std::string name)
{
std::string line, allLines;
std::ifstream theFile(name);
if (theFile.is_open())
{
while (std::getline(theFile, line))
{
allLines = allLines + line + "\n";
}
source = allLines.c_str();
std::cout << source;
theFile.close();
}
else
{
std::cout << "Unable to open file.";
}
}
在main()
之前的区域快照shaderReader vertexShader = shaderReader("vertex.txt");
shaderReader fragmentShader = shaderReader("fragment.txt");
const GLchar* vertexSource =
"#version 150 core\n"
"in vec2 position;"
"void main() {"
" gl_Position = vec4(position, 0.0, 1.0);"
"}";
const GLchar* fragmentSource =
"#version 150 core\n"
"out vec4 outColor;"
"void main() {"
" outColor = vec4(1.0, 1.0, 1.0, 1.0);"
"}";
int main()
{
//stuff
}
作品
GLuint vertexShaderObject = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShaderObject, 1, &vertexSource, NULL);
glCompileShader(vertexShaderObject);
//Now let's create the Fragment Shader Object
GLuint fragmentShaderObject = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShaderObject, 1, &fragmentSource, NULL);
glCompileShader(fragmentShaderObject);
无法解决某些原因
const GLchar* ob1 = vertexShader.source;
const GLchar* ob2 = fragmentShader.source;
GLuint vertexShaderObject = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShaderObject, 1, &ob1, NULL);
glCompileShader(vertexShaderObject);
//Now let's create the Fragment Shader Object
GLuint fragmentShaderObject = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShaderObject, 1, &ob2, NULL);
glCompileShader(fragmentShaderObject);
也不起作用
GLuint vertexShaderObject = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShaderObject, 1, &vertexShader.source, NULL);
glCompileShader(vertexShaderObject);
//Now let's create the Fragment Shader Object
GLuint fragmentShaderObject = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShaderObject, 1, &fragmentShader.source, NULL);
glCompileShader(fragmentShaderObject);
以上代码在工作时在黑屏中间打印出白色三角形。但是,当我不工作时,我只是得到一个黑屏。我尝试检查着色器是否存在编译错误,我完全没有错误。我认为结构中可能出现了问题,我没有做对。感谢您阅读我的问题,如果您有类似的问题,我希望我的问题对您有帮助。
答案 0 :(得分:2)
您以无效方式混合使用C ++(std::string
)和C(char*
)字符串。
在构造函数中,您将在C ++ string
中构建代码,这是一个自动分配和重新分配内存以在字符串增长时保存字符串数据的对象。当它超出构造函数末尾的范围时,它也会自动释放该数据。
问题的根源在于:
source = allLines.c_str();
其中source
是类/结构成员。 c_str()
上的string
方法为您提供了指向对象内部字符串数据的指针。如上所述,当allLines
超出shaderReader
构造函数末尾的范围时,将释放此数据,因此最终会得到一个指向已释放内存的指针。这会导致未定义的行为,因为此内存现在可以用于其他内容。
解决此问题的最简单方法是始终如一地使用C ++字符串。将结构定义更改为:
struct shaderReader
{
shaderReader::shaderReader(std::string);
std::string source;
};
然后在构造函数中,您可以直接将源代码读入此类成员:
while (std::getline(theFile, line))
{
source = source + line + "\n";
}
您必须为char*
打扰的唯一原因是因为glShaderSource()
需要一个。最安全的方法是在最后一刻转换它:
const GLchar* ob1 = vertexShader.source.c_str();
GLuint vertexShaderObject = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShaderObject, 1, &ob1, NULL);
glCompileShader(vertexShaderObject);
这样,您只能暂时使用指向内部string
数据的指针,否则您不必为C风格的字符串和内存管理而烦恼。
答案 1 :(得分:1)
变化
source = allLines.c_str();
到
source = new char[allLines.length()+1];
strcpy(source,allLines.c_str());
在shaderReader的析构函数中,释放为源
分配的内存if(source)
{
delete[] source;
source = nullptr;
}
答案 2 :(得分:1)
我很想将您的着色器存储在std::vector<GLchar>
中,因此您不必担心分配和释放内存:
也许是这样的:
struct shaderReader
{
shaderReader(std::string);
std::vector<GLchar> source;
const GLchar* data;
GLint size;
};
shaderReader::shaderReader(std::string name)
{
std::string line, allLines;
std::ifstream theFile(name);
if(theFile.is_open())
{
while(std::getline(theFile, line))
{
allLines = allLines + line + "\n";
}
source.assign(allLines.begin(), allLines.end());
size = source.size();
data = source.data();
theFile.close();
}
else
{
std::cout << "Unable to open file.";
}
}
int main()
{
shaderReader sr("fragment-shader.txt");
GLuint shader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(shader, 1, &sr.data, &sr.size);
}