UnigineEditor
Interface Overview
Assets Workflow
Settings and Preferences
Working With Projects
Adjusting Node Parameters
Setting Up Materials
Setting Up Properties
Landscape Tool
Using Editor Tools for Specific Tasks
Extending Editor Functionality
Programming
Fundamentals
Setting Up Development Environment
Usage Examples
UnigineScript
C++
C#
UUSL (Unified UNIGINE Shader Language)
File Formats
Rebuilding the Engine and Tools
GUI
Double Precision Coordinates
API
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

API Migration

Major Changes#

Breaking Changes#

Removal and Deprecation List#

We’ve removed the NodePivot as redundant, as you actually can control transformation of a group of nodes by simply building their hierarchy placing dependent ones as children of the one considered as the main one.

Layers, Clusters, and Clutters#

WorldLayer, WorldClutter, and WorldCluster classes are considered deprecated and will be removed in the next release. Starting from 2.11 creation of these nodes is not available in the UnigineEditor. In case your project contains World Layers, we strongly recommend to replace them with NodeLayers, as this significantly reduces spikes and makes your application run smoothly. After a set of performance optimizations including the ones related to spatial tree management and others described below, the World Layer no longer provides any performance gain. Removing it from the world will slightly increase RAM consumption (5-25%, depending on the contents of the layer) but will surely reduce spikes as this node loads the spatial tree heavily. World Clusters no longer provide any performance gain as well, as separate objects became fast enough after optimization.

WorldCluster / WorldClutter will continue to work as before (at least in 2.11), but without any fixes or new features. More likely these objects will also be removed in 2.12.

We strongly recommend using Mesh Clutters and Mesh Clusters in your projects as they provide significant performance gain!

Sectors and Portals#

We’ve decided to remove sectors and portals. Apart from being rarely used, their old implementation gets more unsolvable issues and unacceptable incompatibilities due to active Engine development.

In case you used sectors and portals in your project we recommend replacing them with occluders (either world or mesh). Occluders are clear and straightforward, they are faster, work more stable and offer more flexibility in world building. In case you need to create a room with a door and cut out everything beyond its walls, simply place occluders along the room’s perimeter. Make sure such occluder-walls have zero-width to gain even more performance!

Dataset Classes#

Removed Dataset, DatasetRasterPosResolver, DatasetSpatialReference, and DatasetCoordinateTransformer classes from the Engine’s API, since they are far from being a generic Engine feature and represented a very specific and limited wrapper for GDAL functionality.

You are free to use GDAL directly without any limitations of an intermediate level. You can consider the Geodetics plugin code as an example of GDAL initialization. In case the removed classes are required for your project, or you’d like to use them as an example of using GDAL functionality to implement your own logic, we will send you the corresponding code on-demand. To get the code please contact us via the private helpdesk.

Node Update Changes#

Updating of Engine's logic for objects (simulation of particles, water, cloth, or ropes, and playback of skinned mesh animations) is now controlled via the set of Periodic Update parameters with visibility of an object having an impact on how often it is updated.

The list of objects that require to be updated now includes the following:

For each of them you can now specify an Update Distance Limit - a distance from the camera up to which the object should be updated.

In addition to that, for Particle Systems, Skinned and Dynamic Meshes, you can set the following update rate values:

  • FPSVisibleCamera - for the case when the object is rendered to viewport
  • FPSVisibleShadow - when only its shadow is rendered (here we can cut even more)
  • FPSInvisible - when the object is not rendered at all.

Before 2.11 to enable force updating for a node you could use the addUpdateNode() method of the World class. Now to enable constant updating for an object regardless of its visibility you can set the Update Distance Limit and corresponding update rate values for it to infinity:

UNIGINE 2.10 UNIGINE 2.11
Source code (C++)
World::addUpdateNode(object);
Source code (C++)
object->setUpdateDistanceLimit(Consts::INF);
object->setFPSInvisible(Consts::INF);
object->setFPSVisibleShadow(Consts::INF);
object->setFPSVisibleCamera(Consts::INF);

