在包装OpenGL着色器时,我发现了其中一个必需参数的问题。标准顶点着色器的源由OpenGL复制到内部表示中。一个简单的例子可能是这样的:
static const GLchar * vertex_shader_source[] =
{
"#version 430 core\n",
"void main(void)\n"
"{",
" gl_Position = vec4(0.0, 0.0, 0.5, 1.0):\n",
"}"
};
GLchar
定义为char
,因此本质上是cstr。我编写了一个包装器对象,该对象可以帮助我创建和销毁着色器(GLuint
是OpenGL句柄)。我的问题可以分解为以下函数调用:
GLuint shader_ptr = helper(GL_VERTEX_SHADER, vertex_shader_source);
我只需要vertex_shader_source即可使用。我想写一些使用数组初始化程序创建具有自动作用域的内存的东西。我不想使用C99的转换方式,因为我想使用C ++ 11的方式进行转换。
helper
定义如下:
GLuint helper(GLenum type, const GLchar * source[])
{
GLuint shader_ptr = glCreateShader(type);
glShaderSource(shader_ptr, 1, source, NULL);
glCompileShader(shader_ptr);
return shader_ptr;
}
删除对于这个问题并不重要,可以使用来在析构函数中进行处理glDeleteShader
。
我尝试了以下操作,但无法编译:
GLuint shader_ptr = helper(GL_VERTEX_SHADER,
{
"#version 430 core\n",
"void main(void)\n"
"{",
" gl_Position = vec4(0.0, 0.0, 0.5, 1.0):\n",
"}"
}
);
我怎么称呼它helper
为“一个班轮”?
如果您的着色器是单个字符串(而不是字符串列表,在某些地方实际上是非常有益的),则使您的助手仅接受achar const *
而不是a char const * const *
。这样,您将拥有一个本地符号,可以使用以下地址:
GLuint helper(GLenum type, GLchar const * source)
{
GLuint shader_name = glCreateShader(type);
glShaderSource(shader_ptr, 1, &source, NULL);
glCompileShader(shader_ptr);
return shader_name;
}
您可以仅使用字符串作为参数来调用它:
GLuint shader_name = helper(GL_VERTEX_SHADER,
"#version 430 core\n"
"void main() {"
" gl_Position = vec4(0.0, 0.0, 0.5, 1.0);"
"}"
);
请注意,由于没有逗号(),因此缺少围棋符{
,}
并且这是一个长字符串文字,
。
顺便说一句:OpenGL不给您指针,但是不透明的对象名。
诸如着色器源文本之类的字符串文字是编译时间常数。像任何类型的常数值一样,就地编写它们是不好的方式:如果是数字,这是没有意义的“魔术值”。对于某些字符串,在读取源代码(宿主程序与着色器代码交错)时,您现在必须在头脑中保持两个解析器状态。这在很大程度上降低了可读性并降低了可维护性。
另外,您的助手也缺少错误检查代码。
在我的项目中,使用编译到程序中的着色器源时,我使用此帮助器(请注意,它实际上将数组提取为C字符串):
https://gist.github.com/datenwolf/f108f2ed4085f3840457
GLuint load_gl_shader_from_sources(
GLenum shader_unit,
char const * const * const sources )
{
GLuint shader = glCreateShader(shader_unit);
if( !shader ) {
goto failed_shader;
}
size_t n_sources = 0;
for(; sources[n_sources]; n_sources++);
GLint * const lengths = alloca(sizeof(GLint)*(n_sources+1));
if( !lengths ) {
goto failed_lengths;
}
lengths[n_sources] = 0;
for(size_t i = 0; i < n_sources; i++) {
lengths[i] = strlen(sources[i]);
}
glShaderSource(shader, n_sources, sources, lengths);
glCompileShader(shader);
GLint shader_status;
glGetShaderiv(shader, GL_COMPILE_STATUS, &shader_status);
if( shader_status == GL_FALSE ) {
GLint log_length, returned_length;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_length);
char *shader_infolog = alloca(log_length);
if(shader_infolog) {
glGetShaderInfoLog(
shader,
log_length,
&returned_length,
shader_infolog );
char const * shader_unit_str = NULL;
switch(shader_unit) {
case GL_VERTEX_SHADER: shader_unit_str = "vertex"; break;
case GL_FRAGMENT_SHADER: shader_unit_str = "fragment"; break;
}
fprintf(stderr,
"\n %s shader compilation failed;\n%*s",
shader_unit_str,
returned_length, shader_infolog );
}
goto failed_compile;
}
return shader;
failed_compile:
failed_lengths:
glDeleteShader(shader);
failed_shader:
return 0;
}
GLuint load_gl_program_from_sources(
char const * const * const sources_vs,
char const * const * const sources_fs )
{
GLuint program = glCreateProgram();
if( !program ) {
goto failed_program;
}
GLuint vert_shader = 0;
if( sources_vs ) {
vert_shader = load_gl_shader_from_sources(
GL_VERTEX_SHADER,
sources_vs );
if( !vert_shader ) {
goto failed_vert_shader;
}
}
GLuint frag_shader = 0;
if( sources_fs ) {
frag_shader = load_gl_shader_from_sources(
GL_FRAGMENT_SHADER,
sources_fs );
if( !frag_shader ) {
goto failed_frag_shader;
}
}
glAttachShader(program, vert_shader);
glAttachShader(program, frag_shader);
glLinkProgram(program);
GLint linkStatus;
glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
if( GL_FALSE == linkStatus ) {
GLint log_length, returned_length;
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &log_length);
char *program_infolog= alloca(log_length);
if(program_infolog) {
glGetProgramInfoLog(
program,
log_length,
&returned_length,
program_infolog );
fwrite(program_infolog, returned_length, 1, stderr);
}
goto failed_link;
}
/* shaders will get actually deleted only after the rogram gets deleted */
glDeleteShader(vert_shader);
glDeleteShader(frag_shader);
return program;
failed_link:
if(frag_shader)
glDeleteShader(frag_shader);
failed_frag_shader:
if(vert_shader)
glDeleteShader(vert_shader);
failed_vert_shader:
glDeleteProgram(program);
failed_program:
return 0;
}
您可以像这样使用它:
void renderBoundingBox(mat4x4 mv, mat4x4 proj)
{
char const * vs_sources[] = {
"#version 120\n",
"uniform mat4x4 mv; uniform mat4x4 proj;"
"attribute vec3 position;",
"void main() { gl_Position = proj * mv * vec4(position*2.-1., 1.0); }",
NULL };
char const * fs_sources[] = {
"#version 120\n",
"void main() { gl_FragColor = vec4(1.0f); }",
NULL };
static GLuint program = 0;
static GLint attrib_position, uniform_mv, uniform_proj;
if( !program ) {
program = load_gl_program_from_sources(
vs_sources,
fs_sources );
uniform_mv = voglr_glGetUniformLocation(program, "mv");
uniform_proj = voglr_glGetUniformLocation(program, "proj");
attrib_position = voglr_glGetAttribLocation(program, "position");
}
if( !program ) {
return;
}
/* … */
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句