Good segment organization is critical, and is a primary differentiator of good HOOPS/3dGS-based applications from bad ones. The most common cause of rendering performance problems is poor HOOPS/3dGS database structure.
HOOPS/3dGS segments primarily organize attributes, rather than geometry. It is a common mistake for programmers to structure their segments to mimic the organization of the geometry in a scene. Although this structure works, it can slow rendering and can even make your program more difficult to write.
For example, imagine that you are drawing a checkerboard with white and black squares (ignore for a moment that the best way to draw a checkerboard would be with a mesh). The squares cannot all be in a single segment, because they do not all share the same color-attribute value. One way to organize the database is to put each square of the board in its own segment, but that requires 64 different segments. A more efficient organization is to use two segments, and to put all the black squares in one segment, and all the white squares in the other. This structure uses fewer segments, is faster to render, and can make it easier to change attributes (for example, to change all the white squares to red).
The best way to design a HOOPS/3dGS database is to structure it based on like attributes. This helps maintain attribute coherence and minimizes 'context-switching', which refers to resetting attributes on the underlying device-driver. Organizing the database is a two-step process. The first step is to put into the same segment all geometry that has the same color, transformation, and other attributes. Some attributes, such as transformations, will naturally tend to follow the organization of the geometry in a scene; if they do, then your segment organization might follow the organization of your geometry, but it will not be dictated by that organization. In addition, if you have a group of geometries that will be deleted together, you can put them in their own segment to make deleting them easier.
The second step is to build an inheritance hierarchy for segments with similar attribute settings. For example, if, in the resulting database, there are two segments with nearly identical attribute values, then you should give them a common parent segment and should set the common attributes in the parent. Notice that organizing an attribute hierarchy is just like designing a good class hierarchy in C++. Continue until your attributes are well organized - the goal is to structure your database so that you can change any attribute that affects a group of geometry by changing it in only one place. For example, if a group of objects will normally move together, give the group a common parent so that you can change the transformation in one place. If two attributes conflict on how they want the database to be organized, consider putting one of the attributes into a style segment.
Many developers who evaluate HOOPS/3dGS are aware of the above information, but quickly design a prototype or proof-of-concept that does not take these pratices into account. In these situations, it is important to spend the time to correctly rearchitect the HOOPS/3dGS database early on, since it will be considerably more difficult to do so later.
In some cases it may be challenging to create an efficient segment tree due to the complexities of attribute matching/hashing, or a pre-existing HOOPS scene-graph created elsewhere may have been read in. Alternately, your scene-graph may have been reasonably organized but was not as optimal as it could have been, because of a desire to facilitate object selection, editing, etc.... While we always encourage developers to follow the guidelines above to create a reasonable graphics organization of the data (not to mention that the HOOPS Gods will always shudder if they ever see a segment tree with a single polyline per segment), the Optimize_Segment_Tree method provides support for automatic scene-graph optimization. It provides a wide variety of sub options to remove modelling matrices, merge items based their attributes, merge shells, etc... Depending on the original scene-graph organization and the selected options, enormous performance gains can be had after optimization.
To create a more efficient segment tree, Optimize_Segment_Tree will likely alter the structure and organization of your scene graph significantly. For example, if the "merge shells" option has been set, then individual shells may have migrated to regions within a larger shell. If the "instance shells" option is on, Optimize_Segment_Tree will take any shells which are identical except for a translation and delete all but one copy from the segment hierarchy and replace the deleted ones with a geometry reference and a modelling matrix. As a result of these changes, existing functionality such as selection/query that relied on the original segment/geometry keys might not be valid anymore. HOOPS/3DGS provides the function Show_Optimized_Mapping to address this issue by allowing you to map a piece of geometry between an old segment tree and a new segment tree (or vice-versa). Another consequence of the collapse and/or removal of segments during the optimization process is the loss of information in user options. If you wish to keep segments with user options in tact, set the "preserver user options" option to on. Note, when this option is on, the effectiveness of Optimize_Segment_Tree is significantly reduced especially for models with a large number of user options. By default, "preserve user options" is off.
In some applications, it may be necessary to preserve the model data in its original form. For these situations, using Optimize_Segment_Tree is not a realistic option. HOOPS provides another way to optimize rendering via the static model option in Set_Heuristics. When this option is set on a particluar segment, instead of replacing that segment and its children with an optimized tree, HOOPS creates a parallel optimized segment tree in another part of the database. Additionally, if you have also set the model type option in Set_Heuristics to 'lmv', then the optimized segment tree will be first organized spatially and then by attributes. At render time, HOOPS uses the optimized segment tree instead of the original data. When the static model option is used in conjunction with segment level display lists, it can improve rendering performance significantly.
The optimized tree is highly flexible and can adapt to changes such as segment/geometry deletion as well as geometry edits performed via calls to any of the Edit_* HOOPS/3dGS functions. However, there are limitations. Any other changes made to the segment or any of its children, such as the adding of geometry, will cause the entire optimized segment tree to be rebuilt against the new data. This process can take up significant computing time.
Whenever a the static model needs to be assembled or reassembled, you might experience a lag in performance depending on your system's configuration. To facilitate the creation of the static tree, you can call Control_Update with the compile only option. This option tells HOOPS, on the next update, to skip all drawing. Instead, it will doing nothing but assemble draw information. Such updates will generally be faster to process, and depending on the data and platform can sometimes be orders of magnitude faster.
HC_Open_Segment("."); HC_Set_Heuristics("static model=on"); HC_Control_Update("compile only"); HC_Close_Segment(); HC_Update_Display();
This option can also help you twofold if you additionally have display lists set to segment. However, due to the possible impact on application performance, we suggest that you carefully consider where you set this heuristic.
There are three main factors that determine how much of a performance gain can be had: the size of your model, its original segment organization and the usage patterns of your application. For instance, if your application has a viewing mode that allows the end-user to examine (zooming, rotating and panning the camera) a model without altering it. You can successfully use the the static model to increase performance. Begin by creating a 'view' segment. This segment would include a 'model' segment which contains all your model data under it. For the 'model' segment, enable the static model option. Then you can set and modify camera and other high-level view attributes on the 'view' segment without affecting a change to the model data.
In general, we recommend that you try this option with a number of representative models from your data set along with common usage patterns to determine if using the static model option will benefit your application.
It is much more efficient to refer to the HOOPS/3dGS segments by key (using, for example, Open_Segment_By_Key) than to do so by name. This is discussed in Section 1.3.5.4. Accessing a single segment or just a few segments by name after an operation may not seem very costly, but performing numerous segment accesses by name within a loop (while building up the database after loading a model, for example) will be extremely costly.
There are a few commands that take a segment name, and that cannot be used with a key. In these few cases, you have two alternatives: you can open the segment using Open_Segment_By_Key and then refer to the current segment as ".", or you can manufacture a segment name from the key. To manufacture a segment name from a key, you create a string of the form "@hex-value" - an at sign followed by the ASCII representation of the hexadecimal value of the key.
Update_Display_Timed, a variant of the HOOPS/3dGS function Update_Display, instructs HOOPS to perform a 'time-bounded' update. In this case, HOOPS/3dGS will redraw as much of the scene possible within the specified amount of time.
This function is especially useful when you want to maintain a constant frame rate. Used in conjunction with the culling heuristic, this is a powerful way to control the responsiveness of your application while still maintaining the visual integrity of your scene. When the culling heuristic is enabled, you can determine what objects in the scene will be rendered within the time frame given. To learn more about how to set proper values for the culling heuristic, please see the programming guide section on culling.
Note that Update_Display_Timed has different behavior than Update_Display especially for shadow map generation. During a called to Update_Display_Timed, if a new light is introduced and the shadow map rendering option is enabled, HOOPS will generate the shadow map regardless of the time. In subsequent calls to Update_Display_Timed, shadow maps will not be regenerated. If your scene has camera relative lights and/or the shadow map supoption 'view dependent' is enabled, this will affect your scene visually as no "new" shadow maps will be generated. To force regeneration of shadow maps, you must call Update_Display.
HOOPS/3dGS is not thread safe by default. This means that HOOPS/3dGS functions cannot safely be called from different threads. Furthermore, Update_Display is a blocking function. The user must wait for it to finish before further editing the database, or performing additional updates of other drivers.
However, you have the option to make HOOPS/3dGS thread-safe and use it in a multi-threaded application by performing the following steps:
The multi-threading System Option must be enabled with a called to Define_System_Options. Now, HOOPS/3dGS is completely thread-safe. This allows different threads to call any HOOPS/3dGS functions at any time. Its biggest benefit is that shared parts of the segment tree can be modified by any thread at any time.
HC_Define_System_Options("multi-threading = full");
Depending on the function call, HOOPS/3dGS may set read or read/write locks for the entire segment tree.
All driver instances should have the isolated Driver Option enabled via Set_Driver_Options. From then on, you should call Update_One_Display for each driver instance instead of Update_Display.
HC_Set_Driver_Options("isolated = on");
When Update_Display is called, HOOPS traverses the entire segment tree and updates all driver instances, while Update_One_Display instructs HOOPS/3dGS to perform an update on a single driver instance. Setting the isolated option on a driver instance removes the driver instance from the full list of drivers that gets updated in a call to Update_Display. This is important, because if we've already commenced the update process for a hardcopy driver on our separate thread by calling Update_One_Display, we don't want to re-update after calling Update_Display to perform our display update. As a result, this option should be set before any updates are called in your system.
Next | Previous | Index |