For example this can be used in case in your project you have an invisible particle system (e.g., using the viewport mask) and some logic attached to its update (e.g. spawning some visible particles on collision with objects).

Bounds Calculation Changes#

Some nodes having their bounds defined by the bounds of their children, such as DummyNode, NodeReference, or NodeLayer, especially the ones with complex hierarchies took a lot of time to recalculate such hierarchical bounds. Moreover, calculation sometimes was incorrect, for example, in case the hierarchy contained skinned meshes or particle systems having their bounds changed every frame, as recalculation of all bounds in the hierarchy every frame would certainly drop performance drastically in projects with sophisticated node hierarchies.

We have revised the whole bounds system making it fast, clear and straightforward. The following "abstract" objects (having no visual representation or their own size) now do not have bounds at all and therefore are excluded from the spatial tree: DummyNode, NodeReference, NodeLayer, WorldSwitcher, WorldTransformPath, WorldTransformBone, WorldExpression, and ObjectDummy (if it has no body assigned). This significantly reduces the size of the tree and improves performance due to saving time on bound recalculation when transforming such nodes.

The following types of bounds are used:

  • Local Bounds - bound objects with local coordinates which do not take into account physics and children: BoundBox, and BoundSphere.
  • World Bounds - same as local ones, but with world coordinates: WorldBoundBox and WorldBoundSphere.
  • Spatial Bounds - bound objects with world coordinates used by the spatial tree, and therefore taking physics into account (shape bounds, etc.): SpatialBoundBox and SpatialBoundSphere.
    Notice
    Spatial bounds are calculated faster than World ones.

And their hierarchical analogues (taking into account all children) to be used where hierarchical bounds are required (they are slow, but offer correct calculations):

  • Local Hierarchical Bounds - bound objects with local coordinates taking bounds of all node’s children into account: HierarchyBoundBox and HierarchyBoundSphere.
  • World Hierarchical Bounds - same as local ones, but with world coordinates: HierarchyWorldBoundBox and HierarchyWorldBoundSphere.
  • Spatial Hierarchical Bounds - hierarchical bound objects used by the spatial tree, and therefore taking physics into account (shape bounds, etc.): HierarchySpatialBoundBox and HierarchySpatialBoundSphere.

New Spatial Hierarchical Bounds are equivalent to former bounds of a NodeDummy with all its hierarchy.

Regarding the changes described above you should pay attention to the following:

  • Intersections are detected only for nodes having bounds. So, to find an intersected NodeReference or a NodeDummy you’ll have to find one running up the hierarchy from an intersected node.
  • WorldExpression node does not take into account bounds of its children anymore, only its own. So, it is now critical to update its size in a timely manner to ensure proper behavior.

Physics Intersection Changes#

We have changed the way of detecting intersections - world intersections (i.e. between object bound volumes, or ray intersections with object surfaces) and physics intersections (between physical objects with bodies and collider shapes, or ray intersections with collider geometry) now use separate masks, enabling you to control them independently, which gives more flexibility. So, a new Physics Intersection option with its own Physics Intersection Mask were added to the list of surface parameters.

Physics intersections can be used, for example, to detect collisions of spawned particles with physical shapes and bodies or static collider surfaces to ensure proper interaction, or as a quick way to detect collisions for raycast-wheels of a simulated ground vehicle, or to check if a destructible object was hit by a projectile. Particle systems, shapes, fracture bodies, and wheel joints now use the new Physics Intersection mask.

The Intersection option and the Intersection mask remain responsible for such features as selecting and highlighting objects under the mouse cursor, or cutting grass in areas occupied by other objects.

To manage detection of physics intersections for a surface you can use the following new methods of the Object class:

The Intersection option of the ObjectParticles class was renamed as Physics Intersection:

UNIGINE 2.10 UNIGINE 2.11
ObjectParticles::setIntersectionMask() Renamed as ObjectParticles::setPhysicsIntersection().
ObjectParticles::getIntersectionMask() Renamed as ObjectParticles::getPhysicsIntersection().

New Physics Intersection mask replaces the Intersection mask in the following cases:

