Build Better Software. Faster.
Visit our company site at: www.techsoft3d.com
 

White Papers Index

Creating Optimal HOOPS Stream Files
Gavin

Introduction

The HOOPS/Stream Toolkit provides a set of tools that enable a developer to create and read HOOPS Stream Files (HSF). The developer provides to the toolkit a node within a HOOPS Scene Graph which the toolkit either creates or streams HSF data to or from. When the toolkit is creating a file it creates a stream of data containing the contents of the HOOPS/3dGS database from that node. The toolkit also provides facilities to the developer to receive and interpret HSF data in a piecemeal fashion. These facilities complement the functionality most UI tools provide to load data asynchronously into an application.

It is also important to note that developers may also easily include their own application data within the stream file. This data can then be streamed and queried with the other graphical data.

One of the most important issues when adding streaming functionality to your application is to ensure that the data you are streaming, HSF data in this case, is constructed optimally. The purpose of this paper is to outline the issues involved and the different functionality the toolkit provides to solve these issues.

HSF Structure

Let's start by reviewing the structure of a HSF. A HSF is a stream of binary data which you can create and query the contents of via the Stream Toolkit. Both the HSF data and the toolkit are multi-platform thus enabling developers to stream the same HSF data on different platforms.

In general, the HSF data stream consists of four parts:

1. Scene Graph definition with Bounding Box information

The very start of the file contains a definition of the scene graph and its attribute information; this attribute information includes the bounding box information of all objects in the scene. Among other things, this bounding box information is used to correctly position the camera for the first update.

2. Levels of Detail

Levels of Detail (LOD) are polygon-decimated versions of the facetted objects within the scene. Developers have full control over the number of levels that are generated, the percentage of fall-off between levels, etc. and these options are set via controls exposed in the HOOPS/3dGS. The Levels of Detail are placed immediately after the segment hierarchy. As they are received they are placed into their appropriate node in the scene graph.

3. Original Data

The original, full resolution of the 2D/3D data is placed after the levels of detail. For the optimal balance between streaming speed and visual quality the toolkit provides a number of options on how the Levels of Detail and the original data are ordered within the file. In certain cases this will result in the original data and the LOD levels being mixed in together. Control over how this is given to the developer as the correct balance may vary from application-to-application or model-to-model.

4. File Dictionary

A file dictionary is placed at the end of the HSF, which lists the position of every object within the data stream. This helps developers writing server side logic which could be used for a variety of reasons including view-dependent streaming. One particular use is when you want to only load in a small portion of the scene, or only bring in the coarsest LOD of objects within the scene (in this case streaming and rendering would improve significantly). By utilizing the dictionary a user could then interactively choose which objects they wish to load the full resolutions of. We refer to this process as "sweetening" objects in the scene.

Note, user-data can be stored either at the start or end of the file or with specific objects within the scene.

Creating Optimal HSFs

Since the HSF data is typically being transmitted across a network (Internet or Intranet) where bandwidth may be limited, faster transmit times are ensured by making the data stream as short as possible. Another priority is to get enough information to the user in the shortest time possible so he can quickly begin navigating a meaningful representation of the scene. One of the primary benefits of streaming is that you can begin to receive and interpret data prior to the entire file being transmitted. Compressing the data and/or eliminating unimportant objects from the stream helps keep the stream small, while creating simplified versions of the objects and ordering them within the file will allow the most important information to arrive first and thus allow the user to quickly begin intelligently navigating the scene.

Accessing the different functionality in the toolkit to help you create optimal HSFs is done by setting the flags parameter of your call to HTK_Write_Stream_File(…)

HTK_Write_Stream_File(char *pathname, int flags, HStreamFileToolkit *my_toolkit)

Controlling HSF Size

Compression

Compression is one of the most obvious ways of shortening the data stream. The HOOPS/Stream Toolkit provides facilities that allow the user to compress the data on both a geometric (local) and a binary (file-wide) level.

File Wide Compression

