This page has been translated automatically.
Video Tutorials
Interface
Essentials
Advanced
How To
Basics
Rendering
Professional (SIM)
UnigineEditor
Interface Overview
Assets Workflow
Version Control
Settings and Preferences
Working With Projects
Adjusting Node Parameters
Setting Up Materials
Setting Up Properties
Lighting
Sandworm
Using Editor Tools for Specific Tasks
Extending Editor Functionality
Built-in Node Types
Nodes
Objects
Effects
Decals
Light Sources
Geodetics
World Nodes
Sound Objects
Pathfinding Objects
Players
Programming
Fundamentals
Setting Up Development Environment
Usage Examples
C++
C#
UnigineScript
UUSL (Unified UNIGINE Shader Language)
Plugins
File Formats
Materials and Shaders
Rebuilding the Engine Tools
GUI
Double Precision Coordinates
API Reference
Animations-Related Classes
Containers
Common Functionality
Controls-Related Classes
Engine-Related Classes
Filesystem Functionality
GUI-Related Classes
Math Functionality
Node-Related Classes
Objects-Related Classes
Networking Functionality
Pathfinding-Related Classes
Physics-Related Classes
Plugins-Related Classes
IG Plugin
CIGIConnector Plugin
Rendering-Related Classes
VR-Related Classes
Content Creation
Content Optimization
Materials
Material Nodes Library
Miscellaneous
Input
Math
Matrix
Textures
Art Samples
Tutorials

Systems

Async Queue#

This sample shows how to load resources like meshes and textures in the background using the AsyncQueue class. Files are loaded in a separate thread, so the main application stays responsive.

Meshes and textures are added to the loading queue, and the system listens for events to know when each resource is ready. When a mesh finishes loading, it's removed from the queue. For textures, an event handler is used to handle their completion. The sample also demonstrates how to group and manage resource requests, making it easier to control the loading process.

This kind of async loading is useful for streaming large levels, loading assets on demand in VR, or preloading data in simulations without freezing the interface.


SDK Path: <SDK_INSTALLATION>source/systems/async_queue

Async Queue Stress#

This sample demonstrates how to asynchronously load large number of nodes using the AsyncQueue class while ensuring correct activation on the main thread.

In UNIGINE, world nodes must be created only from the main thread. To comply with this restriction and avoid blocking the main thread, the sample performs the initial node loading in a background thread, and then schedules a follow-up task on the main thread to finalize activation by calling updateEnabled() - a method that registers the node and its children in the world's spatial structure.

With the built-in Profiler enabled, you can observe how the engine handles increasing load smoothly and avoids frame spikes.

Refer to the AsyncQueue class API for detailed information on available execution modes, thread types, and priorities.


SDK Path: <SDK_INSTALLATION>source/systems/async_queue_stress

Async Queue Tasks#

This sample demonstates how to schedule and run different types of tasks using the AsyncQueue class. It shows how to execute operations in different thread types, control thread count, and choose whether tasks should complete within the current frame or run freely in the background.

  • Async - non-blocking execution in a single thread. Useful for offloading tasks without stalling the main thread.
  • Async Multithread - parallel execution across multiple threads. Each thread receives its own portion of work. Does not block the caller.
  • Frame-Async Multithread - same as Async Multithread, but ensures all threads complete their tasks within the current frame.
  • Sync Multithread - multi-threaded execution that blocks the calling thread until all threads finish.
  • Frame-Sync Multithread - same as Sync Multithread, but ensures all threads complete their tasks within the current frame.

Refer to the AsyncQueue class API for detailed information on available execution modes, thread types, and priorities.


SDK Path: <SDK_INSTALLATION>source/systems/async_queue_tasks

Cad-Like View#

This sample demonstrates how to build a CAD-style layout by combining four synchronized views of the same scene: top, side, front, and perspective. Each view uses its own camera with a separate projection matrix - orthographic for technical views and perspective for the main one. Each view is rendered off-screen and displayed through a WidgetSpriteViewport.

The views are arranged in a 2x2 grid using GUI widgets. When the window is resized, texture resolutions are automatically updated to match the new layout and keep the viewports sharp.

Viewcubes are centered on the main object to maintain consistency across all views. They help indicate camera orientation and are updated based on the window size and viewport positions.

