/ * 定义类Shader。 * /
我正在用OpenGL和CMake开发C ++应用程序。我的目录结构为:
Shader.h ist主要用于从文件读取顶点和片段着色器源,进行编译并将其链接到Shader程序。看起来像这样:
#ifndef _SHADER_H
#define _SHADER_H
#include <string>
#include <exception>
#include <fstream>
#include <glad.h>
class shader_exception :std::exception {
private:
const char* text;
public:
shader_exception(const char* text)
: text(text) {}
virtual const char* what() const {
return text;
}
};
class Shader {
private:
std::string* vertex_source = new std::string();
std::string* fragment_source = new std::string();
unsigned int vao, vbo, vertex_shader, fragment_shader, program;
public:
Shader(const char* vertex_source_path, const char* fragment_source_path) {
std::ifstream file_reader;
file_reader.open(vertex_source_path);
std::string line;
if (file_reader.is_open()) {
while (getline(file_reader, line)) {
vertex_source->append(line + "\n");
}
file_reader.close();
}
else
throw shader_exception("Could not open vertex shader source file");
file_reader.open(fragment_source_path); // this is where I get an unhandled exception dialog box
if (file_reader.is_open()) {
while (getline(file_reader, line)) {
fragment_source->append(line + "\n");
}
file_reader.close();
}
else
throw shader_exception("Could not open fragment shader file");
const char** vertex_source_c = (const char**)malloc(vertex_source->size());
*vertex_source_c = vertex_source->c_str();
const char** fragment_source_c = (const char**)malloc(fragment_source->size());
*fragment_source_c = fragment_source->c_str();
vertex_shader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex_shader, 1, vertex_source_c, NULL);
glCompileShader(vertex_shader);
int success;
glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &success);
char infoLog[512];
if (!success) {
glGetShaderInfoLog(vertex_shader, 512, NULL, infoLog);
throw shader_exception(infoLog);
}
glShaderSource(fragment_shader, 1, fragment_source_c, NULL);
glCompileShader(fragment_shader);
glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(fragment_shader, 512, NULL, infoLog);
throw shader_exception(infoLog);
}
program = glCreateProgram();
glAttachShader(program, vertex_shader);
glAttachShader(program, fragment_shader);
glLinkProgram(program);
glGetProgramiv(program, GL_LINK_STATUS, &success);
if (!success) {
glGetProgramInfoLog(program, 512, NULL, infoLog);
throw shader_exception(infoLog);
}
glDeleteShader(vertex_shader);
glDeleteShader(fragment_shader);
}
Shader() = delete;
void use()
{
glUseProgram(program);
}
~Shader() {
glDeleteProgram(program);
}
};
#endif
在TanX.cpp中,我尝试创建一个这样的Shader对象:
Shader shader("vertex.glsl", "fragment.glsl");
如您所见,我要使用的着色器源文件是vertex.glsl和fragment.glsl,它们位于“ Shader”文件夹中。为了使它们对ifstream可用,在Shader文件夹中的CMakeLists.txt文件如下所示(这是here中提到的使文件可用于程序的选项之一):
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/vertex.glsl ${CMAKE_CURRENT_BINARY_DIR} COPYONLY)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fragment.glsl ${CMAKE_CURRENT_BINARY_DIR} COPYONLY)
顶级CMakeLists.txt文件还包含
add_subdirectory("TanX/src/Shader")
以便执行Shader中的CMakeLists.txt文件。
问题是,当我尝试在Visual Studio中运行代码时,在Shader.h文件的第45行(试图打开fragment.glsl)时出现未处理的异常。它是shader_exception,因此显然无法打开vertex.glsl。 “未处理的异常”对话框的详细信息:“ TanX.exe中0x00007FFF43E4A388的未处理异常:Microsoft C ++异常:内存位置0x00000028896FF608的shader_exception。”。现在我有两个问题
1)我需要做些什么来使ifstream打开vertex.glsl(然后再打开fragment.glsl)?
2)为什么我什至会收到未处理的异常错误,不应该在抛出异常后立即构造Shader对象,并且导致程序甚至无法到达第45行?
答案 0 :(得分:0)
这是蝙蝠吧……
Shader* shader;
try {
*shader = Shader("vertex.glsl", "fragment.glsl");
}
...是未定义的行为,因为您要取消引用未初始化的指针(即,您尚未为Shader
对象分配任何存储空间)。这可能不是唯一的问题,但它是一个关键问题,必须先解决,然后再进行进一步调试(因为此后程序的行为是不可预测的)。
您可能想写:
shader = new Shader(...);
(实际上,您应该为此使用std::unique_ptr
而不是一个裸露的指针,但这超出了原始问题的范围。除其他好处外,它还使这种错误更容易发现和避免。 )
对于其他问题,您是否检查过该程序是否在.glsl
文件所在的目录中运行?传递给文件流的相对路径是相对于程序的当前工作目录而不是相对于原始源文件的位置来解释的。
以我的计算,第45行是...
}
...所以似乎有些东西未对齐。将实际的程序输出和异常信息(或对话框内容)以及行号或注释显示调试器所指示的行一起发布将很有帮助。
答案 1 :(得分:0)
问题是我将文件放在哪里。我将它们放入Shader文件夹的bin文件夹中,但是由于它是在标头中实现的,因此正确的位置是顶级文件夹的bin文件夹。