The Stream Toolkit performs standard file wide compression on HSFs. The compression algorithm is lossless and is based on a standard LZ compression algorithm. Results vary depending on the dataset, however you can expect a reduction of 30% to 70% in HSF size depending on the geometry in the scene. This option particularly helps with datasets that contain a large amount of geometry, which is not locally compressed. These include images, polylines, text, arcs, textures and user-data. File wide compression is on by default and turned off by setting the TK_Disable_Compression bit in the flags parameter.

Local Compression of Geometric Primitives

The Stream Toolkit also compresses the facet data (HOOPS Shells and Meshes) in its local coordinate system. If this option is turned on the toolkit will compress the vertices and normals of each facetted object within its local coordinate system. This compression is lossy and can result in changes to the visual fidelity of the model. You can turn the compression of vertices and normals off separately via the TK_Full_Resolution_Vertices and TK_Full_Resolution_Normals bits respectively. Results vary depending on the dataset but this option typically reduces the file size by approximately 40%.

Reducing the amount of data in the file

Outside of compression another way you can reduce the size of an HSF is by reducing the amount of data in the stream. There are three methods the user can reduce the amount of data in a file. The first, Instancing involves searching the scene graph and comparing all objects against each other to see if they only differ by a translation, rotation or uniform scale. The second method is to eliminate LODs for any objects that are not 'important' to the scene. And finally the third method is to not include the file dictionary within the HSF. In this case if no server side logic is implemented then the file dictionary does not provide value and consequently should be excluded.

Instancing

By default before the toolkit begins writing the file it walks the scene graph and checks to see if any objects are simply versions of other objects already in the scene with a translation, rotation or uniform scale applied. Once it finds a match it stores a special tag indicating it is a copy of an object already in the file and the matrix that defines the translation. When decoding the file the toolkit then automatically runs the referenced object through the modeling matrix and restores it to its original location within the scene graph. This is particularly useful in cases where you are not importing the data directly from a CAD system model and consequently don't have the assembly structure of the model. The greatest benefits are found when there are large numbers of similar objects within a scene.

A significant amount of effort has been put into ensuring this algorithm is as efficient as possible, however if you already know the structure of your models you may want to eliminate this preprocess cost by setting the TK_Disable_Instancing bit in the flags parameter.

Eliminating LODs from the HSF stream

In general the Stream toolkit simply takes what is in the HOOPS/3dGS scene graph and creates a HSF from that. Consequently to ensure that LODs are not inserted into the HSF for objects which are unimportant you need to tell the HOOPS/3dGS LOD generator not to generate LODs for such objects. How this is done is discussed in detail the 'Quality of Streaming' section below. One exception to this is that you can tell the toolkit to not put any LOD information into the HSF. This is done by setting the TK_Suppress_LOD bit in the flags parameter

Removing the dictionary from the HSF

If you are just receiving the HSF data in a linear fashion (from start to finish without needing server logic to randomly access objects within the file), then there is no need to have the file dictionary and pay the associated penalty of having to transmit it. By default the file dictionary is not written to the data stream, however to write it to the stream you would turn on the TK_Generate_Dictionary bit in the flags parameter

Controlling the Quality of Streamed Entities

The quality of streaming is related to how quickly the user gets enough data to be able to start effectively navigating the scene. There are two separate parts to this process. The first involves creating simplified versions of 3D objects within the scene and the second involves ordering the objects within the file so that the most important objects in the scene are ordered towards the front of the file.

The Stream Toolkit provides controls to order geometry within the file. However, to control what geometry is in the file and the quality of the LODs you must first build up a HOOPS database (scene-graph). After building up a database the Level of Detail generator is then used to produce simplified versions of the facetted objects within the scene. LOD options are turned on and set via a HOOPS Rendering Option. To do this, choose the root of your segment tree and turn on Levels of Details and set your Level of Detail options as desired. To cause HOOPS to generate ODs you must force an update under a display segment (i.e. cause HOOPS/3dGS to render the scene). Note, if LODs are already in the tree you don't need to regenerate them.

In some instances developers may wish to create HSFs in a batch mode and don't want to render the screen. In this case developers force an update under the image driver to generate the LODs. An example of this is contained below.

