|
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();
|