TGLRenderer
class does
the basic OpenGL rendering of VRML nodes.
“Basic” rendering means that this class is not supposed to
choose the order of rendering of VRML nodes.
This implicates that TGLRenderer
is
not responsible for doing optimizations that
pick only some subset of VRML nodes for rendering
(for example, only the nodes visible within the camera frustum).
This also implicates that it's not responsible for arranging
the rendering order for OpenGL blending, see
Section 6.4.1, “Material transparency using OpenGL alpha blending”.
In fact, it doesn't set any OpenGL blending parameters
(aside from setting colors alpha values as appropriate).
This limitation is done by design. A higher-level routines will internally use an instance of this class to perform rendering. These higher-level routines should choose in what shapes to render, and in which order. In the next Section 6.4, “VRML scene class for OpenGL” we will get familiar with such higher-level class.
The way to use TGLRenderer
looks
like this:
First you must call
Prepare
method for all theState
instances that you want to later use for rendering. You can obtain suchState
instances for example by a traverse callback discussed earlier in Section 3.6, “Traversing VRML graph”. The order of callingPrepare
methods doesn't matter — it's only important for you to prepare all states before you will render them.For example
Prepare
calls may load textures into OpenGL, and triangulate outline fonts (used by VRMLText
andAsciiText
nodes).You are free to mix
Prepare
calls with any other rendering calls to OpenGL. This doesn't matter, asPrepare
only prepares some resources, without changing OpenGL state. You cannot delete yourself any resources (texture names, display lists, buffer objects etc.) reserved insidePrepare
calls. A properly written OpenGL program should always allocate free resource names using calls likeglGenTextures
anyway.Call
RenderBegin
to start actual rendering. This will set up some OpenGL state that will be assumed by further rendering calls.If
Attributes.PreserveOpenGLState
, this also does a push of OpenGL attributes stack, so that everything can be restored later byRenderEnd
. Unfortunately, this is quite costly operation, and it's often not needed (when you don't do any custom OpenGL rendering), soAttributes.PreserveOpenGLState
is false by default.Then you should call
RenderShape
for each VRML/X3D shape that you want to render. As mentioned earlier, all the shapes have to be previously prepared by aPrepare
call.Finally after you rendered all your shapes, you should call
RenderEnd
.Between
RenderBegin
andRenderEnd
you are not allowed to change OpenGL state in any way except for calling otherTGLRenderer
methods. Well, actually there are some exceptions, things that you can legitimately do — these include e.g. setting enabled state of OpenGL blending. But generally you should limit yourself to calling otherTGLRenderer
methods betweenRenderBegin
andRenderEnd
.
Of course the scenario above may be repeated as many times as you want.
The key is that you will not have to repeat Prepare
calls each time — once a state is prepared, you can use it in
RenderShape
calls as many times as you want.
If you will not need some state anymore then you can release some
resources allocated by it's Prepare
call
by using UnPrepare
or UnPrepareAll
methods.
Note that TGLRenderer
doesn't try to control whole OpenGL state. It controls only the state
that it needs to, to accurately render VRML nodes. Some OpenGL
settings that are not controlled include:
global ambient light value (
glLightModel
withGL_LIGHT_MODEL_AMBIENT
parameter),polygon mode (filled or wireframe?),
blending settings.
So you can adjust some rendering properties simply by
using normal OpenGL commands. Also you can transform rendered
VRML models simply by setting appropriate modelview matrix
before calling RenderBegin
. So rendering
done by TGLRenderer
tries to cooperate
with OpenGL nicely, acting just like a “complex
OpenGL operation”, that plays nicely when mixed with other OpenGL
operations.
However, for various implementation reasons, many other
VRML rendering properties cannot be controlled by just setting
OpenGL state before using RenderBegin
.
Instead you can adjust them by setting Attributes
property of TGLRenderer
.
Often when you render various VRML models, you will
use various TGLRenderer
instances. But still
you want those TGLRenderer
instances
to share some common resources. For example, each texture has to
be loaded into OpenGL context only once. It would be ridiculous
to load the same texture as many times as there are VRML models
using it. That's why we have TGLRendererContextCache
.
It can be used by various renderers to store common resources,
like an OpenGL texture name associated with given texture filename.
Things that are cached include:
Fonts display lists.
Texture names. This way you can make your whole OpenGL context to share common “texture pool” — and all you have to do is to pass the same
TGLRendererContextCache
instance around.Shape information: arrays and VBOs mentioned in previous chapter.
By default, each TGLRenderer
creates and uses his own
cache, but you can create TGLRendererContextCache
instance explicitly and just pass it down to every OpenGL renderer that
you will create. All higher-level objects that use TGLRenderer
renderer allow you to pass your desired TGLRendererContextCache
.
And you should use it, if you want to seriously conserve memory
usage of your program.
Also note that when animating, all animation frames of given animation
object (TCastlePrecalculatedAnimation
instance, that will be described
in details in Chapter 7, Animation) always use the same
renderer. So they also always use the same cache instance, which already
gives you some memory savings thanks to cache automatically.
Historically, we used to have many rendering routines for various nodes.
This turned out to be extremely cumbersome to maintain.
The new "geometry arrays" approach unifies this, translating every
shape to only a couple of primitives that map nicely to OpenGL
(triangles, quads, quad strips etc.).
The "geometry arrays" are also be used to implement
TShape.LocalTriangulate
and
TShape.Triangulate
.
Thus, rendering and triangulating is nicely unified.
We also have an alternative, debugging renderer that
will be used if you define USE_VRML_TRIANGULATION
symbol for compilation of GLRenderer
unit. Each node will be triangulated
using TShape.LocalTriangulate
method
(mentioned earlier in Section 3.7.2, “Triangulating”)
and each triangle will be passed to OpenGL. This is a very limited rendering
method, only to show that TShape.LocalTriangulate
works correctly:
It's slower than normal rendering through arrays and VBOs.
Things that are not expressed as triangles (
IndexedLineSet
,PointSet
) will not be rendered at all.It lacks some features, because the triangulating routines do not return enough information. For example, only the first texture unit gets correct texture coordinates, so multi-texturing doesn't work (correctly).