Designing the model
The first thing to do when designing a model is to thing what is the purpose of making it. In this case, I want the model to store information about a 3D scene which can then be rendered using OpenGL (QGLWidget). The scene is to consist of some objects, which can be defined using various ways offered by the OpenGL specification.
As Interview models are item based, the first thing to do is to define what an item is to represent. For 3D scenes, an item should represent a single object (3D model). At the beginning a set of attributes (represented as roles in Qt4 MVC implementation) should be defined and then the hierarchy of the model (if it should have one) should be considered.
A 3D entity can have different attributes, like space coordinates, material data, normal vector coordinates, etc. Below is my suggestion of attributes for a simple representation of a 3D object.
- XRole – X coordinate of the object
- YRole – Y coordinate of the object
- ZRole – Z coordinate of the object
- MaterialRole – Material (colour) description of the object
- TextureRole – Material (texture) description of the object
- FlagsRole – A set of GL flags for an object
- TypeRole – Type of object (described below)
- XNormalRole – X coordinate of the end of the normal vector
- YNormalRole – Y coordinate of the end of the normal vector
- ZNormalRole – Z coordinate of the end of the normal vector
- NameRole – object name
- SizeXRole – size in X axis
- SizeYRole – size in Y axis
- SizeZRole – size in Z axis
- Attr1Role – custom attribute 1
- Attr2Role – custom attribute 2
Instead of defining those roles one could use separate columns to store data associated with different attributes but I want to make my model consistant and easy to extend. If a column based representation is ever needed, it is simple to make one using a proxy model (an example will follow in one of subsequent parts of this article).
Almost all roles are easy to comprehend, the only one which may need some explanation is the one which stores the type of the object. I want my model to be able to store different types of objects, like different primitives (cubes, spheres, …) or complex objects defined using features like display lists, points, lines, line strips or quads. Thanks to the type role, it will be easy to implement a renderer which will act differently depending on the object type it has to draw.
A simple list of types may consist of:
- line strips,
- display list,
- light source,
- complex object (a stub type for noting that an item consists of subitems – see below).
Of course more types can be added upon demand. Those roles listed are all custom roles, but some of them can be implemented as the default roles which Qt offers (like the MaterialRole which could be substituted by Qt::DecorationRole or NameRole with Qt::DisplayRole). I will use the default roles in another way – to make some eye-candy for the model – the Qt::DisplayRole will display the set of coordinates of the object and/or the object name, Qt::DecorationRole will show an icon representing the object type, Qt::ToolTipRole will show the object coordinates, etc.
After defining item attributes, the hierarchy of items should be established. As most objects are complex, they consist of subobjects (which can consist of subsubobjects, and so on) and should be represented using subitems. Because of that the model will have a tree structure, where each level will represent a set of all subobjects of the parent object (with the whole scene being the root item of the model).
A sample scene hierarchy is illustrated on the figure below. It has a single light source, a plane, a standalone point, a line and two complex objects – one being made of a four point line strip and a sphere and the other rendered using a display list.
Scene | +-- Light source +-- Plane | +-- Point | +-- Point | +-- Point | +-- Point +-- Point +-- Line | +-- Point | +-- Point +-- Object | +-- Line Strip | | +-- Point | | +-- Point | | +-- Point | | +-- Point | +-- Sphere +-- Object +-- DisplayList
In the next section of the article I will focus on defining the internal representation of the model. In that episode I will show a stub code of the model class which will allow us to compile it and will contain routines to manipulate the internal representation.