Skip to content
On this page

Geometry data

The Simplygon API represents geometric objects using the GeometryData class. This class provides methods for accessing and manipulating geometric data.

Packed geometry data

Simplygon supports packed geometry data using the PackedGeometryData class. Packed geometry data stores geometry fields per vertex rather than per corner. The GeometryData class can return data in packed format using the NewPackedCopy method. Note that the packed geometry data will contain more vertices than original geometry due to vertices being split up because of non identical per vertex data. The PackedGeometryData class can return unpacked geometry data using the NewUnpackedCopy method. For more, see the packed geometry example.

Appending to geometry data

To combine two geometries, the AppendGeometry method of GeometryData, or the AppendPackedGeometry method of PackedGeometryData can be used. In the case of AppendPackedGeometry, it appends an GeometryData object to the packed geometry, using vertices from the packed geometry when available and adding new vertices from the appended geometry to the packed geometry if no matching vertices are found. It generates a vertex list describing the triangles of the appended geometry expressed in the vertex IDs from the combined vertex set of the packed geometry and the appended geometry.

A boolean flag determines if the method will collapse all vertices of the appended data to the closest matching vertex of the packed geometry, or allow new unique vertices to be added as required. Not allowing new vertices to be added could obviously produce strange meshes if the appended geometry is very different from the packed geometry it is appended to.

Used alongside the conservative setting of the DataCreationPreferences flag when using MeshLOD, AppendPackedGeometry produces a description of a generated LOD using the original vertices by appending the LOD to the packed original geometry. For a relevant example, check the data creation preferences example.

Geometry fields

Simplygon stores geometry information in a collection of arrays called fields. Several built-in fields are provided by the API. Users can also add their own custom fields to a geometry object. The geometry information in these fields are stored either on a per-vertex, per-corner or per-triangle basis.

A corner is a triangle-vertex pair so there are three corners for each of the triangles in the mesh. The default fields (apart from Coords) are mostly defined per-corner, to be able to define discontinuous data, such as normals and texture coordinates. The default geometry fields are listed below, they can all be used with Add[field name], Get[field name], Remove[field name];

Default fieldTuple sizeDescription
Vertex attribute
Coords33D position values for each of the vertices in the geometry
BoneIds1-4Influencing bone identifier, see Working with skinning data
BoneWeights1-4Influencing bone weight, see Working with skinning data
VertexWeights1Importance value for feature preservation during reduction. See Working with vertex weights
VertexLock1Bool value to determine if vertex is locked. See Vertex-lock field
Triangle attribute
GroupIds1The group identifier for each of the triangles
MaterialIds1The material identifier for each of the triangles
QuadFlags1Encoded quad information. See Quad data
Corner attribute
VertexIds1The vertex index used for that corner
Normals3Normal vectors for each of the corners in the mesh
TexCoords[level]2Texture coordinates for each corner in the mesh, per level. The level can be between 0 and SG_NUM_SUPPORTED_TEXTURE_CHANNELS - 1
Tangents[level]3Tangent vectors for each corner in the mesh, per level. The level can be between 0 and SG_NUM_SUPPORTED_TEXTURE_CHANNELS - 1
Bitangent[level]3Bitangent vectors for each corner in the mesh, per level. The level can be between 0 and SG_NUM_SUPPORTED_TEXTURE_CHANNELS - 1
Colors[level]4Color values for each corner in the mesh, per level. The level can be between 0 and SG_NUM_SUPPORTED_COLOR_CHANNELS - 1

Vertices and corners

Vertices and corners cube

Vertex-lock field

The vertex lock field allows the user to fix certain vertices in the geometry so that they will not be modified by the simplification process. The vertex-lock field contains one Boolean value for each vertex that indicate whether the vertex should be locked or not.

Example - Adding a vertex-lock field

The following example shows how to add a vertex-lock field to a geometry object.

cpp
void VertexLockExample(spGeometryData geom)
{
    // Add a field for the vertex locks.
    geom->AddVertexLocks();
    // Retrieve the vertex lock field.
    spBoolArray locks = geom->GetVertexLocks();
    if( !locks.IsNull() )
    {
        unsigned int n = locks->GetItemCount();
        for( unsigned int i = 0; i < n; ++i )
        {
            // Lock every 5th vertex.
            locks->SetItem( rid(i), (i % 5) == 0 );
        }
    }
}
csharp
void VertexLockExample(spGeometryData geom)
{
	// Add a field for the vertex locks.
	geom.AddVertexLocks();
	// Retrieve the vertex lock field.
	spBoolArray locks = geom.GetVertexLocks();
	if (locks != null)
	{
		uint n = locks.GetItemCount();
		for (uint i = 0; i < n; ++i)
		{
			// Lock every 5th vertex.
			locks.SetItem((int)i, (i % 5) == 0);
		}
	}
}
python
def VertexLockExample(geom):
	# Add a field for the vertex locks.
	geom.AddVertexLocks()
	
	# Retrieve the vertex lock field.
	locks = geom.GetVertexLocks()
	
	# Iterate over the array, set the locks 
	n = locks.GetItemCount()
	for i in range(n):
		# Lock every 5th vertex.
		if i % 5 == 0:
			locks.SetItem(i,True)
		else:
			locks.SetItem(i,False)

