[Bf-committers] Concerning real-time display

Ρυακιωτάκης Αντώνης kalast at gmail.com
Tue Apr 19 20:31:17 CEST 2011


I've recently taken a peek at blender's viewport rendering code. There are a
few thoughts I'd like to share here and listen to opinions of course.

Right now there are a couple of OpenGL rendering modes for blender: VBO,
GLSL, and Solid mode. There is quite a lot of duplicated code in there and a
few improvements that could be made. In particular there are a few bugs that
relate to VBO mostly to do with multiple materials and textures and not
without good reason.
This discussion is oriented mostly towards VBOs but can be generalized to
simple OpenGL 1.1 vertex arrays. So, let's take a look at what one may do...

First of all, when talking about real time display we must make a bridge
between OpenGL data representation and Blender internal mesh representation.


Central to the speed of drawing is the notion of indices and batches. Each
vertex in a mesh is associated with an index,so we can generate a triangle
by connecting vertices with indices 2,4 and 15 for example. If we are
concerned with rendering time we must also minimize the calls we make to
OpenGL.

VBOs are excellent in this regard. The idea is to prepare an array with
vertex data(called attributes) like position, normal, uv etc and a separate
array containing indices to recreate the faces and send it to OpenGL with
one draw call. This packet of geometry is called batch. Batches in OpenGL
have a few restrictions. For instance, only one GLSL shader can be active
for a given batch so multiple materials have to be separated into multiple
batches or selected through conditionals in the shader. The same applies to
texture images as well. Faces containing different image textures can't be
rendered in the same batch(Recently the array textures extension lifted this
restriction).

So, to summarize the differences between OpenGL and Blender

* For every OpenGL vertex in a VBO one can associate only one texture
coordinate, one normal or generally only one attribute(see vertex color or
tangent for bump maps). One index is associated with one vertex and its
corresponding attributes.

* Blender stores data per face and a few per vertex. A vertex only has one
normal but it can have many UV's(at the seams for instance)and many Vertex
Colors. In blender a vertex index is not enough to get all the data related
a vertex. Moreover, each face in a mesh can have different texture images or
materials associated with it. One batch is not enough to render a mesh with
multiple textures or materials.

So, in order to counter the fact that blender is face-centric and OpenGL is
vertex/batch-centric, the current way blender draws is based on
glDrawArrays. In order to use this OpenGL command, every triangle is written
in a buffer with the proper data. Indices are not used and a lot of data is
duplicated (for a vertex used in 4 polygons we send roughly 4 times the
'same' vertex data to the GPU).

Now, if we were to send data through a command like glDrawElements, using
indices, we could reduce the amount of data sent to the GPU and most
probably viewport rendering times (GPUs use caching schemes to avoid
processing the same vertices again). The requirement is that we need  way to
sort through the data to create a 1-1 correspondence between attributes and
indices.
So, the idea is to introduce a setup step that groups vertices based on
islands (quite similar to the select linked tool).
These can serve as batches for OpenGL and serve a lot of purposes:

* Speed of drawing. Less data sent to GPU, and even further optimizations to
send triangle strips instead of triangles can be made, further reducing the
data sent to the GPU.

* Less duplicated code. Right now there are quite a few branches in the
code, each doing last-minute-setup while with good initial setup, we simply
select the batches we need to render. Bugs are easier to detect. We have one
area in the code for data setup, and data is already formatted for easy
drawing.

So, to highlight the algorithm.

* First group mesh faces by materials (This already happens I think)
* Group faces by textures (Ensures that multitexture drawing works
correctly)
* Group vertices by linked UV's
* Group vertices by vertex colors

To group vertices, we iterate through the faces and for every vertex that
has had multiple UV's or vertex colors, we generate a new vertex and link
the face with the index of the new vertex. This is standard procedure for
game exporters.


More information about the Bf-committers mailing list