Easy Framework for Opengl Shaders in C/C++

Easy framework for OpenGL Shaders in C/C++

First of all, I'd avoid using glut -- it's buggy, hasn't been updated in roughly a decade, and its design doesn't really fit very well with what most people want today (e.g., though you can use it for animations, it's really intended primarily to produce a static display). I pointed out a number of alternatives to glut in a previous answer.

That (mostly) leaves the code to compile, link, and use shaders. I've written a small class I find handy for this purpose:

class shader_prog {
GLuint vertex_shader, fragment_shader, prog;

template <int N>
GLuint compile(GLuint type, char const *(&source)[N]) {
GLuint shader = glCreateShader(type);
glShaderSource(shader, N, source, NULL);
glCompileShader(shader);
GLint compiled;
glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
if (!compiled) {
GLint length;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length);
std::string log(length, ' ');
glGetShaderInfoLog(shader, length, &length, &log[0]);
throw std::logic_error(log);
return false;
}
return shader;
}
public:
template <int N, int M>
shader_prog(GLchar const *(&v_source)[N], GLchar const *(&f_source)[M]) {
vertex_shader = compile(GL_VERTEX_SHADER, v_source);
fragment_shader = compile(GL_FRAGMENT_SHADER, f_source);
prog = glCreateProgram();
glAttachShader(prog, vertex_shader);
glAttachShader(prog, fragment_shader);
glLinkProgram(prog);
}

operator GLuint() { return prog; }
void operator()() { glUseProgram(prog); }

~shader_prog() {
glDeleteProgram(prog);
glDeleteShader(vertex_shader);
glDeleteShader(fragment_shader);
}
};

For a simple demo, a couple of "pass-through" shaders (just imitate the fixed-functionality pipeline):

const GLchar *vertex_shader[] = {
"void main(void) {\n",
" gl_Position = ftransform();\n",
" gl_FrontColor = gl_Color;\n",
"}"
};

const GLchar *color_shader[] = {
"void main() {\n",
" gl_FragColor = gl_Color;\n",
"}"
};

Which you'd use something like:

void draw() { 
// compile and link the specified shaders:
static shader_prog prog(vertex_shader, color_shader);

// Use the compiled shaders:
prog();

// Draw something:
glBegin(GL_TRIANGLES);
glColor3f(0.0f, 0.0f, 1.0f);
glVertex3f(-1.0f, 0.0f, -1.0f);
glColor3f(0.0f, 1.0f, 0.0f);
glVertex3f(1.0f, 0.0f, -1.0f);
glColor3f(1.0f, 0.0f, 0.0f);
glVertex3d(0.0, -1.0, -1.0);
glEnd();
}

If you're going to use, for example, a number of different fragment shaders in the course of drawing your scene, you simply define a static object for each, then execute prog1();, prog2();, etc., just prior drawing the objects you want shaded with each shader. E.g.,

void draw() { 
static shader_prog wall_shader("wall_vertex", "wall_frag");
static shader_prog skin_shader("skin_vertex", "skin_frag");

wall_shader();
draw_walls();

skin_shader();
draw_skin();
}

Edit: As @rotoglup quite correctly points out, this use of static variables delays destruction until after the OpenGL context has been destroyed, so when the destructors attempt to use glDeleteProgram/glDeleteShader, results are unpredictable (at best).

While this may be excusable in a demo program, it's decidedly undesirable in real use. At the same time, you generally do not want to re-compile your shader(s) every time you enter the function(s) that use them.

To avoid both problems, you generally want to create your shader objects as members of a class instance whose lifetime is, in turn, tied to the lifetime of whatever it's going to shade:

class some_character_type { 
shader_prog skin_shader;
public:
// ...
};

This will compile/link the shader program once when you create a character of that type, and destroy it when you destroy that character.

Of course, in a few cases, this isn't exactly desirable either. Just for example, consider a 3D version of the ancient "kill lots of targets" games like Galaga or Centipede. For games like this, you're creating and destroying lots of essentially identical targets relatively quickly. Given a large number of essentially identical targets, you probably want to use something like a shared_ptr<shader_prog> to create a single instance of the shader that's shared between all the instances of a particular target type. Given that you re-use the same target types many times, you may want to go a bit further even than that, so you maintain the same shaders through the entire game, not just when a particular type of target is being shown.

In any case, we're getting a bit off-track here. The point is that compiling and linking shaders is a fairly expensive process, so you normally want to manage their lifetime to avoid creating and destroying them a lot more often than truly necessary (though that's not to say that it's critical to create them all at the beginning of the game and only destroy them at the end, either).

What is the most short way to run your GLSL shader (not compiled yet) from C++?

Probably the easiest way would be to use a cross-platform OpenGL framework like GLFW with a bit to compile and use a shader (e.g., one I posted in a previous answer). For systems that didn't support OpenGL otherwise, you'd probably want to use Mesa3D.

OpenGL Using built-in lighting or custom one with shaders

OpenGL has built-in lighting

No, it does not. All such things were removed from OpenGL in 3.1 and put into the compatibility profile. Which is not required to be supported.

What does built-in lighting do worse?

Everything. It does everything worse.

Fixed function lighting is per-vertex, while shader-based lighting can be whatever you want: per-vertex, per-fragment, whatever. Fixed-function lighting doesn't work with deferred rendering, lighting pre-passes, or various other rendering techniques. Fixed-function lighting can't handle HDR or gamma correct illumination.