UNIGINE 2.10 UNIGINE 2.11
JointWheel::setIntersectionMask() Renamed as JointWheel::setPhysicsIntersectionMask().
JointWheel::getIntersectionMask() Renamed as JointWheel::getPhysicsIntersectionMask().
Shape::setIntersectionMask() Renamed as Shape::setPhysicsIntersectionMask().
Shape::getIntersectionMask() Renamed as Shape::getPhysicsIntersectionMask().
BodyFracture::setIntersectionMask() Renamed as BodyFracture::setPhysicsIntersectionMask().
BodyFracture::getIntersectionMask() Renamed as BodyFracture::getPhysicsIntersectionMask().
PlayerActor::setIntersectionMask() Renamed as PlayerActor::setPhysicsIntersectionMask().
PlayerActor::getIntersectionMask() Renamed as PlayerActor::getPhysicsIntersectionMask().

Automatic Collider Detection#

Collision detection is now automatically enabled for an object if it has a body assigned or at least one of its surfaces has the Collision flag set. This makes the Collider flag of the node redundant - so we removed it. Fewer boxes to check - simpler adjustment and less chance to make a mistake (false-colliders waste resources).

So, instead of setting the Collider flag via setCollider() for an object in 2.10, in 2.11 you should either enable collision detection per surface via setCollision() per surface or assign a physical body to it via the setBody() method:

UNIGINE 2.10 UNIGINE 2.11
Source code (C++)
object->setCollider(1);
Source code (C++)
object->setCollision(true, 0);
// or
object->setBody(some_body);

For more information on collision detection please refer to the Collision Detection article.

Mouse Control#

Mouse behavior is now controlled directly via API without using defines. You can either select the desired behavior in the UnigineEditor or set it via code and change on the fly, if required.

In the Editor, open Windows -> Settings -> Controls and set the required mouse handle:

  • Grab - the mouse is grabbed when clicked (the cursor disappears and camera movement is controlled by the mouse).
  • Soft - the mouse cursor disappears after being idle for a short time period.
  • User - the mouse is not handled by the system (allows input handling by some custom module).

In your code (world or system logic, components, expressions, etc.), you can set the mouse behavior as follows:

Source code (C++)
ControlsApp::setMouseHandle(Input::MOUSE_HANDLE_GRAB);
// or
ControlsApp::setMouseHandle(Input::MOUSE_HANDLE_SOFT);

C# Code