This setup is ideal for tools that require accurate inspection of a scene from multiple directions, such as modeling, level design, or CAD-style applications.


SDK Path: <SDK_INSTALLATION>source/systems/cad_like_view

Callbacks#

This sample demonstrates how to use the CallbackBase class via the C++ API to wrap and call functions and class methods with various numbers of arguments.

Callbacks are created using the MakeCallback method for both standalone functions and member methods, including parameterized versions with up to four arguments. Once created, callbacks can be executed using CallbackBase::run() method, optionally passing different arguments at runtime. This allows storing and triggering functions dynamically through a unified interface.

Callback mechanism is useful in scenarios such as event-driven systems, user interface interactions, or asynchronous task management in applications requiring dynamic function invocation.


SDK Path: <SDK_INSTALLATION>source/systems/callbacks

Console#

This sample demonstrates how to interact with the engine's built-in console and add custom console commands and variables via API using the Console and ConsoleVariable classes.

It shows how to define different types of console variables: ConsoleVariableInt, ConsoleVariableFloat, and ConsoleVariableString, and how to register custom console commands. Commands are linked to callback functions using MakeCallback, and can be executed directly from code or entered manually through the console.

Commands can also be added and removed dynamically at runtime, making the system flexible for various use cases. Console variables can be accessed or changed through both code and the console interface.

This can be used for development, debugging, rapid prototyping, and runtime adjustments in interactive applications.


SDK Path: <SDK_INSTALLATION>source/systems/console

CPU Shader#

This sample demonstrates how to implement a custom CPU shader by inheriting from the CPUShader class to perform multi-threaded data processing outside the main rendering loop.

The system updates multiple ObjectMeshCluster instances asynchronously by using a helper AsyncCluster structure. Each cluster maintains two versions of itself: one for rendering and one for background updates. At the end of each frame, the two are swapped so the visible cluster always shows the latest result without stalling the frame.

The parallel logic is encapsulated in a derived shader class UpdateClusterCPUShader, where the process() method is overridden to perform per-cluster updates. This method is automatically dispatched using CPUShader::runAsync(), allowing the workload to be spread across available CPU threads. Swap operations, visibility checks, and update decisions are handled independently for each cluster.

This approach is particularly effective for real-time procedural animation, large-scale mesh updates, or any CPU-side logic that benefits from multithreading while remaining synchronized with rendering.


SDK Path: <SDK_INSTALLATION>source/systems/cpu_shader

Events#

This sample demonstrates four different patterns for subscribing UNIGINE's Events via the C++ API, highlighting how event handler lifetime and management can vary depending on the approach.

Each method demonstrates a different strategy for connecting to the same event and managing event handler lifetimes:

  • EventConnectionExample stores a single event handler with manual control over its activation. This type of connection is useful when you need precise control — you can enable, disable, or fully disconnect the handler at any time.
  • EventConnectionsExample acts as a container for multiple handlers. It handles cleanup automatically (via the destructor) and manually (by calling EventConnections::disconnectAll()). This is useful when you have many event handlers with varying lifetimes that need to be grouped.
  • InheritedEventConnectionExample inherits EventConnections class, making connection management part of its internal logic. All connected handlers are automatically disconnected when the object is destroyed.
  • CallbackIDConnection provides a low-level, manual way to manage handlers using a connection ID. It offers flexibility but requires careful memory and lifetime handling. This approach is considered unsafe and should only be used when you fully understand the implications.

Each example connects to a shared EventHolder, and handlers are triggered with a sample value. This setup is useful when designing modular, reactive systems that rely on flexible and explicit event-driven logic.


SDK Path: <SDK_INSTALLATION>source/systems/events

Events Advanced#

This sample demonstrates advanced usage of the UNIGINE event system.

EventsAdvancedSample.cpp triggers custom rotation events when specific keys are pressed. Each event passes one or more arguments to connected listeners.

EventsAdvancedUnit.cpp shows how to connect various types of handlers, including:

  • Class methods with extra arguments
  • Free functions with discarded or additional arguments
  • Lambdas using connectUnsafe()
  • Storing connections using EventConnection or EventConnectionId for later disconnection

This sample helps understand flexible patterns for event handling in modular component systems.


