This page has been translated automatically.
Видеоуроки
Interface
Essentials
Advanced
Подсказки и советы
Программирование на C#
Рендеринг
Принципы работы
Свойства (properties)
Компонентная Система
Рендер
Физика
Редактор UnigineEditor
Обзор интерфейса
Работа с ассетами
Настройки и предпочтения
Работа с проектами
Настройка параметров узла
Setting Up Materials
Setting Up Properties
Освещение
Landscape Tool
Sandworm
Использование инструментов редактора для конкретных задач
Extending Editor Functionality
Встроенные объекты
Nodes
Objects
Effects
Decals
Light Sources
Geodetics
World Objects
Sound Objects
Pathfinding Objects
Players
Программирование
Настройка среды разработки
Примеры использования
UnigineScript
C++
C#
Унифицированный язык шейдеров UUSL
File Formats
Rebuilding the Engine Tools
GUI
Двойная точность координат
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
Работа с контентом
Оптимизация контента
Материалы
Art Samples
Tutorials
Внимание! Эта версия документация УСТАРЕЛА, поскольку относится к более ранней версии SDK! Пожалуйста, переключитесь на самую актуальную документацию для последней версии SDK.
Внимание! Эта версия документации описывает устаревшую версию SDK, которая больше не поддерживается! Пожалуйста, обновитесь до последней версии SDK.

Execution Sequence

This article focuses on details of the UNIGINE execution sequence. Here you will find what is happening under the hood of UNIGINE engine. For a high-level overview of UNIGINE workflow, see the Engine Architecture article.

The UNIGINE engine internal code and the logic of your application that can be extended using plugins in C++ or C#, are executed in the pre-defined order:

  1. Initialization. During this stage, the required resources are prepared and initialized. As soon as these resources are ready for use, the engine enters the main loop.
  2. Main loop. When UNIGINE enters the main loop, all its actions can be divided into three stages, which are performed one by one in a cycle:
    1. Update stage containing all logic of your application that is performed every frame
    2. Rendering stage containing all rendering-related operations, physics simulation calculations, and pathfinding
    3. Swap stage containing all synchronization operations performed in order to switch between the buffers

    This cycle is repeated every frame while the application is running.

  3. Shutdown. When UNIGINE stops execution of the application, it performs operations related to the application shutdown and resource cleanup.


The following diagram (clickable) represents the main stages of the UNIGINE execution sequence.

UNIGINE execution sequence

Waiting GPU#

At most times, UNIGINE finishes all its stages in the main loop faster then the GPU can actually render the frame. That is why double buffering is used: it enables to render frames faster by swapping GPU buffers (the back and front ones) into which rendering is performed.

When all scripts have been updated and all calculations on the CPU have been completed, the GPU is still rendering the frame calculated on the CPU. So, the CPU has to wait until the GPU finishes rendering the frame and the rendering buffers are swapped. The period of such waiting time is represented by the Waiting GPU counter in the performance profiler.

If the Waiting GPU time is too high, it may signal that a GPU bottleneck exists, and art content needs to be optimized. But if by that the frame rate is consistently high, it means you still have the CPU resources available to crunch more numbers.

How much time has passed from the moment when all scripts have been updated and all calculations on the CPU have been completed, to the moment when the GPU has finished rendering the frame, also depends on whether the vertical synchronization (VSync) is enabled (can be done via the System menu). If VSync is enabled, the CPU waits until the GPU finishes rendering and the vertical synchronization is performed. In this case, the Waiting GPU counter value will be higher.

The four schemes below show different scenarios of CPU and GPU performance with VSync disabled and enabled.

The first two schemes show calculation and rendering of the frame when VSync is disabled (in both cases the monitor vertical retrace is ignored):

  • Scheme 1. The CPU calculates the frame faster than the GPU can render it. So, the CPU waits for the GPU (the Waiting GPU time is high).
  • Scheme 2. The CPU calculations are performed slower than the GPU renders the frame. So, the GPU has to wait while the CPU finishes its calculations. In this case, the Waiting GPU time is small.

VSync disabled

Schemes 3 and 4 show calculation and rendering of the frame when VSync is enabled (the monitor vertical retrace is taken into account):

  • Scheme 3. The CPU calculates the frame faster than the GPU can render it, and the CPU waits for the GPU. However, in this case, both the CPU and the GPU also wait for VSync.
  • Scheme 4. The CPU calculates the frame slower than the GPU renders it. In this case, the GPU waits not only the CPU finishes its calculations, but also VSync.

VSync enabled

Physics and Pathfinding Threads#

The engine uses all available threads to update visible nodes simultaneously, and multi-threaded physics (in the asynchronous physics update mode) and pathfinding start updating at the end of the update stage in order to be performed in parallel with the rendering stage.

The following scheme illustrates threads in the process of calculation and rendering of a frame with VSync enabled:

Threads

Physics and pathfinding threads

Correlation between Rendering and Physics Framerates#

The rendering framerate usually varies, while, as we have already mentioned before, physics simulation framerate is fixed. This means that your update() and updatePhysics() functions from the world logic are called with different frequency.

The number of times physical calculations are be performed given the rendering framerate and the physics framerate

The number of times physical calculations are performed given the rendering framerate and the physics framerate

The picture above describes what happens, when the physics framerate is fixed to 60 FPS, and the rendering framerate varies. In general, there are three possible cases:

  • The rendering framerate is much higher. In this case, physical calculations are done once for two or more frames. This does not raise any problems, as positions of moving objects are interpolated between the calculations.
  • The rendering framerate is the same or almost the same. This situation is also OK, the calculations are performed once per frame; the physics keeps pace with the graphics and vice versa.
  • The rendering framerate is much lower. This is where problems begin. First, as you see from the picture, the physics should be calculated twice or even more times per frame, and that does not speed up the overall rendering process. Second, you cannot set the physics framerate too low, as in this case the calculations will lose too much precision.
    Notice
    There is no point in setting the number of iterations too high. Unigine checks whether the next iteration can be performed within physics budget limit, and if not, it is delayed and moved to the next rendering frame.

Synchronizing Engine FPS with Physics One#

As it was mentioned, in case the Engine framerate is higher than the physics one, the results of physics calculations are interpolated between the frames. But you can enable physics to be calculated each rendered frame by synchronizing the Engine framerate to the physics one (setting the SyncEngineUpdateWithPhysics flag via code). In this mode, there is no twitching of physical objects if they have non-linear velocities. This flag has no effect if the Engine FPS is lower than the physics one.

Last update: 09.04.2021
Build: ()