![Big Grin :D](./images/smilies/icon_biggrin.gif)
Learning OpenGL
Learning OpenGL
Do you guys recommend any series of tutorials? ![Big Grin :D](./images/smilies/icon_biggrin.gif)
![Big Grin :D](./images/smilies/icon_biggrin.gif)
The Nehe tutorials are always a good place to start:
http://nehe.gamedev.net/
Although, personally I have found reading the FitzQuake, JoeQuake and in particular the FitzKurok source code very enlightening. And, of course, reading the OpenGL.org forums. (Ironically, MSDN is the best resource for digging deep for detailed documentation on what each OpenGL function does. Ironic because documentation matters, Microsoft excels at documentation and the OpenGL docs themselves on various functions are a bit more obtuse than they should be.)
/One opinion, other opinions may vary.
http://nehe.gamedev.net/
Although, personally I have found reading the FitzQuake, JoeQuake and in particular the FitzKurok source code very enlightening. And, of course, reading the OpenGL.org forums. (Ironically, MSDN is the best resource for digging deep for detailed documentation on what each OpenGL function does. Ironic because documentation matters, Microsoft excels at documentation and the OpenGL docs themselves on various functions are a bit more obtuse than they should be.)
/One opinion, other opinions may vary.
The night is young. How else can I annoy the world before sunsrise?
Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
![Cool 8)](./images/smilies/icon_cool.gif)
Mine doesn't vary.
One thing though that I will say is that the NeHe tutorials are really old-hat nowadays. You see, when you say "OpenGL" these days there are a number of different APIs you might be referring to.
There's classic OpenGL (1.0 to 1.4ish I would say) which is pre-hardware T&L, fixed functionality, focus on immediate mode, etc. OpenGL 1.5 is a slight oddity and an intermediate stage so I'll skip that.
I'd lump OpenGL 2.0 and 2.1 together (as well as with more modern versions using a compatibility context); here we're talking about shaders and VBOs as the primary rendering interface you'll use; hardware T&L now exists so a lot of the OpenGL philosophy of "don't sweat the hardware details, trust the driver to do the right thing" is no longer relevant and often downright dangerous.
Modern OpenGL is 3.x and 4.x in a core context; a lot of stuff is deprecated, you're now required to use shaders and VBOs everywhere, the matrix stack is gone, and so on.
OpenGL ES also exists in 2 flavours, and the main differentiating feature seems to be whether or not shaders are available.
So based on this you can see that one chunk of OpenGL code will often look nothing like another chunk, depending on which version each targets.
Back to NeHe - that's primarily what I've called "classic OpenGL" up above. It's fine for simple basic stuff, but it's not going to perform well at all on modern hardware. It's also completely different to the more modern API so anything you learn from it is not only going to be irrelevant, but it may get you into bad habits.
So take your pick really; depending on what you want to do with your code.
One thing though that I will say is that the NeHe tutorials are really old-hat nowadays. You see, when you say "OpenGL" these days there are a number of different APIs you might be referring to.
There's classic OpenGL (1.0 to 1.4ish I would say) which is pre-hardware T&L, fixed functionality, focus on immediate mode, etc. OpenGL 1.5 is a slight oddity and an intermediate stage so I'll skip that.
I'd lump OpenGL 2.0 and 2.1 together (as well as with more modern versions using a compatibility context); here we're talking about shaders and VBOs as the primary rendering interface you'll use; hardware T&L now exists so a lot of the OpenGL philosophy of "don't sweat the hardware details, trust the driver to do the right thing" is no longer relevant and often downright dangerous.
Modern OpenGL is 3.x and 4.x in a core context; a lot of stuff is deprecated, you're now required to use shaders and VBOs everywhere, the matrix stack is gone, and so on.
OpenGL ES also exists in 2 flavours, and the main differentiating feature seems to be whether or not shaders are available.
So based on this you can see that one chunk of OpenGL code will often look nothing like another chunk, depending on which version each targets.
Back to NeHe - that's primarily what I've called "classic OpenGL" up above. It's fine for simple basic stuff, but it's not going to perform well at all on modern hardware. It's also completely different to the more modern API so anything you learn from it is not only going to be irrelevant, but it may get you into bad habits.
So take your pick really; depending on what you want to do with your code.
We had the power, we had the space, we had a sense of time and place
We knew the words, we knew the score, we knew what we were fighting for
We knew the words, we knew the score, we knew what we were fighting for
Question about this, does this mean OpenGL 1.x apps will not perform as well on modern hardware as if they were re-written to use 3.0+, or does it mean that they will not perform as well as they do on older hardware?what I've called "classic OpenGL" up above. It's fine for simple basic stuff, but it's not going to perform well at all on modern hardware
I.e. will upgrading my video card make quake 3 slower?
No it won't, but you won't be optimally using your video card's resources so an upgrade won't necessarily make it faster either. Immediate mode is slow, fixed func is emulated through shaders on modern hardware, GL_POLYGON, GL_TRIANGLE_STRIP and friends are making no use whatsoever of vertex caches, as well as splitting what could be a nice big hardware-friendly triangle soup into lots of ittly bitty discrete polys (each of which has a fixed overhead that mounts up), and so on. So the only thing that an upgrade will give you is potentially higher clock speed; but that new GPU will be running at maybe 10% to 20% of it's actual capabilities.
Specific example - it's possible on modern hardware to put all frames for all MDLs in a map into VBOs. Use 4 bytes for position (the MDL format only specifies 0 to 255 as valid values) and 4 bytes for normal (because a 3 byte vertex attrib isn't supported in hardware) and you'll get a video RAM usage of 1 to 1.5 MB for ID1 maps, topping out at maybe 5 to 6 MB for bigger stuff. Small fry even on a 128 MB card. Send blendweights to a vertex shader as uniforms and suddenly you can do interpolation completely in hardware with no CPU stress, absolutely minimal bandwidth usage, and a coupla extra instructions on a vertex pipeline stage that's not exactly being overstressed to begin with. Draw them as indexed triangles and you get vertex counts decreased to maybe one quarter to one third what they were (at the cost of no more than 2k for indexes), your vertex caches suddenly start working, so recently used vertexes which have already been transformed don't need to be again. Start pushing the polycounts into 10s or 100s of thousands and you'll see how this can translate into huge performance increases that classic OpenGL is just not even capable of.
Right now using code like this I'm getting FPS counts hitting on 1000 in certain scenes that are ~150 using classic OpenGL type code. OK, so you don't actually need 1000 FPS, 150 is plenty. But I see it as headroom; I know that if I'm getting 1000 FPS here that it gives room for either me to add more visual FX or the mapper to add more detail.
Edit: re-read the Question; the answers are "yes", "no" and "no".
Quake 3 is an interesting case. It coincided with the hardware T&L revolution, but it does something quite evil - using GL_UNSIGNED_INT for it's index format. An interesting thing about hardware T&L is that hardware limits which were previous never an issue suddenly come up to bite you, and it's only relatively recently that hardware capable of 32-bit indexes actually became available. So chances are that OpenGL is - or at least was - disabling hardware T&L and putting the vertex pipeline through software emulation for a lot of people.
Specific example - it's possible on modern hardware to put all frames for all MDLs in a map into VBOs. Use 4 bytes for position (the MDL format only specifies 0 to 255 as valid values) and 4 bytes for normal (because a 3 byte vertex attrib isn't supported in hardware) and you'll get a video RAM usage of 1 to 1.5 MB for ID1 maps, topping out at maybe 5 to 6 MB for bigger stuff. Small fry even on a 128 MB card. Send blendweights to a vertex shader as uniforms and suddenly you can do interpolation completely in hardware with no CPU stress, absolutely minimal bandwidth usage, and a coupla extra instructions on a vertex pipeline stage that's not exactly being overstressed to begin with. Draw them as indexed triangles and you get vertex counts decreased to maybe one quarter to one third what they were (at the cost of no more than 2k for indexes), your vertex caches suddenly start working, so recently used vertexes which have already been transformed don't need to be again. Start pushing the polycounts into 10s or 100s of thousands and you'll see how this can translate into huge performance increases that classic OpenGL is just not even capable of.
Right now using code like this I'm getting FPS counts hitting on 1000 in certain scenes that are ~150 using classic OpenGL type code. OK, so you don't actually need 1000 FPS, 150 is plenty. But I see it as headroom; I know that if I'm getting 1000 FPS here that it gives room for either me to add more visual FX or the mapper to add more detail.
Edit: re-read the Question; the answers are "yes", "no" and "no".
Quake 3 is an interesting case. It coincided with the hardware T&L revolution, but it does something quite evil - using GL_UNSIGNED_INT for it's index format. An interesting thing about hardware T&L is that hardware limits which were previous never an issue suddenly come up to bite you, and it's only relatively recently that hardware capable of 32-bit indexes actually became available. So chances are that OpenGL is - or at least was - disabling hardware T&L and putting the vertex pipeline through software emulation for a lot of people.
We had the power, we had the space, we had a sense of time and place
We knew the words, we knew the score, we knew what we were fighting for
We knew the words, we knew the score, we knew what we were fighting for
Okay, that's what I thought you meant but i couldn't tell for sure... so if you want to run on really old hardware, keep using 1.x (and if you achieve acceptable performance on that old hardware, it will be acceptable on the new stuff too.)
If you target newer hardware and want to push the envelope, abandon 1.x at all costs.
If you target newer hardware and want to push the envelope, abandon 1.x at all costs.
Another interesting one I've always been curious about in the Quake and Quake II source code is the call to "GL_SelectTexture(TEXTURE1_SGIS);" before uploading lightmaps.
I believe that the only reason this exists is for Voodoo 2 cards. The 1st generation of these had something like 4MB framebuffer and 2MB per texture unit; texture swapping would have been the norm and I suspect that this was done to ensure that lightmaps always stayed on GL_TEXTURE1 and therefore wouldn't cause anything in the 2MB for GL_TEXTURE0 to be swapped out (and subsequent binds to GL_TEXTURE0 wouldn't cause lightmaps to be swapped out, and lightmaps wouldn't need to be switched between TMU memory at runtime, etc etc etc).
If memory serves I think that the Voodoo 2 was roundabout the only 3D card with this kind of weird memory configuration and more or less everything else had (or has) unified video RAM, so that call is both meaningless and unnecessary on anything else. Can't see it doing harm though; just interesting to work through the reasoning behind it.
I believe that the only reason this exists is for Voodoo 2 cards. The 1st generation of these had something like 4MB framebuffer and 2MB per texture unit; texture swapping would have been the norm and I suspect that this was done to ensure that lightmaps always stayed on GL_TEXTURE1 and therefore wouldn't cause anything in the 2MB for GL_TEXTURE0 to be swapped out (and subsequent binds to GL_TEXTURE0 wouldn't cause lightmaps to be swapped out, and lightmaps wouldn't need to be switched between TMU memory at runtime, etc etc etc).
If memory serves I think that the Voodoo 2 was roundabout the only 3D card with this kind of weird memory configuration and more or less everything else had (or has) unified video RAM, so that call is both meaningless and unnecessary on anything else. Can't see it doing harm though; just interesting to work through the reasoning behind it.
We had the power, we had the space, we had a sense of time and place
We knew the words, we knew the score, we knew what we were fighting for
We knew the words, we knew the score, we knew what we were fighting for
gles2 is basically gl3core without the requirement to use VBOs. :)
gles1 basically requires you to use ints throughout, which can get messy.
gl1.1 is still too complex for many older cards to support natively.
gl2 is a stepping stone, its for drivers with poor shader performance.
gl3 removes a lot of deprecated/inefficient/slow features.
if you target the features which are still present in gl3 core contexts, you should get better performance, regardless of actual gl version.
the thing about gl1.1 vs gl3, is that gl1.1 builds stuff optimised for the card using extra cpu usage. gl3 code can avoid that extra work. upgrading your drivers/hardware should not mean that old apps will run significantly slower, but if its a more recent card, then it'll at least not be waiting for the card so much, though you'll still spend a lot of cpu time submitting data to the card.
modern drivers are optimised for more recent usage patterns and operating system inefficiencies. there's a lot of overhead thunking between userland and the driver, and you'll see the results of that in your framerate. windows is quite a bottleneck really (I get 1000 more fps in linux than windows), which means that batching many polys before submitting them can be greatly faster than a gl1.1 app would expect. of course, with glVertex, the driver does all the work for you from userland.
when you're submitting 60 verts at a time, you probably don't notice the overhead. when your models are 60,000 verts, you really do start to notice the overhead. :P
gl3 hardware improvements will compensate for additional inefficiencies/bloat within the driver on any given OS.
setting tmu for lightmap uploads means you don't have a texture change as often, both in the main surface texture nor (less common) the lightmap. certain drivers sync with the device for each texture change - texture changes were critisied for being slow, or it could be a copypasta bug.
gles1 basically requires you to use ints throughout, which can get messy.
gl1.1 is still too complex for many older cards to support natively.
gl2 is a stepping stone, its for drivers with poor shader performance.
gl3 removes a lot of deprecated/inefficient/slow features.
if you target the features which are still present in gl3 core contexts, you should get better performance, regardless of actual gl version.
the thing about gl1.1 vs gl3, is that gl1.1 builds stuff optimised for the card using extra cpu usage. gl3 code can avoid that extra work. upgrading your drivers/hardware should not mean that old apps will run significantly slower, but if its a more recent card, then it'll at least not be waiting for the card so much, though you'll still spend a lot of cpu time submitting data to the card.
modern drivers are optimised for more recent usage patterns and operating system inefficiencies. there's a lot of overhead thunking between userland and the driver, and you'll see the results of that in your framerate. windows is quite a bottleneck really (I get 1000 more fps in linux than windows), which means that batching many polys before submitting them can be greatly faster than a gl1.1 app would expect. of course, with glVertex, the driver does all the work for you from userland.
when you're submitting 60 verts at a time, you probably don't notice the overhead. when your models are 60,000 verts, you really do start to notice the overhead. :P
gl3 hardware improvements will compensate for additional inefficiencies/bloat within the driver on any given OS.
setting tmu for lightmap uploads means you don't have a texture change as often, both in the main surface texture nor (less common) the lightmap. certain drivers sync with the device for each texture change - texture changes were critisied for being slow, or it could be a copypasta bug.
What I'm really referring to here is the use of GL_SelectTexture in GL_BuildLightmaps. This is a one-time-only op at startup, and won't actually do anything at all to prevent texture changes at runtime (as the last uploaded lightmap will be the currently bound texture on GL_TEXTURE1, whereas in reality any of the preceding lightmaps may be needed on the first frame).Spike wrote:setting tmu for lightmap uploads means you don't have a texture change as often, both in the main surface texture nor (less common) the lightmap. certain drivers sync with the device for each texture change - texture changes were critisied for being slow, or it could be a copypasta bug.
This usage only makes sense in the context of each TMU having separate texture memory. With unified video RAM it shouldn't matter which TMU lightmaps are bound to at glTexImage2D time. With separate texture memory you'd want to ensure that caches for each TMU are nicely primed in advance of the map running, and have each glTexImage call specifying the texture on the TMU (and therefore in the memory for the TMU) that it will actually be used on.
Also worth noting that texture changes are actually relatively cheap on most hardware these days, but where they really kill you is if they reduce the number of triangles you draw between each change. Sorting is essential, and this is one of the reasons why R_DrawSequentialPoly is one of the most evil things in GLQuake.
I'd love to find an archive of Brian Hook's .plan posts. Carmack's stuff tends to be more high-level, but I'd say there's some solid gold lurking in Hook's.
We had the power, we had the space, we had a sense of time and place
We knew the words, we knew the score, we knew what we were fighting for
We knew the words, we knew the score, we knew what we were fighting for
-
- Posts: 50
- Joined: Mon Jun 08, 2009 4:58 am
Not sure how complete it is (eg if the older ones are missing) but http://www.bluesnews.com/cgi-bin/finger.pl?id=7mh wrote:I'd love to find an archive of Brian Hook's .plan posts. Carmack's stuff tends to be more high-level, but I'd say there's some solid gold lurking in Hook's.
You can select older entries via the dropdown menu on the upper right.
Improve Quaddicted, send me a pull request: https://github.com/SpiritQuaddicted/Quaddicted-reviews
Re:
This was actually a technical requirement of the old Voodoo 2 architecture; in order for multitexture to be used, textures had to be both created and used on the same TMU throughout their lifetime.mh wrote:I believe that the only reason this exists is for Voodoo 2 cards. The 1st generation of these had something like 4MB framebuffer and 2MB per texture unit; texture swapping would have been the norm and I suspect that this was done to ensure that lightmaps always stayed on GL_TEXTURE1 and therefore wouldn't cause anything in the 2MB for GL_TEXTURE0 to be swapped out (and subsequent binds to GL_TEXTURE0 wouldn't cause lightmaps to be swapped out, and lightmaps wouldn't need to be switched between TMU memory at runtime, etc etc etc)..
Carmack's .plan post of Feb 16, 1998 (https://github.com/ESWAT/john-carmack-p ... 8.txt#L357) discusses it:
8 mb or 12 mb voodoo 2?
.....To use the multitexture capability, textures are restricted to being on one or the other TMU (simplifying a bit here).
We had the power, we had the space, we had a sense of time and place
We knew the words, we knew the score, we knew what we were fighting for
We knew the words, we knew the score, we knew what we were fighting for