sealed class Tinman.Terrain.Kernel.MeshBuffer

Provides the shared buffer for terrain meshes.

Using a mesh buffer involves the following steps:

  • Create a MeshBuffer object by calling Create. A container for per-vertex CPU data must be given (see VertexArrays). Optionally, updater objects for vertex data or mesh structure data may be specified; these are usually used to populate GPU buffers, for GPU-based rendering and triangulation.

  • Create terrain meshes by calling MeshCreate. All terrain meshes will use vertices that are stored in the shared mesh buffer.

  • The mesh buffer has a background refinement thread which periodically traverses all terrain meshes, updates the tessellation and triggers background computation of vertex data. This happens automatically and is not visible to the application.

  • The mesh buffer is supposed to be accessed by a single dedicated thread in the application (usually the render thread). A separate snapshot of the terrain mesh tessellation is maintained for consistent access by the application thread.

  • The MeshUpdate and MeshUpdateData will update the terrain snapshot according to the current state of background refinement. This is a write-only access. Subsequently, the application will read from the terrain snapshot (for example, while traversing the MeshTree).

  • If an application needs to read from the terrain snapshot from another thread than the dedicated one, then the IBeginEnd.Begin and IBeginEnd.End methods must be used to wrap each read access. This will ensure that all accesses are properly synchronized: write-accesses and read-accesses are mutually exclusive, while read-accesses will be performed in parallel.

The following API will read from the terrain snapshot:

Refinement of CLOD meshes is not deterministic by default (i.e. the same input may produce slightly different outputs). To ensure deterministic behaviour, for example in a distributed render environment, the following steps must be performed:

The MeshTree.ComputeSectorHash1 method may be used to check if the shadowed structure of two meshes is equal, in order to verify that refinement is deterministic.

Public / Constructors


public static method Create → (3)

vertexData in : VertexArrays

The CPU vertex data collection.

vertexUpdater opt : IVertexUpdater own = null

The vertex data updater.

meshStructureUpdater opt : IMeshStructureUpdater own = null

The mesh structure updater.

returns → MeshBuffer

The mesh buffer object.

Creates a new instance of MeshBuffer.

If necessary, the following vertex data arrays will be created:


If vertexUpdater opt is not null and vertexData in is missing some required data arrays.

Public / Methods


public method BuildFragmentationImage → ()

returns → ColorBuffer

The color coded fragmentation image.

Builds a color-coded image that represents the fragmentation of the shared vertex buffer.

Both width and height of the image are powers of two (but not necessarily the same). Each pixel in the image represent the status of a specific vertex in the shared vertex buffer:

index(x,y)  := y * width + x
color(x,y)  := status

where width and height are the dimensions of the image, x and y are pixel coordinates, index is the mapping from pixel coordinates to zero-based vertex indices and status if the color-coded vertex status:

  • Black
    The vertex is not used by any terrain mesh.

  • Dark rainbow color
    The vertex is used by a terrain mesh and currently invisible.

  • Bright rainbow color
    The vertex is used by a terrain mesh and currently visible.

  • White
    The vertex belongs to the skeleton of a terrain mesh.

The hue of the rainbow colors indicates the level of the respective vertex in the mesh structure (i.e, the number of parent vertices, up to the root sector; see XDag).


public method CycleLimit → (1)

delta opt : int32 = 25

The refinement cycle limit to set, relative to the current refinement cycle counter value. If negative, the limit will be cleared. Positive values are a compromise between suspending refinement more often (lower values) and refreshing the refinement parameters from the application less often (higher values).

returns → int32

The resulting target value of Cycle, at which refinement will stop.

Sets or clears the refinement cycle limit.


[OwnerReturn] [ThreadSafe]
public method MeshCreate → (1)

options in : MeshOptions own

The mesh options.

returns → IMeshDynamic

The created CLOD mesh.

Creates a new dynamic terrain mesh.


If the given options in are invalid.


If MeshOptions.Geometry is null and the given geo-reference is not suitable.


public method MeshUpdate → (1)

wait opt : bool = false

true to wait for other application threads that use IBeginEnd.Begin and IBeginEnd.End to read from the current terrain snapshot, before applying the buffered mesh updates,
false to skip buffered mesh updates and return 0 when other threads are still reading from the terrain snapshot.

returns → int32

> 0 : if the vertex/index data has changed
= 0 : if no vertex/index data has changed
< 0 : if an error has occurred and the mesh buffer has entered the error state (i.e. NeedsReinitialize will return true). In this case, mesh refinement and all compute tasks will have terminated when this method returns. To recover from the error state, call Reinitialize.

