Hope you still with me... =)
Today I'll try to figure out one of the possible ways of passing data from Game Engine to 3D engine for drawing.
=== Separated Threads architecture ===
First of all I' have to note that each time when Scene Manager is called to draw the scene it will draw only one single frame. So, it means that until this routine isn't called the 3D drawing subsystem awaits. May be blocked on some semaphore, whatever. Before calling scene rendering method we should prepare the data for drawing from the Game Core layer. There are some questions here:
- Q: Should we split this routine into two threads one for updating game core data, game objects and another one strictly for processing the 3D scene and drawing elements or this work may be done within one thread?
- A: Yes, we separate the game updating process (objects state, game state, user events etc) and scene rendering;
- Q: How we should pass data from Game Core layer to 3D Engine?
- A: We need to pass strictly limited set of data from Game Core layer to Scene Manager layer via Scene Queue -- fill a small structure with necessary set of data and place it into Scene Queue;
- Q: which data we should pass each time when we need to update scene?
- A: strongly limited set of data related to each game entity - entity position and rotation (quaternions), mesh id, texture id, skeleton id and animation state id (in case we have skeletal animation);
- Q: how should we store all of 3D related data in the meantime?
- A: we don't need to store any graphical data at the Game Core layer. All graphical related data is stored at the 3D engine layer. At the Game Core layer we should store only links (some kind of IDs) to resource(s) used by each particular game entity;
- Q: does the Scene Manager flush its queues after rendering scene?
- A: the Scene Manager should flush Active Scene Queue from memory after scene gets rendered and switch Active and Inactive Scene Queues between each other. Then Scene manager will proceed rendering of next frame based on data from Active Scene Queue;
Let's see to the design architecture for two threads implementation (game state update and render) - refer to the picture below:
Briefly description of the design components:
- Game Core (GC) -- update game world and place visible entities (according to current position and rotation data) into Inactive Scene Queue and notify Scene Manager about it;
- Scene Manager (SM) -- picks up the new elements from Active Scene Queue and renders them;
- Scene Queue (SQ) -- the abstract object which is implemented to let threads be running simultaneously; Scene Queue contains two FIFO lists - Active Scene Queue and Inactive Scene Queue; Active Scene Queue - contain elements which currently renders by drawing subsystem; Inactive Scene Queue is used by Game Core update thread to store (describe) new frame data and pass it into Scene Manager; Scene Queue contains mutex and counting semaphore also to manage access to lists;
1. Scene Mutex is used for:
- preventing simultaneous access from Game Core side to Active Scene Queue which is currently being rendered;
- preventing switching of scene queues by Scene Manager until Game Core has not completed updating of Inactive Scene Queue;
- blocking of rendering thread in case there are no any elements for rendering in the Active Scene Queue;
- waking of rendering thread in case new elements have been added into Active Scene Queue by Game Core;
- blocking of the Game Core update thread in case previous frame hasn't been rendered yet (means that the Active and Inactive queues have not been switched yet since last update operation);
The activity diagrams of Game Core Update and Render threads are provided below:
Some comments about activity diagrams:
- Scene Manager flushes the Active Scene Queue each time when frame has been rendered;
=== Single Thread Architecture ===
This design approach is actually the same as previous just without mutex, counting semaphore, Scene Queues, and now we have only one single thread to process game world and 3D scene. The all operations called to add node into the scene for rendering applies directly on Z-ordered Render Queue. So, each time when Game core adds new node into the scene, this node goes directly into Render Queue and takes place there according to node Z-axis value.
Activity diagram of "sceneUpdate" routine for single thread architecture is provided below:
Note: before this routine will start we need to have some list of all in-game objects to process them. Actually we will process this list and collect from it visible objects.
From the data transfer perspective -- there is no significant changes, we still need to pass limited set of data (mesh id, texture id, skeleton id, animation state id/number, position and rotation). Also we don't need to store graphical data at the Game core layer, just links to them -- all 3D stuff is managed by 3D engine core (Scene Manager, Resource Manager etc).
Unfortunately, in case we have single thread for processing all in-game stuff, someday (e.g. in case of game world with large number of entities) we could face an significant time delay issue which causes FPS degradation.
WBR,
Vadim
Комментариев нет:
Отправить комментарий