Working with vertex weights

The Simplygon API now provides the ability for the user to assign importance values per vertex as weights. These weights are used during reduction to keep some important features in a mesh intact (i.e facial features). This allows more artistic control during reduction process. A vertex weighting field has been added to the IGeometryData class. Use the AddVertexWeights method to add the field to an IGeometryData object.

The weight value should be a positive scalar between larger than zero, where small values means the vertices are less important to preserve. Values around 1.0 means they will be reduced just like normal. Large values will preserve the vertices accordingly.

Example - Adding vertex weights

This example shows how to add vertex weights.

cpp
void AddVertexWeightsToGeometryData(spGeometryData geom)
{
    // Add the vertex weighting field.
    geom->AddVertexWeights();
   
    // Fetch the vertex weighting field to assign data to it.
    spRealArray vertex_weights = geom->GetVertexWeights();
   
    // Every vertex has equal weighting.
    for( int v_index=0; v_index<vertex_count; ++v_index )
    {   
        vertex_weights->SetItem(v_index,10.0);
    }
}
csharp
void AddVertexWeightsToGeometryData(spGeometryData geom)
{
    // Add the vertex weighting field.
    geom.AddVertexWeights();
   
    // Fetch the vertex weighting field to assign data to it.
    spRealArray vertex_weights = geom.GetVertexWeights();
   
    // Every vertex has equal weighting.
    for( uint v_index=0; v_index<geom.GetVertexCount(); ++v_index )
    {   
        vertex_weights.SetItem((int)v_index,10.0);
    }
}
python
def AddVertexWeightsToGeometryData(geom):
	# Add the vertex weighting field.
	geom.AddVertexWeights()
	
	# Fetch the vertex weighting field to assign data to it.
	vertex_weights = geom.GetVertexWeights()
	
	# Set every vertex to a weighting of 10
	for v_index in range(geom.GetVertexCount()):
		vertex_weights.SetItem(v_index,10.0)

User fields

The Simplygon API allows users to add their own fields to geometry objects. This information is preserved, if possible, when the geometry is processed by the various tools provided by the API.

There are three types of user fields, per-vertex, per-triangle and per-corner (triangle-vertex pair) fields. Vertex fields store a tuple for each vertex in the geometry, while per-triangle and per-corner fields store a tuple for each triangle and corner respectively. Vertex fields are added with the AddUserVertexField and AddBaseTypeUserVertexField, with their triangle and corner counterparts named AddUserTriangleField, AddBaseTypeUserTriangleField, AddUserCornerField and AddBaseTypeUserCornerField. This allows the user to either add pre-existing arrays or create new ones with a specific data type.

Example - Per-corner field

This example shows how to create and retrieve a new per-corner field containing real values.

cpp
void UserFieldExample(spGeometryData geom)
{
    // Add a field storing real values for each corner.
    geom->AddBaseTypeUserCornerField( TYPES_ID_REAL,
                                      MyCornerField );
    spValueArray values = geom->GetUserCornerField(
                                      MyCornerField );
    if( !values.IsNull() )
    {
        // Cast the array to a IRealArray.
        spRealArray realArray = spRealArray::SafeCast( values ) );
       
        if( !realArray.IsNull() )
        {
            // Fill the array with per-corner data.
           
            // ...
        }
    }
}
csharp
void UserFieldExample(spGeometryData geom)
{
    // Add a field storing real values for each corner.
    geom.AddBaseTypeUserCornerField((int)BaseTypes.TYPES_ID_REAL,
                                      "MyCornerField",3);
    spValueArray values = geom.GetUserCornerField(
                                      "MyCornerField");
    if (values != null)
    {
        // Cast the array to a IRealArray.
        spRealArray realArray = spRealArray.SafeCast(values) );

        if (realArray != null)
        {
            // Fill the array with per-corner data.

            // ...
        }
    }
}
python
def UserFieldExample(geom):
	# Add a field storing real values for each corner. 
	# Name it MyUserFieldName and set the per-tuple size to 3
	geom.AddBaseTypeUserCornerField( 
		Simplygon.TYPES_ID_REAL, 
		"MyUserFieldName" , 
		3 
	)
	
	# retrieve the field
	values = geom.GetUserCornerField( "MyUserFieldName" )
	if values != None:
		# Cast the array to a spRealArray.
		realArray = Simplygon.spRealArray.SafeCast( values ) 
	   
		# If it was correctly cast, we now have an 
		# spRealArray that we can fill with data
		if realArray != None:
			# Fill the array with per-corner data, in 
			# this case, set all corners to value 3
			n = realArray.GetItemCount()
			for i in range(n):
				realArray.SetItem(i,3.0)