Source code (C#)
ControlsApp.MouseHandle = Input.MOUSE_HANDLE.GRAB;
// or
ControlsApp.MouseHandle = Input.MOUSE_HANDLE.SOFT;

UnigineScript Code

Source code (UnigineScript)
engine.controls.setMouseHandle(MOUSE_HANDLE_GRAB);
// or
engine.controls.setMouseHandle(MOUSE_HANDLE_SOFT);

Please check out the updated usage example on Customizing Mouse Cursor and Behavior

Property Switch Parameter Changes#

Switch parameter of the property is now one step closer to enums in C#/C++. Now it is a set of values, each of these values may have an optional arbitrary name (Item) associated with it. Items can have positive or negative values, several items can have the same value.

Suppose we have a property switch parameter declared as follows:

Source code (XML)
<parameter items="red=-1,green,blue=5,yellow"/>
Notice
Spaces in the items attribute declaration are taken into account. Thus, items="red=-1, green" shall produce 2 items: "red" and " green".

After loading we'll have switch items with the following values: red = -1, green = 0, blue = 5, yellow = 6.

Source code (C++)
PropertyParameter::setValue(5); // "blue" is selected in the corresponding combobox in the UnigineEditor
PropertyParameter::setSwitchItem(3); // "yellow" is selected (3rd item, starting from 0)

// If "green" item is selected in the UnigineEditor:
PropertyParameter::getValueInt(); // returns 0, as "green" corresponds to the value of 0.
PropertyParameter::getSwitchItem() // returns 1, as "green" is the 1st element in the combobox (starting from 0).

Landscape Modification#

As GPU-based modification ensures significantly higher performance and stability, its CPU-based counterpart is considered redundant. So the corresponding methods were marked as deprecated and will be removed in the next release. As for other changes, operation ID's are now managed differently:

UNIGINE 2.10
Source code (C++)
int id = Landscape::asyncTextureDraw(file_guid, coord, resolution, flags_file_data);
// user's code (bounding to ID)
UNIGINE 2.11
Source code (C++)
int id = Landscape::generateOperationID();
// user's code (bounding to ID)
Landscape::asyncTextureDraw(id, file_guid, coord, resolution, flags_file_data);

Landscape Class Changes#

UNIGINE 2.10 UNIGINE 2.11
asyncTextureDraw() Return value changed.
asyncTextureDraw() Return value changed.
asyncTextureDraw() Return value changed.
asyncApplyDiff() Return value changed.
asyncSaveFile() Return value changed.
asyncSaveFile() Return value changed.
asyncImageDraw() Deprecated.

New Functions:

For more information on the current implementation of terrain modification please refer to the Landscape Class article.

Application Window Title Customization#

It is now possible to set up your custom title for the application window on the Engine's initialization (it will be applied instantly, without any delay):

Source code (C++)
Unigine::EnginePtr engine(UNIGINE_VERSION, "Custom Window Title", argc, argv);

App::setTitle will work as before.

The following additional methods are now available for the Engine class:

Scoped Profiler#

Added a scoped profiler for your application logic. Now you can mark fragments of code to be monitored by simply adding the following macros inside the scope you'd like to inspect:

Source code (C++)
void myFunction()
{
	UNIGINE_PROFILER_FUNCTION;
	// your function's code
}
	
// ...
	
	for (int i = 0; i < num_points; i++)
	{
		UNIGINE_PROFILER_SCOPED("my_loop");
		// your loop iteration code
	}
	
// ...

To enable GPU profiling simply add "_GPU" to the corresponding macro: UNIGINE_PROFILER_FUNCTION_GPU and UNIGINE_PROFILER_SCOPED_GPU(NAME)

App Class#

BoundFrustum Class#

UNIGINE 2.10 UNIGINE 2.11
addPortal() Removed.
removePortal() Removed.
getNumPortals() Removed.
getPortalPoints() Removed.
insidePortals() Removed.
insidePortalsValid() Removed.

ControlsApp Class#

BodyFracture Class#

UNIGINE 2.10 UNIGINE 2.11
setIntersectionMask() Renamed as setPhysicsIntersectionMask().
getIntersectionMask() Renamed as getPhysicsIntersectionMask().

Game Class#

UNIGINE 2.10 UNIGINE 2.11
setFTime() Removed. Use the setMaxFPS() method of the Render class instead.
getFTime() Removed. Use the getIFps() method instead.

New Functions#

Image Class#

UNIGINE 2.10 UNIGINE 2.11
copy(image) Removed. Use the assignFrom() method instead.

New Functions#

Input Class#

UNIGINE 2.10 UNIGINE 2.11
KEY_KEY_SPACE KEY_SPACE
KEY_QUOTE = KEY_COMMA KEY_QUOTE = KEY_APOSTROPHE
setMouseShow() Removed.
getMouseShow() Removed.
setMouseGrab() Removed.
getMouseGrab() Removed.

New Functions#

JointWheel Class#

UNIGINE 2.10 UNIGINE 2.11
setIntersectionMask() Renamed as setPhysicsIntersectionMask().
IntersectionMask() Renamed as getPhysicsIntersectionMask().

Material Class#

Node Class#

UNIGINE 2.10 UNIGINE 2.11
setCollider() Removed. Colliders are now detected automatically by the Engine.
isCollider() Removed. Colliders are now detected automatically by the Engine.
setLatest() Removed. This parameter is now enabled automatically by the Engine for the following types of nodes: NodeExtern, ObjectExtern, WorldExtern, and WorldExpression.
isLatest() Removed. This parameter is now enabled automatically by the Engine for the following types of nodes: NodeExtern, ObjectExtern, WorldExtern, and WorldExpression.
setPortalCullingEnabled() Removed. Due to removal of sectors and portals.
isPortalCullingEnabled() Removed. Due to removal of sectors and portals.
getWorldSector() Removed. Due to removal of sectors and portals.

New Functions#

Object Class#

ObjectMeshDynamic Class#

ObjectMeshSkinned Class#

Legacy mode (skinned_legacy_mode) enabling to use old-style references (by name) to skinned mesh animations has been removed, so now each animation is stored in a separate *.anim file and referred to by path.

UNIGINE 2.10 UNIGINE 2.11
ObjectMeshSkinned() Set of arguments changed.
addAnimation() Set of arguments changed.

New Functions#

ObjectMeshStatic Class#

UNIGINE 2.10 UNIGINE 2.11
ObjectMeshStatic() Set of arguments changed.

ObjectParticles Class#

PlayerActor Class#

UNIGINE 2.10 UNIGINE 2.11
setIntersectionMask() Renamed as setPhysicsIntersectionMask().
getIntersectionMask() Renamed as getPhysicsIntersectionMask().

Property Class#

PropertyParameter Class#

Render Class#

UNIGINE 2.10 UNIGINE 2.11
setClutterDistance() Removed.
getClutterDistance() Removed.
getExposureInterpolation() Removed.
setLandscapeCacheGPUUpdateLimit() Removed.
getLandscapeCacheGPUUpdateLimit() Removed.
setLandscapeTerrainCullingAgressive() Renamed as setLandscapeTerrainCullingAggressive().
isLandscapeTerrainCullingAgressive() Renamed as isLandscapeTerrainCullingAggressive().

New Functions#

Shape Class#

UNIGINE 2.10 UNIGINE 2.11
setIntersectionMask() Renamed as setPhysicsIntersectionMask().
getIntersectionMask() Renamed as getPhysicsIntersectionMask().

New Functions#

StructuredBuffer Class#

Texture Class#

UGUID Class#

New Functions#

Visualizer Class#

UNIGINE 2.10 UNIGINE 2.11
renderBoxHandler() Removed.
renderSphereHandler() Removed.
renderTextureHandler() Removed.
renderWorldSectorObjectSurfaces() Removed.

New Functions#

Widget Class#

WidgetMenuBox Class#

WidgetSprite Class#

World Class#

UNIGINE 2.10 UNIGINE 2.11
addUpdateNode() Removed. Updating of Engine's logic for objects (simulation of particles, water, cloth, or ropes, and playback of skinned mesh animations) is now controlled via the set of Periodic Update parameters. To enable constant updating for an object regardless of its visibility you can set the Update Distance Limit and corresponding update rate values for it to infinity:
Source code (C++)
object->setUpdateDistanceLimit(Consts::INF);
object->setFPSInvisible(Consts::INF);
object->setFPSVisibleShadow(Consts::INF);
object->setFPSVisibleCamera(Consts::INF);
addUpdateNodes() Removed.
getNumUpdateNodes() Removed.
getUpdateNode() Removed.
setName() Removed.
getName() Removed. Use the getPath() method instead, that returns a path/to/the/world/file.world.

WorldBoundFrustum Class#

UNIGINE 2.10 UNIGINE 2.11
addPortal() Removed.
removePortal() Removed.
getNumPortals() Removed.
getPortalPoints() Removed.
insidePortals() Removed.
insidePortalsValid() Removed.

New Functions#

WorldExpression Class#

Due to changes in updating nodes instead of the set of removed parameters (offset, distance, size) you should use UpdateDistanceLimit to define the range in which the expression should be executed.

UNIGINE 2.10 UNIGINE 2.11
WorldExpression() Set of arguments changed.
setOffset() Removed. Replaced by setUpdateDistanceLimit().
getOffset() Removed. Replaced by getUpdateDistanceLimit().
setDistance() Removed. Replaced by setUpdateDistanceLimit().
getDistance() Removed. Replaced by getUpdateDistanceLimit().
setSize() Removed. Replaced by setUpdateDistanceLimit().
getSize() Removed. Replaced by getUpdateDistanceLimit().

New Functions#

WorldSwitcher Class#

Due to changes in updating nodes instead of the set of removed parameters (offset, point, size) you should simply use MaxDistance and MinDistance.

UNIGINE 2.10 UNIGINE 2.11
WorldSwitcher() Set of arguments changed.
setOffset() Removed.
getOffset() Removed.
setPoint() Removed.
isPoint() Removed.
setSize() Removed.
getSize() Removed.

WorldTransformBone Class#

Due to changes in updating nodes the WorldTransformBone is now updated by the ObjectMeshSkinned, so it doesn't have its own radius anymore.

UNIGINE 2.10 UNIGINE 2.11
setRadius() Removed.
getRadius() Removed.

WorldTransformPath Class#

UNIGINE 2.10 UNIGINE 2.11
setRadius() Removed. Replaced by setUpdateDistanceLimit().
getRadius() Removed. Replaced by getUpdateDistanceLimit().

New Functions#

Syncker Plugin Classes#

Syncker::Syncker Class#

UNIGINE 2.10 UNIGINE 2.11
setSetupMode() Removed. Use the following instead:
Source code (C++)
getProjections()->setConfiguratorEnabled()
useDefaultProjections() Removed. Use the following instead:
Source code (C++)
getProjections()->setEnabled(false);
isDefaultProjectionsUsed() Removed. Use the following instead:
Source code (C++)
( getProjections()->isEnabled() == false )
loadViewConfig() Removed. Use Projections::loadProjections()
getCAVEHead() Removed. Use getViewOffset() instead.
addCallback() Removed. Use Master::addCallback() or Slave::addCallback() instead for the Master and Slave respectively.
removeCallback() Removed. Use Master::removeCallback() or Slave::removeCallback() instead for the Master and Slave respectively.
clearCallbacks() Removed. Use Master::clearCallbacks() or Slave::clearCallbacks() instead for the Master and Slave respectively.

New Functions#

Syncker::Master Class#

UNIGINE 2.10 UNIGINE 2.11
setBroadcast() Removed.
setUdpSendSize() Removed.
getUdpSendSize() Removed.
getSlaveName() Removed.
setSyncCAVE() Removed. Use setSyncViewOffset() instead.
isSyncCAVE() Removed. Use isSyncViewOffset() instead.
createNode() Set of arguments changed.
isNodeCreated() Removed. Use isNodeCreatedBySyncker() instead.
deleteNode() Set of arguments changed.
setSyncPlayer() Set of arguments changed.
setSyncRender() Set of arguments changed.
isSyncPlayer() Set of arguments changed.
editorSet() Removed.
editorCall() Removed.
editorStream() Removed.
systemSet() Removed.
systemCall() Removed.
systemStream() Removed.
worldSet() Removed.
worldCall() Removed.
worldStream() Removed.
waitSlaves() Removed.
sendTCPUser() Removed. Use Syncker::sendMessage() instead.

New Functions#

Syncker::Slave Class#

UNIGINE 2.10 UNIGINE 2.11
setUdpRecvSize() Removed.
getUdpRecvSize() Removed.
setSkipWorldMessages() Removed. Use setSkipFlags() instead.
isWorldMessagesSkipped() Removed. Use getSkipFlags() instead.
setSkipUserMessages() Removed. Use setSkipFlags() instead.
isUserMessagesSkipped() Removed. Use getSkipFlags() instead.
isPacketsReceived() Removed.
isPacketsLost() Removed.
hasCAVE() Removed.
hasEnd() Removed.
hasFrame() Removed.
hasPlayer() Removed.
hasRender() Removed.
sendTCPUser() Removed. Use Syncker::sendMessage() instead.

New Functions#

Syncker::Manager Class#

UNIGINE 2.10 UNIGINE 2.11
getArgMasterBroadcast() Removed.
getArgSlaveName() Removed.
getArgTcpPort() Removed.
getArgTcpPingPort() Removed.
getArgMasterBroadcast() Removed.
getArgMasterBroadcast() Removed.
getArgMasterBroadcast() Removed.
getArgMasterBroadcast() Removed.
initMaster() Set of arguments changed.
initSlave() Set of arguments changed.

New Functions#

Last update: 2020-04-30