The Level Of Detail avoids to display a far object with lot of details. In fact, if an object is far, we can't see the complexity of the object. So the aim of the LOD methods is to decrease the complexity of the object depending of the distance on the point of view.
Ldraw uses a basic LOD: many objects may use two different resolutions (it concerns cylinders and curved surfaces). On the picture, meshes of stud are more detailed in the second case. The LDraw format file has been created before the 3D evolution in computer sciences, so it considers non smoothed primitive. With this technical limitation, if you want great visual result, you need to increase the number for primitives. So using smoothed surface may resolve the using of detailed meshes. Next, the Ldraw format is a tree structure. Each file contains an average of 15 primitives (quads, triangles, lines) and a list of links to other files. This structure is convenient if you have memory limitation but today graphical cards prefer big meshs than lot of little parts of an object. The program wastes time during tree traversal, transformation selection and culling. The best way is certainly to merge the object whose the memory size is relatively small. So the culling time is insignificant and the global time is lower even with a high resolution.
The screen-shots show that we obtain speed-up of 25 and 33 for respectively the low and high resolution.
low resolution non-merged: 10.4 + 4.5 = 14.9ms
low resolution merged: 0.2 + 0.4 = 0.6ms
high resolution non-merged: 29 + 14.2 = 43.2ms
high resolution merged: 0.2 + 1.1 = 1.3ms
Three points needs to be implemented:
LDraw format proposes two type of line (line and optional line) which are merged. These type of line need to be splitted to use them correctly.
The second point concern the color, it exists two type of objects: the monochrome parts and the part with motifs (patern). Commonly, monochrome part use the color 16 for each primitive. So color mechanism don't need to be implemented as a color vector. But for patern part, object should be splitted to separate monochrome color and motif.
The third point, concern the propagation of the color during the merge. An color indexes vector exists but we don't use it because there are difficulty which the color 16. During the merge, the color 16 may needs to be replace by an other color and I'm sceptique about the interrest to use indexes vectors to group colors.
From the application point of view, we need to create a mechanism to exclude a part of the object during the merge. Many times, we will need to separated parts of an object (for example: a door need to be be separate from an house to allows interaction with the door).
A few years ago, my sister given me a wooden dinosaur skeleton. After some thinkings, I have chosen to make an original thing. I don't know if it's really original or not, but I have imagined that the skeleton shines in the dark. Nevertheless, my aim was to avoid to illuminate nearby objects. So I have used fluorescent paintings on the bones which and I have lighted up the dinosaur with ultra-violet light. This is absorbed by most of the material and it reflects on fluorescent objects.
I have bought a set of four fluorescent paintings (yellow, green, blue and red/orange). If my first intention was to use an unique color, I have hesitated to chose one of them. I was worried, because I couldn't predict the result: yellow and green colors seem me too common, blue and red might be too dark. So I have used green, red and blue. Now, I think blue color is the worst choice because difficult to see.
The base is a wooden box modified and painted with metallic color. I have installed four LEDs with reflectors on each corner. I have added a special plaster to create a ground with volcanic appearance. This is a plaster for model railroading with a granite texture.
The electronic is composed of a micro-controller, a voltage regulator and diodes. I have used Pulse-Width-Modulation to obtain a smooth evolution of the light intensity.
This third post concerns many points of a LDraw Loader with OpenSceneGraph Library. OSG has plugins with read different format. Each plugin is related to a file format. OSG offers to create customized loader plugins. To be honest, I don't know how are constructed all formats of different 3D models. OBJ format need to read a file with the material properties and I'm not sure that it exists 3D model format which use more complex tree structure. So the LDraw format is special, made of repetitive patterns, and it needs to load many files to complete a model. A file which needs to load a file which needs to load a file ...
For the LDraw loader, I don't want use recursive algorithms because bugs may easily appear. The second point, I need to keep all of the loaded file in memory and avoid to load many times the same pattern. I think it exists in OSG a mechanism to avoid this but I'm not sure of its use. So I have chosen to have a list of models and I have split the loading process into 2 parts: the loading of the data from a file and a mechanism which links models. So when the program load data, it creates a geometry model and stores the name of the model. Next, the model is put in the models list. During the second step, for each loaded model, the program reads the name of children. If the file is already loaded, it creates a link to the corresponding model, else it loads the file and store it in the queue of the list of models. This system is easy to implement but I don't know if it is the best method. Nevertheless, it appears that LDraw models are a support to avoid to recreate model and I will use an another format in my future applications.
A second difficulty concerns a strange choice about the Back Face Culling. The BFC avoids to display faces which aren't visible by the camera. In fact, it is interesting for speed gain during rendering. There are two modes: Clockwise and Counter-Clockwise. LDraw use CCW by default but can use CW and many time a subpart of a model need to invert the BFC mode. For example, to create a hollow cylinder, the author need use twice a cylindrical surface: an external surface and an internal surface. The two surfaces correspond to the same model with a different scale. If the BFC mode is the same for all surfaces, a camera in the center of the hollow cylinder will display no one of the surfaces. So the author of the part needs to invert the BFC of the internal surface. In the LDraw format, the Meta-Command 'INVERTNEXT' allows to change the BFC of the next submodel. I have chose to duplicate the model and flip all geometries and submodels. The new model is registered to the models list with the suffix '_INVERT'. My main use of the BFC concerns the direction of the normal vectors (for light reflexion). There is an another problem with BFC: if there are a negative scale for a submodel (the determinant of the transformation matrix is negative), BFC need to be inverted. So there are two types of inversion: an inversion of a model and a inversion due to transformations (translate, rotate, scale). An inverted model has inverted normal but transformation may change BFC but not normals. For display a brick as an group of submodel, I prefer deactivate the BFC. When I will merge all geometries of a brick in a unique object, it will be possible to reactivate BFC.
In the next post, I will talk about the colors and the Level Of Detail. Currently, only a basic LOD is implemented. This corresponds to a Ldraw specifications for the resolution mesh of a curved surface (as cylinders).