This step reviews how to create different levels of detail for the model. Drawing objects in the scene with lower levels of detail reduces the polygon count, and let's the scene get drawn more quickly. This is particular useful when dealing with large models, or trying to maintain a constant framerate.
![]() | ![]() | ![]() |
There are two main ways to create LODs: implicitly and explicitly. The implicit method involves setting the 'lod' HOOPS/3dGS Rendering_Options along with the desired 'lod options', and then performing a regular update. LOD creation happens 'behind the scenes' using this method. However, we'll review the explicit method since it give a clearer picture of how LODs work.
Let's first add a new menu item called 'LMV Tools' to our 'Visualize' application, and then add a pulldown item called 'Build LODs'. We'll map it to a new view method called 'OnBuildLODs' which will call a portable build LOD function that we'll place in HVisualView:
void CVisualizeView::OnBuildLODS(){((HVisualizeView *)m_pHView)->OnBuildLODS();}
The explicit lod-generation method involves:
Here's the BuildLODs sample code:
First, we find all the shells in the model:
void FindAllGeometry(int * current_count, HC_KEY **keys){static char type[128];static char full_path_name[MVO_BUFFER_SIZE];static int i;static HC_KEY * new_keys;static HC_KEY key;HC_Begin_Contents_Search("...", "shells, includes");while(HC_Find_Contents(type, &key)){if(streq(type, "include")){HC_Show_Include_Segment(key, full_path_name);HC_Open_Segment(full_path_name);FindAllGeometry(current_count, keys);HC_Close_Segment();}else{new_keys=new HC_KEY [(*current_count)+1];for(i=0; i<*current_count; ++i)new_keys[i]=(*keys)[i];delete [](*keys);new_keys[*current_count]=key;(*current_count)++;*keys=new_keys;}}HC_End_Contents_Search();}void HVisualizeView::OnBuildLODS(){int count=0;HC_KEY *keyarray=0;HC_Open_Segment_By_Key(GetModelKey());FindAllGeometry(&count, &keyarray);HC_Close_Segment();
For each shell, we allocate the necessary arrays, and 'show' (query) its contents:
for (int shellnum = 0; shellnum < count; shellnum++){int plen, flen, plen_optimized, flen_optimized;HC_KEY shellkey = keyarray[shellnum];HC_Show_Shell_Size(shellkey, &plen, &flen);HPoint *plist = new HPoint[plen];int *flist = new int[flen];HPoint *plist_optimized = new HPoint[plen];int *flist_optimized = new int[flen];HC_Show_Shell(shellkey, &plen, plist, &flen, flist);
We open each shell, and create/insert 2 LOD levels using a falloff level of 10% and 5%. We also use the 'nice' LOD algorithm, and only generate a LOD if there are more than 50 points in the shell:
HC_Open_Geometry(shellkey);for (int j=1;j<=2;j++){HC_Open_LOD(j);HC_Flush_Contents(".", "everything");switch(j){case 1:if (plen > 50){HC_Compute_Optimized_Shell(plen, plist, 0, flen, flist, "lod = 10%, lod algorithm = nice",&plen_optimized, plist_optimized, &flen_optimized, flist_optimized, 0, 0);HC_Insert_Shell(plen_optimized, plist_optimized, flen_optimized, flist_optimized);}break;case 2:if (plen > 50){HC_Compute_Optimized_Shell(plen, plist, 0, flen, flist, "lod = 5%, lod algorithm = nice",&plen_optimized, plist_optimized, &flen_optimized, flist_optimized, 0, 0);HC_Insert_Shell(plen_optimized, plist_optimized, flen_optimized, flist_optimized);}break;}HC_Close_LOD();}HC_Close_Geometry();
Now we just have to clean things up:
delete [] plist;delete [] plist_optimized;delete [] flist;delete [] flist_optimized;}delete [] keyarray;Update();}
Test the new lod building function by reading in an assembly-type dataset. We suggest reading in /datasets/hsf/cad/train_chassis.hsf from the datasets package (available for download from the Tech Soft 3D Developer Zone).
Now that we've created LODs, let's see what they look like. The HOOPS/3dGS lod switching functionality let's you 'clamp' to a particular LOD level. This forces the system to draw the object using the geometry representing that level. This is useful for demonstration/testing purposes (to see what a particular LOD levels look like), and can also be useful when trying to maintain a constant framerate. (Constant Framerate is discussed in the next section of this tutorial.)
Let's add 3 new GUI buttons titled 'Switch to LOD 1', 'Switch to LOD 2' and 'Switch to Original' that map to the following view methods and call matching methods in HVisualizeView:
void CVisualizeView::OnLOD1(){((HVisualizeView *)m_pHView)->OnLOD1();}void CVisualizeView::OnLOD2(){((HVisualizeView *)m_pHView)->OnLOD2();}void CVisualizeView::OnLODOriginal(){((HVisualizeView *)m_pHView)->OnLODOriginal();}
To clamp, we set the lod Rendering_Options to 'on' (to tell HOOPS to draw the scene using LOD logic), and we set the lodo Rendering_Option to '(clamp = [level], fallback = coarsest)'. The fallback setting tells HOOPS/3dGS what to draw if the requested LOD level does not exist. The 'coarsest' options tells HOOPS to draw the roughest LOD available. For example, if we clamped to LOD level 2 and none existed, it would then try to fallback to LOD level 1. If that didn't exist, then it would fallback to the original shell. We'll also set the render mode to 'flat', which will help us more easily see the faceting of the LODs, and confirm that we're seeing a LOD representation.
The code for OnLOD1 would look like:
void HVisualizeView::OnLOD1(){// render in flat shaded mode for lodsRenderFlat();HC_Open_Segment_By_Key(GetSceneKey());HC_Set_Rendering_Options("no lighting interpolation, lod = on, lodo = (clamp = 1, fallback = coarsest)");HC_Close_Segment();Update();}
Go ahead and add the necessary code for HVisualizeView::OnLOD2. We'll also add a method to turn LODs off and drawn the original geometry. For this method, we turn shading back on, and turn LODs off:
void HVisualizeView::OnLODOriginal(){// render gouraud shaded mode for original LOD levelRenderGouraud();HC_Open_Segment_By_Key(GetSceneKey());HC_Set_Rendering_Options("lighting interpolation = on, lod = off");HC_Close_Segment();Update();}
Now read in train_chassis.hsf, build LODs, and clamp to each of the 2 LOD levels. Then select the 'original' level. HOOPS/3dGS edges/lines are on by default, but you could turn these off by making the following setting in the view's Init() method:
void HVisualizeView::Init(){...HC_Open_Segment_By_Key(m_SceneKey);HC_Set_Visibility("edges = off, lines = off");HC_Close_Segment();}
For more detailed information on how to create LODs and instruct the user to either clamp or automatically choose LODs when redrawing, refer to Section 6.2 of the HOOPS/3dGS Programming Guide, as well as the lod and lod options sub-options of ::Set_Rendering_Options.