SDK Path: <SDK_INSTALLATION>source/systems/events_advanced

External Package#

This sample demonstrates how to create a custom data package using code and use it to generate objects in the scene.

Package is a collection of files and data for UNIGINE projects stored a single file. The Package class is a data provider for the File System. You can use it to load all necessary resources.

The ExternalPackage class describes the generation of a mesh (in this case, a box) and its saving to a temporary file at a specified path. The class also implements an interface for searching, reading, and retrieving information about files within the package.

The ExternalPackageSample class adds the created external package, and its contents are used to create meshes with different positions and orientations. This approach allows for quick and convenient management of a large number of objects without adding them by hand.

Packages can be used to conveniently transfer files between your projects or exchange data with other users, be it content (a single model or a scene with a set of objects driven by logic implemented via C# components) or files (plugins, libraries, execution files, etc.).

Using this example will help you understand how to organize work with external files, create and manage your own data packages, implement a mechanism for loading and reading data from a package.


SDK Path: <SDK_INSTALLATION>source/systems/external_package

Ffp#

This sample demonstrates how to render a simple 2D shape using the Fixed Function Pipeline (Ffp) in UNIGINE via the C++ API. A colorful figure composed of 16 vertices is drawn directly on screen using orthographic projection.

The rendering logic is called every frame by hooking into the engine's render loop. Ffp mode is enabled for drawing and then disabled, keeping this rendering isolated from the rest of the frame.

This approach is useful for quick visualization overlays, editor tools, or debugging tasks where shader-based rendering isn't required.


SDK Path: <SDK_INSTALLATION>source/systems/ffp

File#

This sample shows how you can create a text file and display its contents inside the widget via C++ API by using the File class. To create a text file, type the text from keyboard inside the Writer widget and press Write to save. Click Read inside the Reader widget to display the recorded information. The saved information will be displayed in the same widgets when you start the sample next time.
SDK Path: <SDK_INSTALLATION>source/systems/files

Images#

This sample shows how to procedurally generate 3D image data and use it as a density texture for a volume-based material in real time.

The result is visualized using a volume box that updates dynamically every frame based on custom field simulation.

The sample initializes a 3D image with a predefined resolution and fills it with voxel data derived from a set of moving fields. Each field represents an abstract spherical influence zone that contributes to the voxel density based on distance. Field dynamics are updated every frame to simulate motion.

The raw image data is accessed directly via a pixel pointer and modified per frame, with density values mapped to RGBA channels. The resulting image is then uploaded to a material as a 3D texture used in a volumetric shading model.

The sample demonstrates how to work with the Image class and update GPU resources efficiently at runtime. This approach can be used for generating volumetric effects such as clouds, fog, or procedurally driven visual phenomena.


SDK Path: <SDK_INSTALLATION>source/systems/images

Multiple Async Requests#

This sample demonstrates how to launch and manage a large number of asynchronous ray-based intersection queries simultaneously.

The results are visualized in real time and latency statistics are displayed for performance analysis.

In this sample, an emitter object continuously rotates and moves vertically, casting rays in multiple directions (slices and stacks) to detect intersections with objects in the world. Each ray is handled asynchronously.

All active requests are monitored for completion. Once finished, the results (intersection points and normals) are visualized using Visualizer tools. A latency histogram is computed based on how many frames passed between the request and response, and the results are displayed in the UI.

The sample uses double-buffering for safe multi-threaded access and demonstrates efficient scheduling of a high number of asynchronous operations. This approach is useful for stress-testing intersection systems, profiling async request latency, or building interactive tools relying on high-frequency spatial queries.


SDK Path: <SDK_INSTALLATION>source/systems/intersection_multiple_async_requests

Simple Async Requests#

This sample demonstrates how to perform a single asynchronous intersection query based on the user's mouse cursor position in the scene. The result includes the hit point and surface normal, which are visualized in the scene, along with latency information.

The sample demonstrates detection of intersections with all objects in the world using a combination of World::getIntersection() and Landscape::getIntersection() methods. A single ray is cast from the current camera position through the mouse cursor. If the ray intersects with any geometry, the hit point and surface normal are rendered using Visualizer. Intersection queries are handled asynchronously. A callback processes the result and records latency in frames. The average and maximum latency values are updated in real time and shown in the sample UI.

This setup demonstrates how to implement non-blocking intersection queries suitable for object selection or similar real-time input-driven interactions.


SDK Path: <SDK_INSTALLATION>source/systems/intersection_simple_async_request

JSON#

This sample shows how to generate a structured JSON document containing objects, arrays, and various data types such as strings, numbers, booleans, and null values. It also demonstrates how to traverse and print this structure recursively with indentation, imitating a pretty-printed output.

The sample begins by constructing a custom JSON structure in memory using Json::create() and its child manipulation methods. Nodes are added dynamically and include both named and unnamed children of various types. Once built, the structure is traversed recursively and printed to the console in a readable format using indentation and commas, based on node type and position. The code demonstrates how to distinguish between arrays, objects, and primitive values when printing.

This sample is useful for learning the basics of JSON manipulation, such as creating structured data, traversing an element tree, and formatting output. It can serve as a foundation for processing JSON data (e.g., responses to REST API requests), as well as for complex serialization or debugging tools.


SDK Path: <SDK_INSTALLATION>source/systems/json

Materials and Properties#

This sample demonstrates how to access all materials and properties in the project via API.

The sample iterates through the list of registered in the Property Manager via Properties::getProperty() and prints out the names and child counts for each. It also gets all available materials from the Materials Manager via Materials::getMaterial(), and lists them along with their file paths and number of children.

This can be used as a reference for accessing and working with project assets at runtime - whether for inspection, dynamic assignment, or content management logic.


SDK Path: <SDK_INSTALLATION>source/systems/materials_and_properties

Microprofiler#

This sample demonstrates methods for tracking performance and estimating the time spent on different sections of code. For this purpose, it uses Microprofile, an advanced CPU/GPU profiler with per-frame inspection support.

Profiling is crucial for identifying performance bottlenecks and optimizing code execution. This analysis helps you understand if any code sections negatively impact the project's speed.


SDK Path: <SDK_INSTALLATION>source/systems/microprofiler

Procedural Mesh Apply#

This sample demonstrates the correct order of operations for modifying and applying procedural mesh data at runtime. It serves as a minimal example showing how to build geometry, configure procedural mode, and apply changes to an ObjectMeshCluster. The same workflow and apply methods are also available for other objects that support procedural meshes, such as ObjectMeshStatic, ObjectGuiMesh, DecalMesh, and ObjectMeshClutter.

Inside the component's code, you'll find a linear implementation of the procedural mesh pipeline, demonstrating how geometry is generated and applied in the correct order.

Use this sample to understand the basic flow of procedural mesh updates and try adjusting configurations to find what best suits your needs.

Refer to the Procedural Mesh Workflow article for more details on memory behavior, update strategies, and best practices when working with procedural geometry.


SDK Path: <SDK_INSTALLATION>source/systems/procedural_mesh_apply

Procedural Mesh Generation#

This sample demonstrates how to generate static mesh geometry at runtime using different procedural mesh generation methods. A grid of ObjectMeshStatic objects is created, each receiving its geometry from a user-defined callback that builds a box-shaped mesh surface via the Mesh API.

You can experiment with various procedural modes (such as Dynamic, File, or Blob), as well as configure how geometry is stored and accessed by selecting different MeshRender usage flags (DirectX 12 only). These flags determine whether vertex and/or index data is kept in RAM instead of VRAM, allowing the GPU to render directly from system memory.

  • Dynamic - fastest performance, stored in RAM and VRAM, not automatically unloaded from memory.
  • Blob - moderate performance, stored in RAM and VRAM, automatically unloaded from memory.
  • File - slowest performance, all data stored on disk, automatically unloaded from memory.

The Field Size parameter defines how many mesh objects are generated along each axis, forming a square grid.

For each configuration, the sample shows total RAM and VRAM usage, along with the number of active mesh objects. This makes it easier evaluate the performance, memory layout, and behavior of each procedural mode in different runtime conditions.

Use this sample to understand how procedural mesh generation works across different modes, observe how geometry is stored and managed between RAM, VRAM, and disk, profile memory usage for small versus large number of procedural objects, and explore how update strategies influence performance.

Refer to the Procedural Mesh Workflow article for more details on memory behavior, update strategies, and best practices when working with procedural geometry.


SDK Path: <SDK_INSTALLATION>source/systems/procedural_mesh_generation

Procedural Mesh Modification#

This sample demonstrates how to dynamically generate, modify, and apply procedural geometry at runtime using different procedural mesh modification methods.

The dynamic surface mesh being built and animated over time using trigonometric functions. The geometry is rebuilt each frame depending on current configuration.

You can experiment with various procedural modes (such as Dynamic, File, or Blob), as well as configure how geometry is stored and accessed by selecting different MeshRender usage flags (DirectX 12 only). These flags determine whether vertex and/or index data is kept in RAM instead of VRAM, allowing the GPU to render directly from system memory.

Additionally, you can choose whether mesh generation occurs on the Main thread or in the Background, giving you more control over performance and responsiveness during updates.

  • Dynamic - fastest performance, stored in RAM and VRAM, not automatically unloaded from memory.
  • Blob - moderate performance, stored in RAM and VRAM, automatically unloaded from memory.
  • File - slowest performance, all data stored on disk, automatically unloaded from memory.

You can also toggle between different update modes (Async or Force), choose memory transfer strategies (Copy or Move), and optionally enable manual control of the MeshRender, where you update its content explicitly after modifying mesh data, instead of relying on automatic updates. Additionally, collision data can be generated explicitly after geometry modification, as it is not created automatically.

Use this sample to understand how procedural mesh modification works across different configurations and explore how update strategies influence performance.

Refer to the Procedural Mesh Workflow article for more details on memory behavior, update strategies, and best practices when working with procedural geometry.


SDK Path: <SDK_INSTALLATION>source/systems/procedural_mesh_modification

Stream Base#

This sample demonstrates how to create a custom stream class by inheriting from StreamBase and use it for reading from and writing to files. The resulting stream is used to serialize and deserialize basic data types to and from a binary file.

The sample provides a wrapper around standard C file I/O functions and integrates with the UNIGINE stream system by implementing the StreamBase interface. In the sample logic, a binary file is first created and filled with data via Stream::writeString(), writeInt(), and writeFloat(). Then the file is reopened in read mode and the same values are read back using the corresponding Stream 'read' methods, verifying the functionality of the custom stream.

This example serves as a reference for implementing custom stream sources (e.g., from memory, network, or virtual filesystems) and integrating them with the engine's serialization tools.


SDK Path: <SDK_INSTALLATION>source/systems/stream_base

Thread#

This sample shows how to define and manage background threads in UNIGINE by inheriting from the Thread class and overriding the process() method.

Two custom thread types are demonstrated:

  1. InfiniteThread - continuously outputs messages while running.
  2. CountedThread - performs a finite number of iterations before completing.

Threads are started during component initialization and executed in parallel with the main engine loop. The infinite thread is explicitly stopped via stop() once the counted thread completes all iterations.

This sample illustrates basic principles of multithreading and can serve as a foundation for offloading computations or I/O operations from the main thread.


SDK Path: <SDK_INSTALLATION>source/systems/thread

Two-Point Perspective#

This sample shows how to simulate a two-point perspective projection using a lens shift technique implemented via a secondary Dummy Player. When enabled, the sample dynamically adjusts the projection matrix of a dummy camera to visually align vertical lines while preserving the viewing direction.

The effect is achieved by adjusting the projection matrix of a PlayerDummy instance according to the pitch angle of the active camera. During the rendering phase, the Dummy Player temporarily replaces the main camera to apply the modified view.

This approach can be used for architectural visualization or stylized camera effects where a more orthographic-like vertical perspective is desired.


SDK Path: <SDK_INSTALLATION>source/systems/two_point_perspective

USC Arrays#

This sample showcases integration between C++ and UnigineScript by registering external C++ functions that manipulate UnigineScript array types.

The registered functions allow for setting and getting values, generating test data, and enumerating the contents of both ArrayVector (indexed container) and ArrayMap (associative container).


SDK Path: <SDK_INSTALLATION>source/systems/usc_arrays

USC Callbacks#

This sample demonstrates how to call UnigineScript functions from C++ code via callbacks.

The mechanism is based on Variable Class instances and allows calling both custom and built-in script functions by name.

The sample registers a C++ wrapper function to expose script invocation capability to UnigineScript via the Interpreter class.


SDK Path: <SDK_INSTALLATION>source/systems/usc_callbacks

USC Classes#

This sample demonstrates how to export classes from C++ side to UnigineScript.

A simple C++ class named ExternClass is used to export custom MyExternObject into the UnigineScript environment. This allows scripts to instantiate the class, call its methods, and interact with its properties at runtime.


SDK Path: <SDK_INSTALLATION>source/systems/usc_classes

USC Functions#

This sample demonstrates how to export functions from C++ side to UnigineScript. It includes examples of exporting regular functions, handling multiple data types, and registering class members for a singleton-like object.
SDK Path: <SDK_INSTALLATION>source/systems/usc_functions

USC Inheritance#

This sample demonstrates how to work with UnigineScript containers via C++ API. It showcases class composition, constructor registration, base-to-derived linkage, and virtual method exposure within a scripting context.

Each class in the hierarchy is registered via the Interpreter class, allowing scripts to instantiate and interact with derived types, call inherited methods, and override behavior.


SDK Path: <SDK_INSTALLATION>source/systems/usc_inheritance

USC Stack#

This sample demonstrates how to use a stack implemented via C++ in UnigineScript.

The sample defines a simple formatter function on the C++ side. This function takes a format string and substitutes tokens with values popped from a runtime stack. Values are passed from the script and pushed onto the stack prior to the call.


SDK Path: <SDK_INSTALLATION>source/systems/usc_stack

USC Structures#

This sample demonstrates how to expose C++ structs to UnigineScript using the Interpreter class.

It defines a simple C++ structure MyVector with four float fields (x, y, z, w) and registers it. Each field is mapped via explicit getter and setter methods to allow full read/write access from the UnigineScript side.


SDK Path: <SDK_INSTALLATION>source/systems/usc_structures

USC Transfer#

This sample demonstrates how to transfer complex data between UnigineScript and C++ using the Variable class and the TypeToVariable utility.

The example shows several ways to pass and return Image objects between script and native code. It compares direct object passing, conversion via Variable, and using TypeToVariable.


SDK Path: <SDK_INSTALLATION>source/systems/usc_transfer

USC Types#

This sample demonstrates how to enable type conversion between custom C++ types and UnigineScript using the Variable class.

A user-defined MyVector3 class is introduced to represent a 3D vector. To integrate this class with the UnigineScript environment, custom specializations of the TypeToVariable and VariableToType templates are implemented. These allow automatic conversion between MyVector3 and vec3 values inside the UnigineScript runtime.


SDK Path: <SDK_INSTALLATION>source/systems/usc_types

USC Variables#

This sample demonstrates how to work with different variable types in UnigineScript using the Variable class from C++ code.

Various types (int, long, float, double), and vector types (vec3, vec4, dvec3, etc.), are wrapped in Variable objects and passed into a UnigineScript callback function.


SDK Path: <SDK_INSTALLATION>source/systems/usc_variable

Visualizer#

This sample demonstrates the full range of features provided by the Visualizer class for visual debugging.

The sample illustrates how to use Visualizer for debugging node positions, physics vectors, bounding volumes, and custom geometry in both world space and screen space. Use controls to explore the area.

VisualizerUsage.cpp renders a wide range of primitives including points, lines, boxes, frustums, spheres, capsules, and object bounds using Visualizer methods.

2D visualizer features can be toggled on and off via the corresponding checkboxes.

Enable or disable depth testing, toggle specific primitives, and inspect how different rendering options behave in real time.


SDK Path: <SDK_INSTALLATION>source/systems/visualizer

Xml#

This sample demonstrates how to create and manipulate an XML document using the Xml class.

The sample creates a nested XML tree with multiple child nodes, each containing arguments and optionally a text value. The structure is built using the Xml::addChild() method, and the arguments are parsed using Xml::getArgName() and Xml::getArgValue(). After construction, the XML tree is traversed recursively to display the structure and all attributes in the console output.

This approach demonstrates the use of the Xml class for working with hierarchical data, which is useful for config files, level data, and other structured content in XML format.


SDK Path: <SDK_INSTALLATION>source/systems/xml

The information on this page is valid for UNIGINE 2.20 SDK.

Last update: 2025-07-25
Build: ()