Applies all buffered mesh updates, but does not update vertex data via IVertexUpdater or mesh data via IMeshStructureUpdater.

The MeshUpdateData method must be called before vertex data is used (e.g. rendering using the GPU vertex buffer). This ensures that the mesh structure is consistent with the vertex or mesh data that has been sent to the IVertexUpdater resp. IMeshStructureUpdater object.

The call to MeshUpdateData may be omitted iff the vertex data is not used. Calling the MeshUpdateData more than once with the same arguments is allowed, but will have no effect.


public method MeshUpdateData → (2)

vertexData opt : bool = true

Update vertex data via VertexUpdater?

meshData opt : bool = true

Update mesh data via MeshStructureUpdater?

returns → int64

The amount of data that has been updated, in bytes.

Performs all vertex data and mesh structure updates that have been left out during the last call to MeshUpdate.

This method can be called multiple times, data updates will only be performed once.


public method Reinitialize → ()

Re-initializes the mesh buffer and all meshes, in order to recover from the error state.

This method must be called after MeshUpdate has returned a negative value, in order to recover from the pending error state. Calling this method when there is no error state is allowed, but has no effect.


public method ReinitializeTest → (1)

error opt : int32 = 1

A bitmask that indicates which error to fake:
1 : fake an error in the refinement thread,
2 : fake an error a the compute task.
Any fake error that is included in the bitmask may be generated.

Forcibly generates a fake internal error, in order to test error detection and recovery via MeshUpdate and Reinitialize.

This method should only be used for testing the behaviour of an application when responding to a the mesh buffer error state.

Public / Attributes


public attribute AllowSleep → (get,set)

value : bool

true to allow sleeping, false to disallow it.

Allow the refinement thread to sleep for a short period of time when little or no refinement work is necessary?

The default value is true.


public attribute CountUnused → (get)

value : int32

The number of unused mesh buffer vertices.

Returns the number of vertices that are currently not exposed to the application by any mesh and that may be re-used for mesh refinement.

Unused vertices may either be recycled for being used elsewhere or they may be reactivated for use in their current mesh. Since only leaf vertices can be re-used for mesh refinement, this count will usually not be equal to the mesh buffer capacity:

Capacity = CountUnused + CountVisible + N

where N is the number of unused non-leaf vertices. If this counter drops to zero, mesh refinement will not be able to use new vertices to add detail to the terrain.


public attribute CountVisible → (get)

value : int32

The number of visible mesh vertices.

Returns the number of visible vertices in all meshes.

As a rule of thumb, the number of visible vertices should be roughly 50% of the mesh buffer capacity, so that vertex caching may contribute to performance.


public attribute Cycle → (get)

value : int32

The refinement cycle counter.

Returns the refinement cycle counter of this mesh buffer.

The background refinement thread continuously runs refinement cycles and increments the counter for each cycle. This property returns the cycle counter value that corresponds to the state that has been established by the most recent call to MeshUpdate.


public attribute MeshStructureUpdater → (get)

value : IMeshStructureUpdater

The mesh structure updater or null.

Returns the mesh structure updater of this mesh buffer.


public attribute NeedsReinitialize → (get)

value : bool

true if MeshUpdate has returned a negative value and Reinitialize must be called,
false if there is no mesh buffer error.

Is the mesh buffer in an error state and needs to be reinitialized?

The mesh buffer can enter the error state in one of the following cases:

  • An IOException is thrown by IHeightmap.GetSamples, for example because the internet connection is down. A warning log message will be generated in this case.

  • An unexpected exception is thrown in one of the components that have been passed to the mesh buffer:

    This usually indicates a code bug in the component. In this case, please file a bug report, if the component belongs to the Tinman 3D SDK.

  • An unexpected internal error has occurred in the mesh buffer, the refinement thread or a compute task. In this case, please file a bug report.

When entering the error state, background mesh refinement stops and all pending compute tasks are cancelled. While in the error state, the application may still use all terrain meshes in their current state. Refinement will be frozen until the mesh buffer recovers from the error state.


public attribute VertexArrays → (get)

value : VertexArrays

The vertex data collection.

Returns the CPU vertex data collection of this mesh buffer.


public attribute VertexUpdater → (get)

value : IVertexUpdater

The vertex updater or null.

Returns the vertex updater of this mesh buffer.