Controlling Level of Detail Generation

LOD generation is controlled via a HOOPS Rendering Option

HC_Set_Rendering_Options("lod=on, lod options = (<opt1, opt2, …>)");

The options that are currently exposed are:

Levels = N: This is the number of levels that should be generated for each facetted object as long as the triangle count of a LOD is not less than the 'min triangle count'. N is a positive intege.

Ratio = [0, 1]: This is a floating point value between 0 and 1, which indicates the number of triangles that should be eliminated in each LOD level. A value of 0.1 would mean the first level LOD would have 10% of the triangles that the original has.

Min triangle count = M: The minimum triangle count of a LOD. The default is 25, which means the LOD generator stops generating LODs for an object if the LOD has less than 25 triangles. M is a positive integer.

Preprocess = on/off: When this is turned on HOOPS will generate all LODs in one pre-process step.

Max degree = n: This is a positive integer value, which indicates the maximum number of edges connected to a vertex in any generated LOD.

Usefulness Heuristic = (string): Specifies the heuristic by which usefulness is calculated and compared against the bounding value. Current valid options include 'diagonal ratio / triangles', 'diagonal ratio', 'diagonal / triangles', 'diagonal', 'volume ratio / triangles', 'volume ratio', 'volume / triangles', 'volume'.

Bounding = (min_x, min_y, min_z, max_x, max_y, max_z)): Via this option you set the bounding box against which the bounding boxes of geometry are compared when the LOD generator is making decisions about whether LODs should be generated for a specific object. "bounding = current" causes the LOD generator to use the bounding box of the currently opened segment.

Calculation Usefulness Cutoff = (float): Minimum Usefulness Heuristic value at which the LODs will still be calculated.

Controlling Ordering within the File

After Levels of Detail have been created for the scene you want to have some controls over the order in which objects are written to the file. By default the toolkit will write the highest level LODs (i.e. the most coarse LODs) at the start of the file with the next level LODs inserted immediately after them and so on until the original data is written towards the end of the file. The toolkit provides a flag which allows you to override this default behavior and allow you to tell the toolkit to order the objects in the file based on the Usefulness Heuristic. This is set via the TK_Priority_Heuristic bit in the flags parameter.

Example of creating an HSF

In the example below the user has created their scene graph under the segment that has a key of m_lMySceneKey. They have not created LODs for the scene and consequently need to generate them. Additionally, they do not want an update drawn to the screen so they are using our image driver.

// Setup the levels of detail for this model.

char cval[256];

sprintf(cval, "lod = on, lodo =(levels = 2, ratio = 0.2, preprocess, bounding = current, usefulness heuristic = (volume/triangles), calculation usefulness = 0.05 )");

HC_Open_Segment_By_Key(m_lMySceneKey);

HC_Set_Rendering_Options(cval);

HC_Close_Segment();

// Setup a raster image for the LODs

long image_key;

int width = 32;

int height = 32;

HC_Open_Segment("/null");

image_key = HC_KInsert_Image(0.0, 0.0, 0.0, "rgb", width, height, NULL);

HC_Close_Segment();

HC_Open_Segment("/driver/image/foo");

sprintf(cval, "use window id = %ld", image_key);

HC_Set_Driver_Options(cval);

HC_Set_Rendering_Options ("hsra = szb");

HC_Include_Segment_By_Key(m_SolidWorksSegmentKey);

HC_Close_Segment();

// Tell HOOPS/3dGS to walk the tree and do an update

HC_Update_Display();

// now delete the segment to free any memory

HC_Delete_Segment("/driver/image/foo");

//Write options flag.

//Want the geometry ordered in the scene based on its usefulness caracteristic

int flags = TK_Priority_Heuristic;

HC_Open_Segment_By_Key(m_lMySceneKey);

HTK_Write_Stream_File(buffer, flags, NULL);

HC_Close_Segment();

 

 
 

 

 

 

 

©2004-06 Tech Soft 3D All Rights Reserved. Privacy | Legal