6 ms·
> When writing my first OpenGL code, I was stunned by the amount of boilerplate required. Huh, actually the amount of boilerplate required for getting a triang
by datenwolf 10y ago
> When writing my first OpenGL code, I was stunned by the amount of boilerplate required.
Huh, actually the amount of boilerplate required for getting a triangle to the screen with OpenGL is minimal.
- Create a context
- fill a buffer with the triangle vertex data
- load buffer to OpenGL
- create vertex shader implementing vertex to position transformation
- create vertex shader implementing pixel coloirization
- issue draw commands
- rwmj 10y agoI think you missed: - spend a few hours working out why your display window just shows black
- datenwolf 10y ago> - spend a few hours working out why your display window just shows black I hardly ever had this kind of problem… and I'm doing OpenGL programming for almost two decades now. Yes, when implementing a new shader (idea) I often am greeted with a blank window, too. This is where the "stringiness" of OpenGL is actually a huge benefit. See, you don't have to recompile your program just to change things in the shader. In fact in development builds of my OpenGL programs I regularly place a filesystem monitor on each shader source file, so that the shader gets automatically reload and recompiled whenever the file changes. Combine that with a GLSL compiler error log parser (the GLSL compiler will emit helpful diagnostics) for your favourite editor and you can quickly iterate your development cycles. Just to give you an idea of how well this works and how quickly you can develop with OpenGL if you know how to do it properly: Past February our company showed our new realtime videorate 4D-OCT system at Photonics West/BiOS expo. The first day of the expo, about 10 minutes before opening my CEO asked me, how difficult it would be to hack a variance visualization into it. Since we had a developer build of the software on the demo system I could make the changes in-situ in the running program. It took me less than 5 minutes to implement that new display mode shader… from scratch. Considering that even the smallest changes in the program C++ files would still require a at least 10s long linking stage and that after each launch of the program it takes about 2 minutes for the program to go through all the required calibration I couldn't have done it that quickly. ---- For those wondering how to effectively debug shaders: First get the vertex shader working, only then start with the fragment shader. Until the vertex shader doesn't work use the following as fragment shader: out vec4 o_fragcolor; void main() { o_fragcolor = vec4(1.,0.,0.,1.); } i.e. a solid red. For debugging the vertex shader you may introduce some varyings that you pass into the fragment color. Once you've got the vertex shader doing what you want it to do you can tackle the fragment shader. And always remember: Don't link the shader text hard into your program binary. Load them from external files instead and have a way to signal a reload.
- deleted 10y ago[deleted]
- fixermark 10y agoYour advice is sound, if maddening (it's maddening to have to debug a black box; I've hit bugs in shader compilers before that had me tearing my hair out. Things should not be fixable by multiplying a quantity by 1.0 in a sane world ;) ).
- datenwolf 10y agoHa, the things I've seen shader compilers do. One of the funniest (or so I think) was how the NVidia shader compiler messed up its intermediary assembly code: The NVidia GLSL compiler (which is based on the Cg compiler), to this date, first compiles from GLSL into assembly as specified by the GL_ARB__program extensions plus extra instructions specified in the GL_NV__program extensions. Nothing wrong with that. But what's wrong is applying the LC_NUMERIC locale onto floating point literals emitted into the assembly code, because if your system happens to be set to a locale where the decimal separator is a comma (,) and not a period (.) the following assembly stage will interpret the commas as list separators. NVidia's beta drivers of November 2006 for their then newly released G80 GPUs had this very bug (it also happens that I did report it first, or so I think); NVidia got the report just in time to apply an in-situ workaround before the next non-beta driver release (at least so I was told back then).
- vvanders 10y agoThere's nothing intrinsic to graphics work there, you're just talking about content-driven development which is common in a bunch of domains. Your not hitting the black-screen since you've been doing it self-admitted for 20 years. Kudos, good for you. The problem is getting fresh-blood in who have a hunger to learn but don't have a deep understanding of shaders, pipelines, vertices, etc. It's really easy to make a trivial mistake in that boiler plate(I've seen someone fight something for hours until they thought to turn of culling, they just had their winding wrong). Case in point from one of the foremost figures in the domain: https://twitter.com/id_aa_carmack/status/370205518532329472 https://twitter.com/id_aa_carmack/status/370205518532329472 PIX was about the most sane step in the direction of fixing this, sadly tools seem to have slid backwards of late.
- xigency 10y agoAnd yet you've just described a decent amount of boilerplate. The fact that future iterations of OpenGL and OpenGL ES have nuked the fixed function pipeline is sort of annoying. I'm not saying there should be more codepaths in the implementation, but if there were a default compiled fixed function vertex shader and fragment shader, it would be helpful. What you've just described for rendering one primitive includes compiling two shaders, linking arguments, and specifying byte arrays before issuing commands, when this task used to be as simple as: glBegin(GL_TRIANGLES); glColor3f(1.0f, 0.0f, 0.0f); glVertex3f(0.0f, 1.0f, 1.0f); glColor3f(0.0f, 1.0f, 0.0f); glVertex3f(-0.866f, -0.5f, 1.0f); glColor3f(0.0f, 0.0f, 1.0f); glVertex3f(0.866f, -0.5f, 1.0f); glEnd(); Being able to draw a triangle in eight lines of code is much more encouraging to someone wanting to make a 3D game for mobile or the web than an estimated 50 lines, including two shaders they had to borrow from a textbook. I would understand if immediate mode were gone, which might be better regardless. Still, things should be as simple as a glDrawArrays call without compiling shaders. Not to mention, when working as a solo game developer, shaders feel like an orphan between artists and programmers.
- mattbee 10y agoIt's staggering! The above is immediate-mode code which is what's gone and that's how a lot of people learned OpenGL 1-3. Anton Gerdelans's tutorials are the best I've found and just look at how much typing there is: Code: https://github.com/capnramses/antons_opengl_tutorials_book/blob/master/00_hello_triangle/main.c https://github.com/capnramses/antons_opengl_tutorials_book/b... Explanation: http://antongerdelan.net/opengl/hellotriangle.html http://antongerdelan.net/opengl/hellotriangle.html Once you can get through that mess, the effort/reward ration seems to be a bit more incremental, but the triangle program a pretty good illustration of that first cliff, and how much it's grown.
- datenwolf 10y ago> when this task used to be as simple as: a) Immediate Mode has been out of fashion for since before the turn of the century. Even the good old NVidia GeForce2 of 1998 already had OpenGL extensions that are essentially vertex buffer objects; you can in fact use the GL_ARB_vertex_buffer_object extension on a GeForce2. If you don't believe me, I'm currently headed to my mother's and I have a old box stored in her cellar with a GeForce2 in it; I could give interested parties a SSH into it (you just have to live with a old Gentoo installation that I didn't touch for some 10 years or so). b) There's a certain complexity cutoff where the whole shader loading boilerplate plus shader code is less, than what it takes to setup an equivalent fixed function pipeline setup. Making an educated estimation I'd say, that the break even point is, when enabling a register combiner on two textures, one a cube map, the other a normal+shininess map, setting DOT3 combining of normal with vertex secondary color (for normal mapping), directing the normal map into the cubemap texture coordinate lookup and fading between reflection and dull shader based on shininess. Sounds complex? Indeed it is, but keep in mind that this kind of thing was already possible with the GeForce3 (at least, I think it may even work on the GeForce2, but after over 14 years since writing the last time a program targeting it, I'm a bit shaky on the details). Anyway, to set up this kind of register combining you'd need between 4 to 5 calls of glTexEnvi per texture. Another 3 glTexEnvi calls for setting up the secondary color muxing mode and another 3 calls for setting the final stage fading mode. Add to that the hours of twisting your brain to figure trying to wrap your mind around all the relevant state switches in the register combiners. With shaders you simply write down what you want.