This chapter is on renderer design, that is, designing the layer of a 3D engine that sits between the underlying rendering API, like OpenGL or Direct3D, and the rest of the engine. Since my experience is largely with OpenGL, the chapter focuses on OpenGL, but it still mentions Direct3D in many places for comparison. Although I'd love to fill an entire book on the topic (hmm), the chapter is only 70 pages, so it requires some previous experience with OpenGL or Direct3D, as does our book in general.
As I said a while back, this is the third time I've designed such an abstraction layer, so much of my advice is battle tested. I've learned to favorite ease of use and flexibility over performance, although I mention where performance can be improved, perhaps only marginally in the grand scheme of things, at the cost of something else.
The major components of our renderer are shown here:
The highlights of this chapter include:
- Motivation for a renderer layer: ease of development, portability, flexibility, robustness, performance, additional functionality. I can't come up with a reason not to do it except for "hack something together as fast as possible."
- Big picture: the device [code] and contexts [code].
- State management: global render state vs. state objects [code], draw state [code], clear state [code], sorting by state.
- Shaders: compiling and linking [code], built-in constants [code], vertex attributes [code], uniforms [code], automatic uniforms [code], and shader caching [code].
- Vertex data: vertex buffers [code], index buffers [code], vertex arrays [code], meshes [code], creating vertex arrays from meshes [code].
- Textures: read and write pixel buffers [code], 2D textures [code], samplers [code], texture units [code].
- Framebuffers [code].