The geometry list file (glist) describes the geometry present in a scene. It is the newer, XML replacement for the older Object Database (ODB) file format. The goals of introducing this file to replace the ODB file were multi-fold:
We wanted more flexibility in instance location descriptors
GLIST supports geographic locations
We wanted more flexibility in instance orientations descriptors
The ODB format supported either Euler angles with a fixed rotation order or an explicit 4x4 affine transform that bundled location, scale and rotations.
We wanted to expand the set of internal geometry primitives (e.g. spheres, boxes, cylinders, etc.) and to support instancing of a specific primitive (which the ODB format did not support).
We wanted a more flexible format to add more dynamic instancing options.
|Although this format is more powerful and flexible than the older Object Database (ODB) format, the GLIST format is NOT supported by either Bulldozer or the Blender plugins at this time. Hence, it is useful only for hand-crafted scenes.|
The primary component of a GLIST file is the
describes one or more geometry objects and where they appear in the
scene (or relative to the parent geometry that inserts them). The
following example shows a simple GDB object that appears in the scene
once at a fixed (static) location and a second time using a movement
<geometrylist enabled="true"> <object> <basegeometry> <gdb><filename>truck.gdb</filename></gdb> </basegeometry> <staticinstance> <translation> <point><x>0</x><y>0</y><z>0</z></point> </translation> <rotation> <cartesiantriple><x>0</x><y>0</y><z>90</z></cartesiantriple> </rotation> <scale> <cartesiantriple><x>1</x><y>1</y><z>1</z></cartesiantriple> </scale> </staticinstance> <dynamicinstance> <keyframemovement> <filename>truck.mov</filename> </keyframemovement> </dynamicinstance> </object> <geometrylistinclude name="Cars" enabled="true">cars.glist</geometrylistinclude> <object> <basegeometry> <sphere> <matid>4</matid> <radius>8.0</radius> <center><point><x>0.0</x><y>0.0</y><z>0.0</z></point></center> </sphere> </basegeometry> <staticinstance> <translation> <point><x>-12</x><y>3</y><z>4</z></point> </translation> <rotation units="degrees"> <cartesiantriple><x>0</x><y>0</y><z>0</z></cartesiantriple> </rotation> <scale> <cartesiantriple><x>1</x><y>1</y><z>1</z></cartesiantriple> </scale> </staticinstance> <dynamicinstance> <keyframemovement> <filename>rolling.mov</filename> </keyframemovement> </dynamicinstance> <dynamicinstance> <keyframemovement> <filename>bouncing.mov</filename> </keyframemovement> </dynamicinstance> </object> </geometrylist>
Notice that this example defines the basics of a
<geometrylist> contains one or more
<object> entries, and each
entry is comprised of:
The "base object" that will be instanced one or more times.
The list of one or more instances describing where the base object will appear in the scene.
The user can also include another geometry list by using the
<geometrylistinclude> element as shown below the first object.
|You can also instance another glist or ODB (statically or dynamically), see "Instancing Another Geometry List".|
Primitive objects (analytical constructs that are mathematical surfaces other than triangles) are handled in the same way as facetized geometry — the base geometry is used to define the prototype object and instances place copies into the scene.
The user can also add point sources (see Sources) to the scene directly from the glist rather than representing them with a single vertex and normal in a GDB (Geometric Database) file. In this case, the base object is a source rather than a piece of geometry and is defined using a
<basesource> element (see the Base Sources section below).
Extended geometric sources
(i.e. pieces of geometry that are used to model
volumetric shadowing) can only be defined as an instance of a piece
This section describes the various types of base geometry that are
supported. The base geometry is described in the
The primary geometry used by most users in DIRSIG are objects defined by a set of polygons or facets. DIRSIG natively supports attributed, facetized geometry in two formats:
The DIRSIG specific Geometric Database (GDB) format
The Alias/Wavefront Object (OBJ) format
DIRSIG Geometric Databases
The user can supply a DIRSIG Geometric Database file
<gdb> element that contains a
<filename>. The path
for this file is assumed to be relative to the GDB Path specified
in the scene file, or relative to the simulation directory or
<basegeometry> <gdb><filename>car.gdb</filename></gdb> </basegeometry>
The user can supply an Alias/Wavefront Object file using the
element that contains a
<basegeometry> <obj><filename>car.obj</filename></obj> </basegeometry>
Instancing Another Geometry List
The user can apply an affine transformation to entire (separate) geometry list by using a similar syntax to the gdb/obj geometry:
<basegeometry> <glist><filename>another.glist</filename></glist> </basegeometry>
<basegeometry> <odb><filename>another.odb</filename></odb> </basegeometry>
A box primitive is modeled using an axis-aligned convention which
requires that the user define two corners of the box at the minimum
and maximum points (labeled as
respectively). While this results in a box that is always exactly
aligned with the axes of the local coordinate system, the box may
be rotated out of alignment using the instance transform.
In addition to the geometric definitions, the user must provide a material ID to apply to the box and has the option of giving a temperature (in degrees Kelvin).
<basegeometry> <box> <matid>100</matid> <lowerextent><point><x>-1.0</x><y>-0.5</y><z>-0.4</z></point></lowerextent> <upperextent><point><x>1</x><y>0.5</y><z>0.2</z></point></upperextent> <temperature>300</temperature> </box> </basegeometry>
The default cylinder is vertically aligned (along the z-axis) from z = -0.5 to z = +0.5 and has a radius of 1. The only required element in the definition is the material ID associated with the geometry:
<basegeometry> <cylinder> <matid>100</matid> </cylinder> </basegeometry>
In addition to transforming the cylinder with a static/dynamic instance transformation, the user can define the orientation and length of the cylinder by providing the two cap center points. The shape of the cylinder can be further modified by providing the radius and the temperature can be set in degrees Kelvin:
<basegeometry> <cylinder> <matid>100</matid> <point_a><point><x>+0.7</x><y>+1</y><z>0</z></point></point_a> <point_b><point><x>-0.7</x><y>-1</y><z>1</z></point></point_b> <radius>0.5</radius> <temperature>300</temperature> </cylinder> </basegeometry>
Either or both of the cylinder cap may also be removed by setting the corresponding attribute to false:
<basegeometry> <cylinder cap_a="true" cap_b="false"> <matid>100</matid> <point_a><point><x>+0.7</x><y>+1</y><z>0</z></point></point_a> <point_b><point><x>-0.7</x><y>-1</y><z>1</z></point></point_b> <radius>0.5</radius> <temperature>300</temperature> </cylinder> </basegeometry>
<basegeometry> <cylinder cap_a="false" cap_b="false"> <matid>100</matid> <point_a><point><x>+0.7</x><y>+1</y><z>0</z></point></point_a> <point_b><point><x>-0.7</x><y>-1</y><z>1</z></point></point_b> <radius>0.5</radius> <temperature>300</temperature> </cylinder> </basegeometry>
The default disk is centered at the origin with the surface normal (facing direction) pointing up (+z). The default radius is one and the only required element is the material ID associated with the object.
|The disk is a section of a plane and has no thickness. If a solid object is desired, it is recommended that the user create a very thin cylinder.|
<basegeometry> <disk > <matid>100</matid> </disk> </basegeometry>
The disk can be further customized by providing a radius, a temperature, and a specific normal vector (which doesn’t need to be normalized) to determine the orientation before instance transformation:
<basegeometry> <disk> <matid>100</matid> <radius>0.5</radius> <temperature>300</temperature> <normal><point><x>-0.7</x><y>-1</y><z>1</z></point></normal> </disk> </basegeometry>
DIRSIG supplies a frustum object that produces a pyramidal frustum with conical corners. The frustum is characterized by sloped sides defined by bottom and top parameters. The bottom takes a width along the x and y axes, a radius, and a center point that positions it in the scene (note that the instance transform must be used to obtain anything other than a vertically (+z) aligned frustum). The top just takes a single radius and is always centered over the bottom. The height finishes off the shape definition and the user supplies a material ID and an optional temperature.
There are a few limits to the types of objects that can be created under this scheme. The bottom radius must always be greater than or equal to the top radius and the width in both axes must be greater than or equal to twice the radius.
The radii in the definition are used to connect one side of the top/bottom to the other (curving the corner):
<basegeometry> <curvedfrustum> <matid>100</matid> <height>0.5</height> <bottom> <xwidth>1.5</xwidth> <ywidth>1.5</ywidth> <radius>0.5</radius> </bottom> <top> <radius>0.2</radius> </top> </curvedfrustum> </basegeometry>
Setting the top radius to zero means that the top is a rectangle measuring the (width - (2 x radius)) in each dimension:
<basegeometry> <curvedfrustum> <matid>100</matid> <height>0.5</height> <bottom> <xwidth>1.5</xwidth> <ywidth>1.5</ywidth> <radius>0.5</radius> </bottom> <top> <radius>0.0</radius> </top> </curvedfrustum> </basegeometry>
A cone can be created with this setup by setting the bottom radius equal to half the x and y widths (which should be equal for a cone). That indicates that the radius of curvature covers the entire transition from one side to the next. To complete the cone, the top radius should be set to zero, creating a point at the top:
<basegeometry> <curvedfrustum> <matid>100</matid> <height>1</height> <bottom> <xwidth>1</xwidth> <ywidth>1</ywidth> <radius>0.5</radius> </bottom> <top> <radius>0.0</radius> </top> </curvedfrustum> </basegeometry>
For demonstration purposes, it is possible to approach the extreme of letting both radii be zero and build an approximate box (note that the user is advised to just use the box primitive in this case).
<basegeometry> <curvedfrustum> <matid>100</matid> <height>1</height> <bottom> <xwidth>1</xwidth> <ywidth>1</ywidth> <radius>0.0</radius> </bottom> <top> <radius>0.0</radius> </top> <temperature>300</temperature> </curvedfrustum> </basegeometry>
A catenary curve is a hyperbolic cosine function that is a good model of objects strung between two points and sagging under their own weight. Its definition has been simplified as much as possible and requires two points ("a" and "b") and the maximum sag (in meters) between those two points (NOTE: this is not the same as the formal catenary curve sag parameter, which is harder to work with). The user can also set the thickness of the material strung between the two points (assumed to be circular in cross-section) as well as the assigned material. An error will be issued if a curve cannot be generated from the parameters provided. This primitive is particularly good at representing power lines.
<basegeometry> <catenary> <thickness>0.1</thickness> <a><point><x>1390.57</x><y>801.823</y><z>634.064</z></point></a> <b><point><x>1304.17</x><y>825.456</y><z>635.46</z></point></b> <matid>301</matid> <sag>3.55947</sag> </catenary> </basegeometry>
The user can specify an infinite plane using the
primitive. Ground planes are currently always horizontal (i.e. their
normals point in the (+z) direction), though they can be rotated
(with care) by using the instance transformation.
The default ground plane is located with an anchor (pivot point)
at [0,0,0], but this can be changed with the addition of an
element. The user must provide a material ID associated with the
plane, and also has the option of setting a temperature:
<basegeometry> <groundplane> <matid>100</matid> <anchor><point><x>0</x><y>0</y><z>0</z></point></anchor> <temperature>300</temperature> </groundplane> </basegeometry>
|The anchor point mostly exists to support defining the origin of a checkerboard in local space (see below). However, equivalent behavior for both the ground plane and the checkerboard can be produced by translating the instance of the plane.|
The ground plane has the additional option of painting a checkerboard
on the surface. This is done by adding a
checkers element to
description with an additional material ID and a width (in meters).
The checks start at the anchor point (x,y), so that can be used to
shift the pattern around.
<basegeometry> <groundplane> <matid>100</matid> <anchor><point><x>0</x><y>0</y><z>0</z></point></anchor> <checkers matid="101" width="1.0"/> <temperature>300</temperature> </groundplane> </basegeometry>
The user may also control the painting of individual checks using
an index system where the origin is the anchor point. Note that the
material ID of either the plane or the checks may be
0 to be
transparent and that indices may be negative.
<basegeometry> <groundplane> <matid>100</matid> <anchor><point><x>0</x><y>0</y><z>0</z></point></anchor> <checkers matid="100" width="1.5"> <paint xindex="0" yindex="0" matid="101"/> <paint xindex="1" yindex="1" matid="101"/> </checkers> <temperature>300</temperature> </groundplane> </basegeometry>
The sphere description allows the user to set the center of the sphere, a radius, the material ID and temperature of the object.
<basegeometry> <sphere> <matid>100</matid> <center><point><x>0</x><y>0</y><z>0.5</z></point></center> <radius>0.8</radius> <temperature>300</temperature> </sphere> </basegeometry>
The sphere is the only non-facetized object that has UV texture coordinates built in for mapping purposes. Those UV coordinates are computed directly from the hit as:
$u = \phi / ( 2\pi ),$
$v = (\pi - \theta ) / \pi,$
which are based on the azimuth and zenith angles of the hit (relative to the sphere), respectively.
A Secchi disk is a high contrast target often used for measuring
turbidity in natural waters. DIRSIG provides an easy way to set
this up by providing a disk that accepts two materials as input,
but is otherwise the same as the
disk previously described:
<basegeometry> <secchidisk > <matid_a>100</matid_a> <matid_b>101</matid_b> <radius>1</radius> </secchidisk> </basegeometry>
The sinusoid primitive allows the user to create an analytical sinusoidal surface constrained to a box. The sinusoid itself need not be aligned with the box — a 2-D orientation can be provided, as well as the period and a phase shift. If the box height is equal to twice the magnitude of the sinusoid, then the object created is a surface:
<basegeometry> <sinusoid> <matid>100</matid> <lowerextent><point><x>-1.0</x><y>-1</y><z>0.0</z></point></lowerextent> <upperextent><point><x>1</x><y>1</y><z>0.2</z></point></upperextent> <magnitude>0.1</magnitude> <orientation><vector><x>-0.8</x><y>0.4</y></vector></orientation> <period>0.5</period> <phaseshift>0.1</phaseshift> </sinusoid> </basegeometry>
By defining a box that has a height greater than the peak to trough measurement of the sinusoid, the object becomes a solid — the same sinusoidal surface but with a box on the lower side:
<basegeometry> <sinusoid> <matid>100</matid> <lowerextent><point><x>-1.0</x><y>-1</y><z>-0.4</z></point></lowerextent> <upperextent><point><x>1</x><y>1</y><z>0.2</z></point></upperextent> <magnitude>0.1</magnitude> <orientation><vector><x>-0.8</x><y>0.4</y></vector></orientation> <period>0.5</period> <phaseshift>0.1</phaseshift> </sinusoid> </basegeometry>
A "regular grid" is a representation of a 3D voxelized field of a spatially varying volume. This data representation is useful for an object like a factory stack plume. The grid description is split between two different files:
The "grid" file, which indicates the number of spatial elements in each dimension of the grid and the properties of grid element, and
The inclusion in the GLIST file, which includes then name of the "grid" file and which specifies the spatial length of the grid elements (or "voxels") for each dimension.
|The separation of the spatial length of grid elements from the the "grid file" allows a single grid to be used multiple times but with different scales.|
Because of the current configuration, a "Regular Grid" cannot be
instanced like other
The following example shows the contents of a grid file:
142 142 64 43 57 0 206 795.444 1000.2030 44 57 0 206 795.228 1000.2030 41 58 0 206 795.228 1000.2030 ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
The first line has three integers, denoting the dimensions of the grid. In
the example above, the grid is
The remainder of the file consists of lines with six columns of data. The
first three columns indicate the voxel index (counting from 0). The fourth
column indicates a DIRSIG material ID corresponding to an entry in the
Material Database file (.mat). The fifth column indicates temperature in
Kelvin. The final column indicates concentration in parts per million
|Specifying voxel data for each grid voxel is not required. Unspecified voxels are treated as being empty. Furthermore, empty voxels do not take up memory, though they do slow the ray-tracing process to some degree.|
The "grid" file is then inserted into the scene via a GLIST entry like the one shown below:
<basegeometry> <regulargrid> <gridfilename>regular.grid</gridfilename> <insertpoint> <point><x>10</x><y>10</y><z>0</z></point> </insertpoint> <voxeldeltax>1.0</voxeldeltax> <voxeldeltay>1.0</voxeldeltay> <voxeldeltaz>0.5</voxeldeltaz> </regulargrid> </basegeometry>
<insertpoint> indicates the Scene ENU coordinates (in meters) to
insert the origin of the grid (the
0,0,0 coordinate of grid).
associate a physical size to respective XYZ dimensions of the voxels.
When information in the grid file and the GLIST specification are combined:
The grid contains 142 x 142 x 64 grid elements (from the "grid" file)
The grid is 142m x 142m x 32m (using the voxel sizes from the GLIST file)
The origin of grid is at
10, 10, 0in the Scene ENU coordinate system (from the GLIST file).
<heightfield> is a 3D representation of a (potentially dynamic) 2D array of height data. It is used in conjunction with a
<heightmodel> that defines the heights at each sample point. The model can be as simple as an image (mimicking an unoptimized conversion of elevation data to facetized geometry) or as complex as a wind-driven wave surface that develops over time.
The options to the height field itself are fairly limited:
<basegeometry> <heightfield> <matid>100</matid> <boxmode>false</boxmode> <cachesize>100</cachesize> <heightmodel type="..."> ... </heightmodel> </heightfield> </basegeometry>
<matid> defines the material assigned to the surface (which may be mapped as with other surfaces — the uv space is defined for the horizontal
extents of the box height field, with the minimum horizontal point corresponding to the minimum uv point). The two other inputs (
<cachesize>) are optional and rarely used. The
<boxmode> uses boxes to model the surface rather than facets. The
<cachesize> dictates the maximum number of instantiations of a surface that are held in memory to optimize non-sequential intersection of dynamic surfaces (in particular, this enables faster per-pixel temporal integration). The default values for the two optional parameters are "false" and "100", respectively.
The height field is primarily a way to facilitate bringing regularly sampled height data into DIRSIG without going through an intermediate step of transforming the height data into a facetized 3D object. The advantage of the height field is that all ray tracing is done directly on the height field data itself using an optimized grid traversal algorithm, usually saving both memory and some run time for intersections. This is convenient for static height fields (e.g. terrain) and a necessity for dynamic height fields (e.g. waves)
Internally, the height field is just the grid of data points, with individual surfaces that connect each set of four neighboring points being generated on the fly. This can be seen in a low resolution render using the "box mode", which uses a 3D box at the base of the height field extended to the maxium height of the four neighboring points:
Box mode is only useful under very limited circumstances beyond visualization and normally we want to use the height field in the (default) facetized mode. In this mode, the box is replaced by two triangular facets which collectively have vertices at each of the 4 neighboring data points:
To generate physically realistic scene geometry, the resolution of the grid should be high enough so that the facetization is significantly sub pixel, e.g.
The facetized height field can be treated just like any other facetized piece of geometry — it can be assigned maps and can be given reflectance and transmittance properties:
See the height model documentation for details on how to drive the underlying data.
<basesource> is analogous to a
<basegeometry> element and supplies the definition of a single source that can be instanced multiple times. Its availability in the GLIST provides an alternative to the GDB (Geometric Database) based definition of a point source using a piece of geometry (see Sources) and allows for adding new types of sources in the future. Currently, the only type of base source available is a point source.
<pointsource> element as the base source in the GLIST provides the same functionality as the point sources described in Sources without requiring a piece of geometry to define the position, direction and associated material ID. Instead, each point source defined as a base source is always located at the scene origin (it can then be re-positioned using the translation). The default pointing direction is in the positive
Z direction, but this can be overriden by rotating an instance or providing an optional new default pointing vector. An element attribute provides the associated material ID and is mandatory:
<basesource> <pointsource matid="777"> <pointing><vector><x>0.0</x><y>0.0</y><z>-1.0</z></vector></pointing> </pointsource> </basesource>
|Scaling a point source in the instance has no effect!|
Instancing is technique that has been used in the computer graphics community for a long time to assist in making large scenes using a smaller number of "base" objects. Each "instance" is internally represented by a lightweight object referencing a "base" object and a set of translation, rotation and scaling operations to be applied to the object. The key is that the "base" geometry does not need to be duplicated for each instance, because the translation, rotation and scaling can be quickly applied to each ray intersecting the instance rather than to base geometry.
Note that the instancing transform makes several assumptions about the base geometry provided for each object:
The translation of the base object is applied to the origin of the object.
The rotation of the base object is also relative to the origin of the object.
If the object is not "centered" in the described fashion, the rotation of the object may yield unexpected results.
|In most cases, it is desired that the user modify the object geometry so that the model is centered about the X and Y origin and the bottom of the model (smallest Z value) is at the Z origin. In this configuration, it is very easy to place the object within the scene.|
An instance can also be named, which is useful when other sections of the glist need to refer to it (such as the anchoring mechanism in some of the random fills). The name is provided by a "name" attribute and should be unique (which also means that it needs to be at the highest level of embedded instancing).
A "static" instance places the base geometry at a specific location and orientation with the specified scaling. There are currently two ways to define a static instance:
XYZ Axis Triplets
4x4 Transform Matrix
XYZ Axis Triplets
The order of operations is:
The explicit translation, scale and rotation values supplied here are used internally to form the affine transform used by DIRSIG to describe the instance.
|The order of the rotations affects the final orientation of the object.|
A scale of
The following is an example of inserting an instance of an object using the "Scene ENU" coordinate system:
<staticinstance> <translation> <point><x>-20</x><y>-55</y><z>10</z></point> </translation> <rotation units="degrees" rotationorder="xyz"> <cartesiantriple><x>30</x><y>0</y><z>60</z></cartesiantriple> </rotation> <scale> <cartesiantriple><x>1</x><y>1</y><z>10</z></cartesiantriple> </scale> </staticinstance>
<cartesiantriple> elements specify the quantities for the respective
XYZ dimensions. The
units attribute in the
specifies the units of the angles in the associated
rotationorder attribute in the
<rotation> element specifies the
order that the rotations are performed in.
xyz implies the objects rotated about the X axis, then the
Y axis and finally the Z axis.
The GLIST file also supports geolocation of objects. The following is an example using the "Geodetic (Lat/Long/Alt)" coordinate system to specify the location:
<staticinstance> <translation> <geodeticlocation> <latitude>43.120</latitude> <longitude>-78.450</longitude> <altitude>300.000</altitude> </geodeticlocation> </translation> <rotation units="radians" rotationorder="zyx"> <cartesiantriple><x>0</x><y>0</y><z>0.78539816</z></cartesiantriple> </rotation> <scale> <cartesiantriple><x>1</x><y>1</y><z>1</z></cartesiantriple> </scale> </staticinstance>
Note that in this example the
<rotation> has units of radians and
the rotation order is ZYX.
In DIRSIG 4.5.0, the new
|If one or more of the three affine tranformation components are missing, DIRSIG will not do anything to the original geometry for that particular component (e.g. a missing translation tag means that no additional translation will be added, though rotation and scaling may be applied if they are present).|
If the user wants to use the base geometry without any transformations at all they can use the brief syntax:
to indicate that object maintains its original position, rotation and scaling.
4x4 Affine Transform
The second option available is to specify the instance via a 4x4
affine transform matrix. The transform is provided
<matrix> element within the
<staticinstance>. The matrix
needs to be provided in row-major order as
a comma separated list:
<staticinstance> <matrix>+2, 0, 0, -5, 0, +2, 0, -5, 0, 0, 2, 0, 0, 0, 0, 1</matrix> </staticinstance>
Delta (Keyframe) Motion
An object can be dynamically positioned as a function of time using an external Delta Movement (sometimes referred to as "keyframe" movement) file:
<dynamicinstance> <motion type="delta"> <filename>truck.mov</filename> </motion> </dynamicinstance>
This model is explained more in the DeltaMotion1 demo.
An object can be dynamically positioned as a function of time using an external Generic Platform Position Data file:
<dynamicinstance> <motion type="generic"> <filename>truck.ppd</filename> </motion> </dynamicinstance>
This model is explained more in the GenericMotion1 demo.
An object can be dynamically positioned and oriented as a function of time using the Flexible Motion model:
<dynamicinstance> <motion type="flexible"> <locationengine type=... > ... </locationengine> <orientationengine type=... > ... </orientationengine> </motion> </dynamicinstance>
This model is explained more in the FlexibleMotion1 demo.
Turning Instances On/Off (Time Windows)
enabled attribute has been used in some of the previous examples to turn objects and included files on or off in the
glist file. The instances themselves don’t have an equivalent input, but it is possible to schedule when they are part of the scene by providing a
<staticinstance timewindow="..."> ... </staticinstance>
The time window is a generic term for an on/off schedule and the inputs are dependent on the schedule being used. The type of schedule is automatically determined (the attribute is always
Time Window: Simple
The simple time window is defined by
b correspond to the time the instance will be "turned on" and "turned off," respectively. They are both given in decimal seconds from the start of the simulation.
Time Window: Daily
The daily time window is similar to the simple time window, but it repeats every day. Instead of providing times from the start of the simulation, the inputs to this window are two (local) clock times and are not dependent on the simulation start,
As with the simple format, seconds can be provided as decimal values. The hours component uses a 24hr clock.
Including other Geometry Lists
Although you can use another GLIST/ODB as the base geometry and then instance it, you can also "include" an external GLIST and ODB files. The following is an example of including an external GLIST file:
<geometrylistinclude name="Cars" enabled="true">cars.glist</geometrylistinclude>
This option allows you to break a larger scene down into smaller parts. For example, the MegaScene1 scene was split up based on the names of roads in the real-world scene:
<geometrylist enabled="true"> <geometrylistinclude name="Belmeade_Rd" enabled="true">tile_1/Belmeade_Rd.odb</geometrylistinclude> <geometrylistinclude name="Biltmore_Dr" enabled="true">tile_1/Biltmore_Dr.odb</geometrylistinclude> <geometrylistinclude name="Briarwood_Dr" enabled="true">tile_1/Briarwood_Dr.odb</geometrylistinclude> <geometrylistinclude name="Bristol-Winona-StPaul" enabled="true">tile_1/Bristol-Winona-StPaul.odb</geometrylistinclude> <geometrylistinclude name="Cambria_Rd" enabled="true">tile_1/Cambria_Rd.odb</geometrylistinclude> <geometrylistinclude name="Chimayo_Rd" enabled="true">tile_1/Chimayo_Rd.odb</geometrylistinclude> <geometrylistinclude name="CircleCourt" enabled="true">tile_1/CircleCourt.odb</geometrylistinclude> ... </geometrylist>
Instancing other Geometry Lists
To instance another GLIST or ODB, you can add it as a basegeometry type like the other objects:
<basegeometry> <glist> <filename>tree_stand.glist</filename> </glist> </basegeometry>
<basegeometry> <odb> <filename>tree_stand.odb</filename> </odb> </basegeometry>
Population based variants
When populating a scene with geometry, we often have a situation where we want many variations of a class of object (e.g. many vehicle geometries with different paint colors, or suburban house geometries with varying building materials) that are interchangeable. In other words, all that matters is that an object of a particular type go in a specific spot, the specific object used is irrelevant. If, say, there are a 100 different vehicle variants within a population (potentially with a known distribution within that population) it would be nice to have a single list of where those vehicles should go and have DIRSIG automatically assign one of the variants (following the distribution) to each of those instances.
Using the basic glist tools, developing a population of instances means having to use copies of the same geometry that vary only by the material ids (to represent different material variants in the population) and separate lists of instances for each object. Not only is this tedious and messy (even with the help of external scripts), but we also end up creating redundant geometry (i.e. each material variant of an object replicates the same base geometry) and a complex set of glist files that are difficult to modify. As an alternative, DIRSIG provides a number of built-in tools to help input populations of objects, automatically varying the geometry used and the materials assigned based on user-provided inputs. Geometric and material variants are described in more detail below.
Adding geometry variants
Adding more than one
<basegeometry> entry to an object allows the user to specify a pool of objects that will be randomly selected from for each instance in the instance list. The different "base geometry" objects can be
weighted to create a discrete population distribution that reflects different proportions. The user must still provide a list of instances (either static or
dynamic) but the model will choose which "base geometry" is used
with each instance based on the weightings. This mechanism can be
used for a variety of applications, including:
Quickly populate a forest (the user supplies tree locations as static instances) so that the final forest reflects the supplied proportions of each tree species (provided as the set of "base geometry" objects).
Quickly populate a traffic pattern (the user supplies the vehicle tracks as dynamic instances) with many different types of cars. If a car of a certain make or type is more or less common, the base geometry weightings can be manipulated to reflect this.
The different base geometries are defined by creating multiple
<basegeometry> elements within an
<object> element. Consider
the following example from a glist file:
<geometrylist> <object> <basegeometry weight="1"> <glist><filename>cars/vw_beetle.glist</filename></glist> </basegeometry> <basegeometry weight="2"> <glist><filename>cars/generic_pickup.glist</filename></glist> </basegeometry> <basegeometry weight="2"> <glist><filename>cars/generic_suv.glist</filename></glist> </basegeometry> <basegeometry weight="2"> <glist><filename>cars/infiniti_g35.glist</filename></glist> </basegeometry> ... </object> </geometrylist>
weight attribute is used to manipulate the relative proportion
of that base geometry in the overall population.
The base geometry
In this example, we have defined a pool of four different cars that will
be randomly selected from as each instance is defined. Note that the
weight values in this case have the Volkswagen Beetle
vw_beetle.glist) appearing less often than the other vehicles in the
scene. It is important to realize that since the
file (and the other 3 vehicle GLIST files) include randomized material
attributions (discussed in the next section) that each instance
will get a random base geometry (which vehicle type) and a random
attribution of that base geometry (the paint type on that vehicle).
To add another base geometry to the pool, the user just needs to
Adding material variants
The ability to randomly reassign material properties to each instance
is performed via a
<population> element within an
<object> element (separate from the
<basegeometry> element(s). A
<materialvariant> element defines which original material ID will be reassigned and the weighted distribution of assignable material IDs.
In the example below, the model looks for surfaces attributed with material
ID #500 (the default material ID for a car, which is associated
with the body of the vehicle). These surfaces will be reassigned either
material ID #501, #502, #503,#504 or #505 based on the respective
for each ID. In this case, these material IDs correspond to different vehicle
body paints in the DIRSIG material database:
<geometrylist> <object> <basegeometry> <obj swapyz="false"> <filename>Cars/vw_beetle.obj</filename> <assign name="paint" id="500">default</assign> ... </obj> </basegeometry> <population> <materialvariant> <variantid>500</variantid> <seed>1234</seed> <distribution> <matid weight="2">501</matid> <matid weight="1">502</matid> <matid weight="1">503</matid> <matid weight="1">504</matid> <matid weight="2">505</matid> </distribution> </materialvariant> </population>
|The seed is optional — if not provided, the global random number generator is used instead.|
The material ID
In this case, material ID #501 and #505 have larger weights than the other
materials, reflecting that these body colors are more likely to be chosen.
The weights add up to
9, which means #501 and #505 will be assigned to
2/9ths (each) of the vehicles and the remaining materials will be assigned
to 1/9th (each) of the vehicles.
To reassign another material ID, the user just needs to add
|Using the same seed for multiple material variants will make sure that the same combinations of material are used with every random draw.|
Including lists of instances
The locations of objects within the scene are often driven by a third-party tool or script that generates position information, but not a full glist. If that data is in the form of static/dynamic instance entries, it would be nice to directly use that information without having to manually wrap it with a (potentially nontrivial) set of object definitions.
For example, we might setup a generic population of building models in a glist (different geometric models and material variants), but have a third party tool (such as a procedural scene builder) tell us where those buildings should go and how they are oriented. We could have that tool generate a list of instances (or convert its native output to DIRSIG instances) and then manually copy/paste the building object information in, but this becomes tedious if future modifications of the instance list is necessary. Instead, it would be a lot handier to have DIRSIG grab the contents of one file (the list of instances) and insert it in the current file (the glist with the building population). That way the glist never needs to be modified if we are changing the positions and any modifications to the included file will be used automatically.
To support this, DIRSIG has minimal support for the XInclude (XML
Inclusions) standard via an
xi:include embedded in the XML file. When
this tag is encountered, the included file is loaded, converted to an
XML fragment, and inserted into the current XML tree being read in. To
read in a list of instances for example, you’d use:
<object> ... <xi:include href="instances.list"/> </object>
where "instances.list" is a text file in the same directory consisting of (bare) XML instance entries.
DIRSIG does not support any other options/attributes of the XML
Inclusion standard and only minimally supports
In addition to explicitly defining where objects go within the scene, it is possible to have DIRSIG automatically fill a region (usually randomly) with instances of one or more types of objects. Traditionally, this sort of approach has been done by writing external scripts to generate instancing information (potentially using truth images generated from DIRSIG). While this is still an effective technique, the integrated tools in DIRSIG allow the instance generation to robustly place objects, checking for overlaps with existing scene geometry or anchoring based on a subset of the scene.
|While it is possible to intance a geometry list containing a random fill, you will alway get the original, filled geometry and the content of the copies will match the original (i.e. they will not be independently filled). This is generally only useful for quickly generating cyclic boundary conditions. The random fills are intended to be unique components of a scene.|
The instance generators defined here are all defined within a
<randomfill> tag and only one generator can be defined per tag (though
its possible to use multiple
<randomfill> tags). The
element has two optional attributes that can be used to save out the
location of instances and then use them if the save file exists, e.g.:
<randomfill savefile="instances.sav" loadinstances="true"> ... </randomfill>
If the file "instances.sav" doesn’t exist then the random fill will generate instances based on the fill mechanism (see below) and will save out the instance entries to the file. If the file does exist then the instances will be read in (skipping any instance generation) if "loadinstances" is set to "true". If it is false (or absent) then the existing file is overwritten (if no "savefile" exists then nothing is loaded or saved). Attempting to load a nonexistent save file (i.e. "loadinstances" set to "true") will result in an error.
|The save mechanism is very useful to make sure that any subsequent runs use the exact same distribution of objects in the scene. It also might save a bit of time during initialization if the random fill is very large or complicated.|
|The fill tools are still prototypes at this time and the exact syntax is subject to change|
The anchor list
The simplest form of random fill is based on reading in a list of horizontal positions within the scene and automatically filling them with geometry objects taken from a defined population (see previous discussion of geometry and material variants). For example, we could setup a small fleet of cars (different geometry models with material variants) that looks like this:
<object enabled="true"> <basegeometry weight="1"> <glist><filename>vw_beetle.glist</filename></glist> </basegeometry> <basegeometry weight="2"> <glist><filename>infiniti_g35.glist</filename></glist> </basegeometry> <basegeometry weight="1"> <glist><filename>generic_pickup.glist</filename></glist> </basegeometry> <basegeometry weight="1"> <glist><filename>toyota_corolla.glist</filename></glist> </basegeometry> <basegeometry weight="1"> <glist><filename>vw_golf.glist</filename></glist> </basegeometry> <basegeometry weight="1"> <glist><filename>nissan_fairlady.glist</filename></glist> </basegeometry> <basegeometry weight="2"> <glist><filename>bmw_x5.glist</filename></glist> </basegeometry> <population> <materialvariant> <variantid>500</variantid> <distribution> <matid weight="2">501</matid> <matid weight="1">502</matid> <matid weight="1">503</matid> <matid weight="1">504</matid> <matid weight="2">505</matid> <matid weight="2">506</matid> <matid weight="2">507</matid> </distribution> </materialvariant> </population> ...
Now we can use the new instancing tool to fill the spots listed in one of our lists:
... <randomfill loadinstances="false" savefile="instances.sav"> <anchorlist> <filename>drivewayspots.txt</filename> <blocking>blocking.txt</blocking> <fillpercent>80</fillpercent> <reversepercent>30</reversepercent> <anchor>lot</anchor> <seed>33932194</seed> <posdev><point><x>0.02</x><y>0.4</y><z>0</z></point></posdev> <rotdev units="degrees"><point><x>0</x><y>0</y><z>3</z></point></rotdev> </anchorlist> </randomfill> </object>
where the options are:
name of the file with the location information (rows of <x> <y> <dx> <dy> where <x> and <y> are the horizontal position coordinates in the local ENU coordinate system and <dx> <dy> are the "facing" orientation of the spot)
optional name of another file that blocks placement of objects (rows of <x> <y> <wx> <wy>, where <wx> and <wy> are the axis aligned widths of the block — this is useful for excluding areas externally, such as making sure light posts aren’t placed in driveways)
the percent of locations that will be filled (randomly)
the percent of placements that will point in the opposite direction from that given (useful for parking spots where cars can point in two directions)
the instance of geometry on which the object should be placed (corresponds to the name attribute of an instance)
the specific seed to use for random draws (can be changed to vary placement without modifying the runtime seed)
a set of three (x,y,z) standard deviations for random offset (gaussian pull) from the given location
same as the position deviation, but for a rotation relative to the given direction (or the reversed direction if applicable); units are user-supplied as radians or degrees
An example of using this fill tool is shown below for a parking lot:
DIRSIG will supply the vertical position (and any slope-based rotation) automatically for the placed geometry based on the underlying terrain/object listed.
The density map
We often want to fill an area in the scene somewhat randomly (as opposed
to providing a list of locations), but want to have some control over the
spatial density of the distribution of objects. Additionally, if there
is stuff already in the scene, we potentially want to avoid planting
the new object on top of or intersecting those objects (for example,
we might want to add a distribution of trees around existing buildings
in the scene). The density map (
<densitymap>) based random fill is
meant to handle these situations:
<randomfill> <densitymap> <count>50</count> <mindist>0.1</mindist> <maxdist>2.0</maxdist> <matid>200</matid> <anchor>lot</anchor> <seed>33932194</seed> <randomorientation>true</randomorientation> </densitymap> </randomfill>
number of objects (those listed in the same
<object>section) to try to place
the (approximate) minimum distance between placed objects at highest density [m]
the (approximate) maximum distance between placed objects at lowest (non-zero) density [m]
the material id associated with the density map to be used; if no density map exists, objects will be placed at random distances between the min and max; the material ID should also correspond to a material exiting in the anchor object being mapped to ensure that it is registered with the simulation
the specific seed to use for random draws (can be changed to vary placement without modifying the runtime seed)
flag for having the placed object be rotated randomly (full 360 degree rotation)
As seen above, the
<densitymap> fill takes a material ID associated
with a density map (defined in the maps section of the scene file). The
density map (defined in the scene file along with all other maps) might
look something like:
<maplist> ... <!-- Parking density --> <densitymap name="Parking Density Map" enabled="true"> <matidlist> <matid>200</matid> </matidlist> <projector> <uvprojector/> </projector> <image> <filename>parking_density.png</filename> </image> </densitymap> ... </maplist>
The image used for the map is simply a grayscale image where the highest possible value (white) corresponds to the densest packing of objects and the lowest possible value (one digital count above black) corresponds to the least dense packing. A value of zero (absolute black) in the image means that no objects should be planted in that region (which is useful for masking out portions of the scene where objects would be planted otherwise).
The practical definition of density is based on the provided values for
<maxdist>. These values are approximately the spacing
between the placed object at the highest and lowest density, respectively
(they are actually the distances between the transformed bounding boxes
of the placed objects since it would be too expensive to test potentially
complex surfaces). When two objects exist in two different density regions
(e.g. two different points in a density gradient) then the distance
between them will be the average of the two density based distances.
|If a density map (image) is not provided then the placement will pick a random spacing between the minimum and maximum distance|
|Only the first valid density map for a surface will be used — it is not possible to define multiple density maps on the same surface currently (though the type of object can be varied uniformly using the population options)|
The following image is an example of using the density map to place stray shopping carts in a grocery parking lot scene in a semi-logical fashion (i.e. in between cars, and primarily between opposing stalls, but never in the drive aisles).
The density map we’re using (shown below, above the material map that defines the lines) shows how this was done. The area between opposing stalls has a band of pure white (highest density packing), the areas between cars have a darker value with a slight gradient (we want a few carts between vehicles, but make it very unlikely to pack two in close together), and finally the drive aisles are black, making sure there are no carts blocking traffic.
The other key part of the
<densitymap> is the choice of
which is that name of a (unique) geometry instance in the scene. This the
object onto which the objects will be placed. If the anchor is occluded
by another object (e.g. a car on the parking lot when the lot is the
anchor), then the object won’t be placed. Otherwise each placed object
will rest on the anchor object based on its "origin" (usually set to
the center bottom of the object).
Note that our choice of anchor is important here (it was assigned to the parking lot geometry instance, "lot"). If the entire scene was used as the anchor then carts would be placed whereever they fell (though avoiding each other). The following image shows this (for a larger number of carts than used in the previous):
<densitymap> fills are used in the
demo which was used to create the images shown here.
The polygon fill
The polygon (vertex) based fills are setup similarly to the density based fill except that objects are placed uniformly within each polygon:
<randomfill> <polyfill> <polyfile>yards/backyards.txt</polyfile> <mincount>10</mincount> <maxcount>40</maxcount> <matid>910</matid> <seed>42832</seed> <randomorientation>true</randomorientation> </polyfill> </randomfill>
The name of the file with the vertex information (rows of <x> <y>, where <x> and <y> are the horizontal position coordinates in the local ENU coordinate system; polygons are separated by two blank lines and the last vertex and first vertex should match for each polygon)
The minimum number of objects to try to place within each polygon
The maximum number of objects to place within each polygon
The material id that objects can be planted on (e.g. the id corresponding to the lawn material)
The specific seed to use for random draws (can be changed to vary placement without modifying the runtime seed)
The flag for having the placed object be rotated randomly
The following image is an example of using backyard polygons to direct the placement of tree, pool, and playground clutter (note that there is no socio-cultural logic applied — a pool is placed near a sidewalk even though that would not be likely to occur):