Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>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 <em>can</em> 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 href="https://stackoverflow.com/questions/2254706/how-to-start-developing-with-opengl-and-c-what-tools-do-i-need-to-install-on-w/2254966#2254966">a previous answer</a>. </p> <p>That (mostly) leaves the code to compile, link, and use shaders. I've written a small class I find handy for this purpose:</p> <pre><code>class shader_prog { GLuint vertex_shader, fragment_shader, prog; template &lt;int N&gt; GLuint compile(GLuint type, char const *(&amp;source)[N]) { GLuint shader = glCreateShader(type); glShaderSource(shader, N, source, NULL); glCompileShader(shader); GLint compiled; glGetShaderiv(shader, GL_COMPILE_STATUS, &amp;compiled); if (!compiled) { GLint length; glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &amp;length); std::string log(length, ' '); glGetShaderInfoLog(shader, length, &amp;length, &amp;log[0]); throw std::logic_error(log); return false; } return shader; } public: template &lt;int N, int M&gt; shader_prog(GLchar const *(&amp;v_source)[N], GLchar const *(&amp;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); } }; </code></pre> <p>For a simple demo, a couple of "pass-through" shaders (just imitate the fixed-functionality pipeline):</p> <pre><code>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", "}" }; </code></pre> <p>Which you'd use something like:</p> <pre><code>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(); } </code></pre> <p>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 <code>prog1();</code>, <code>prog2();</code>, etc., just prior drawing the objects you want shaded with each shader. E.g., </p> <pre><code>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(); } </code></pre> <p>Edit: As @rotoglup quite correctly points out, this use of <code>static</code> variables delays destruction until after the OpenGL context has been destroyed, so when the destructors attempt to use <code>glDeleteProgram</code>/<code>glDeleteShader</code>, results are unpredictable (at best).</p> <p>While this may be excusable in a demo program, it's decidedly undesirable in real use. At the same time, you generally do <em>not</em> want to re-compile your shader(s) every time you enter the function(s) that use them.</p> <p>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:</p> <pre><code>class some_character_type { shader_prog skin_shader; public: // ... }; </code></pre> <p>This will compile/link the shader program once when you create a character of that type, and destroy it when you destroy that character.</p> <p>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 <code>shared_ptr&lt;shader_prog&gt;</code> 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.</p> <p>In any case, we're getting a bit off-track here. The point is that compiling and linking shaders is a <em>fairly</em> 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).</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload