Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

http://www.sdltutorials.com/sdl-opengl-tutorial-basics

http://www.opengl-tutorial.org/beginners-tutorials/tutorial-2-the-first-triangle/

These two tutorials use completely different approaches to get nearly the same result. The first uses things like glBegin(GL_QUADS). The second one uses stuff like vertexBufferObjects, shaders based on GLEW. But the result is the same: you get basic shapes.

Why do these differences exist?

The first approach seems much easier to understand. What's the advantage of the complicated second approach?

share|improve this question
1  
There is never just one way to skin a cat. –  Philipp yesterday
2  
@Philipp Yes, but there are right ways and wrong ways, old ways and new ways (and as the answers below demonstrate, the old and new ways may not be compatible in all situations) –  Andrew Hill 18 hours ago

2 Answers 2

OpenGL has four different major versions, not counting the versions for mobile devices and embedded systems (OpenGL|ES) and the Web via JavaScript (WebGL). Just like Direct3D 11 has a different way of doing things than Direct3D 8, so does OpenGL 3 have a different way of doing things than OpenGL 1. The big difference is that OpenGL versions are mostly just add-ons to the older versions (but not entirely).

On top of the different editions and versions of OpenGL, the main OpenGL also added the concept of profiles. Namely the Compatibility Profile (which enables support for APIs from older versions) and the Core Profile (which disables those old APIs). Things like glBegin simply don't work when you use the Core Profile but will when you use the Compatibility Profile (which is the default).

As one further major complication, some implementations of OpenGL (like Apple's, among others) will only enable newer OpenGL features when you're using the Core Profile. This means that you must stop using older APIs in order to use newer APIs.

You then end up with several very confusing scenarios for tutorials:

  1. The tutorial is old and only uses deprecated APIs.
  2. The tutorial is new and well-written and only uses Core-compatible APIs.
  3. The tutorial is new but makes the mistake of assuming that you're working with a driver that enables all APIs in Compatibility mode, and freely mixes both new and old APIs.
  4. The tutorial is for a different edition of OpenGL like OpenGL|ES that doesn't support any of the old APIs at all, in any version.

Things like glBegin are part of what's sometimes called the immediate mode API. This is also super confusing because there's no such thing as a retained mode in OpenGL and "immediate mode" already had a different definition in graphics. It's much better to just refer to those as OpenGL 1.x APIs as they've been obsolete since OpenGL 2.1.

OpenGL's immediate mode would immediately submit vertices to the graphics pipeline back in the old days. This worked well when the speed of the hardware that rendered vertices was roughly on par with the speed of the CPU generating the vertex data. OpenGL back then just offloaded the triangle rasterization and not much else.

These days, the GPU can chew through massive numbers of vertices at very high speeds while performing advanced vertex and pixel transformation and the CPU simply cannot even remotely keep up. On top of that, the interface between the CPU and the GPU has been designed around this speed difference meaning that it's not even possible to submit vertices to the GPU one at a time anymore.

All GL drivers must emulate glBegin by internally allocating a vertex buffer, putting the vertices submitted with glVertex into this buffer, and then submitting that whole buffer in a single draw call when glEnd is called. The overhead of these functions is far greater than if you just updated the vertex buffer yourself, which is why some documentation will (very mistakenly!) refer to vertex buffers as "an optimization" (it's not an optimization; it's the only way to actually talk to the GPU).

There are various other APIs that have been deprecated or obsoleted in OpenGL over the years. The so-called fixed-function pipeline is another such piece. Some documentation might still use this pipeline or mix with with the programmable pipeline. The fixed-function pipeline comes from the olden days when graphics card hard-coded all of the math used to render 3D scenes and the OpenGL API was limited to setting some configuration values for that math. These days the hardware has very little hard-coded math and (just like your CPU) runs user-supplied programs (often called shaders) instead.

Once again the drivers must emulate the old API as the fixed-function features simply aren't present on hardware anymore. This means that the driver has a bunch of compatibility shaders embedded in it that execute the old math from the fixed-function days which is used when you don't supply your own shaders. The old OpenGL functions that modify that old fixed-function state (like the old OpenGL lighting API) are actually using modern OpenGL features like uniform buffers to feed these values to the driver's compatibility shaders.

Drivers that support compatibility have to do a lot of behind-the-scenes work just to figure out when you're using these obsolete features and making sure that you can combine them with modern features smoothly, which adds overhead and greatly complicates the driver. This is one of the reasons that some drivers force you to enable the Core Profile to get at newer features; it simplifies their driver internals greatly by not having to support both the old and new APIs being used simultaneously.

A lot of documentation may recommend that you start with the old APIs simply on account of them being easier to get started with. Direct3D solved this problem for beginners by offering a companion library (DirectX Tool Kit) that provides simpler drawing APIs and pre-written shaders which can be freely mixed with raw Direct3D 11 usage as your expertise grows. The wider OpenGL community has mostly stuck with the Compatibility Profile for beginners, unfortunately, which is problematic as again there are systems that do not let you mix old OpenGL APIs with the newer ones. There are many unofficial libraries and tools for simpler rendering on the new OpenGL, but nothing officially endorsed or widely agreed upon.

Documentation you're finding may not even be for OpenGL but may be for one of the other similar APIs. OpenGL|ES 1.x had fixed-function rendering but did not have the OpenGL 1.x APIs for vertex submission. OpenGL|ES 2.x+ and WebGL 1+ do not have any fixed-function features at all and there is no backwards compatibility modes those APIs.

These APIs look very very similar to main OpenGL; they're not quite compatible, but there are official extensions to OpenGL that some (not all) drivers support to become compatible with OpenGL|ES (which WebGL is based on). Because things weren't confusing enough before.

share|improve this answer
2  
+1 Fantastic answer! If you could mention a couple of those unofficial libraries and tools for simple rendering on the new OpenGL that would be great :) –  Mehrdad 18 hours ago
1  
Brilliant answer. I've had the same trouble with DirectX back in the day - much simpler than with OpenGL, but the leap from retained/immediate mode to shaders was huge. Fortunately, the documentation helped a lot (unlike OpenGL's, at least for me), but the beginning of "how do I even light" was crazy :D –  Luaan 15 hours ago
    
I'm the author of opengl-tutorial.org, and I agree with Sean. The API evolved this way primarily for performance reasons. –  Calvin1602 15 hours ago

The primary difference is how up-to-date the strategies are. The immediate mode used in the first tutorial:

glBegin(GL_QUADS);
    glColor3f(1, 0, 0); glVertex3f(0, 0, 0);
    glColor3f(1, 1, 0); glVertex3f(100, 0, 0);
    glColor3f(1, 0, 1); glVertex3f(100, 100, 0);
    glColor3f(1, 1, 1); glVertex3f(0, 100, 0);
glEnd();

Is outdated and not supported on newer versions.

Using vertex buffers and shaders is the current method of rendering with OpenGL. It may seem more complicated, but it performs considerably better. Additionally, once you have your supporting code wrapping up the OpenGL stuff, the differences are abstracted away for the most part.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.