There is nothing that fixed-function lighting can do that user-defined lighting cannot. While there is a ton of stuff that user-defined lighting can do that fixed-function can't.

It is good that modern OpenGL tutorials don't teach that outdated garbage.

How to design a simple GLSL wrapper for shader use

Basic Linking:

There is no standard way here. There are at least 2 general approaches:

  1. Monolithic - one shader covers many cases, using uniform boolean switches. These branches don't hurt performance because the condition result is constant for any fragment group (actually, for all of the fragments).

  2. Multi-object program compositing - main shader declares a set of entry points (like 'get_diffuse', 'get_specular', etc), which are implemented in separate shader objects attached. This implies individual shader for each object, but any kind of caching helps.

Setting Variables: Uniforms

I will just describe the approach I developed.

Each shader program has a list of uniform dictionaries. It's used to fill the uniform source list upon program (re-)linking. When the program is activated, it goes through the uniform list, fetches values from their sources and uploads them to GL. In the result, data is not directly connected with the user shader program, and whatever manages it does not care about the program using it.

One of these dictionaries can be, for example, a core one, containing model,view transformations, camera projection and maybe something else.

Setting Variables: Attributes

First of all, shader program is an attribute consumer, so it is what has to extract these attributes from a mesh (or any other data storage) and upload them to GL in a way it needs. It should also make sure that types of provided attributes match the requested types.

When using with monolithic shader approach, there is a possible unpleasant situation when one the disabled branch ways requires a vertex attribute that is not provided. I would advice using another attribute's data to supply the missing one, because we don't care about the actual values in this case.

P.S.
You can find an actual implementation of these ideas here: http://code.google.com/p/kri/

OpenGL Shaders Not Drawing

I have 0 idea why the manner in which I declared the VSource was incorrect, but re-referencing the source in the textbook showed that having commas at the end of the quotation marks (for the GLSL source) was what broke it.

Code was

/// EOL commas broke this
static const GLchar* VSource[] = {
"#version 450 core\n",
"void main(void)\n",
"{\n",
" const vec4 vertices[3] = vec4[3](vec4(0.25, -0.25, 0.5, 1.0),",
" vec4(-0.25, -0.25, 0.5, 1.0),",
" vec4(0.25, 0.25, 0.5, 1.0));\n",
" gl_Position = vertices[gl_VertexID];\n",
"}\n"
};

static const GLchar* FSource[] = {
"#version 450 core\n"
"out vec4 color;\n"
"void main(void)\n"
"{\n"
" color = vec4(0.0, 0.8, 1.0, 1.0);\n"
"}\n"
};

Code should be

static const GLchar* VSource[] = {
"#version 450 core\n",
"void main(void)\n",
"{\n",
" const vec4 vertices[3] = vec4[3](vec4(0.25, -0.25, 0.5, 1.0),\n",
" vec4(-0.25, -0.25, 0.5, 1.0),\n",
" vec4(0.25, 0.25, 0.5, 1.0));\n",
" gl_Position = vertices[gl_VertexID];\n",
"}\n"
};

static const GLchar* FSource[] = {
"#version 450 core\n"
"out vec4 color;\n"
"void main(void)\n"
"{\n"
" color = vec4(1.0, 1.0, 1.0, 1.0);\n"
"}\n"
};

Edit:

I just figured out why it wasn't working. The "Shader Code" to human-eyes was correct, but it was only reading the first line of the vertex shader, which was an empty shader program. The GLSL compiler reads 1 entry, instead of all of them.

How to start developing with OpenGL and C++, what tools do I need to install on windows

The Ne-He tutorials (to which @wich has already kindly provided a link) are quite good for what they are (but at least the last time I looked carefully, the OpenGL the teach and work with is quite dated).

glut, however, I'd generally avoid. It has a fair number of bugs, and nobody's working on fixing them. It was basically abandoned in a beta test state in the late 1990s, so it seems doubtful (at best) that anybody will ever even try to fix them.

A couple of alternatives to glut (both apparently in active development) are GLFW and FLTK. Between these, GLFW is much closer to glut in character -- a small toolkit for abstracting away most of the OS-dependent parts, so you can produce OpenGL programs with relatively little hassle. FLTK is really a full-blown GUI toolkit (though rather small as GUI toolkits go) that has a built-in glut emulation (that, at least the last time I played with it, seemed considerably better implemented than glut itself).

I suppose I should also point out one more alternative to glut: freeglut is a free re-implementation of the glut API. I can't say I really recommend it, but at least it's been actively developed a lot more recently than the original glut.

When/if you decide you want to play around with shaders, both AMD and nVidia have developer web pages. nVidia's, in particular, has a huge amount of free "stuff" available (just beware that it's easy to burn all too many hours playing around with their demos and such).

OpenGL Separable shader programs and pipline performance on modern hardware

It is funny you should mention D3D11 hardware by name.

If you talk about D3D, you should know it has always worked this way. Shader programs are not immutable objects with every stage linked together in D3D like they are in OpenGL. D3D uses semantics and other goodies to let you swap out the shader attached to each stage whenever you want. The hardware has always worked the way D3D does and OpenGL just exposes this better now.

Whether you will see a change in performance or not from separable shaders is not a problem with the hardware. Any performance gain or loss will be down to the driver implementation. It cannot be substantial, however, or D3D would have adopted OpenGL's linked program model a long time ago -- that API constantly reinvents itself to lower overhead.



Related Topics



Leave a reply



Submit