Tag Archives: Scene Manager

Scene Manager

I think that the Scene manager is the most important part of an engine. rendering pipelines, some lighting techniques and shadow map generators, culling and collision systems, AI systems, triggers, and any other things in the game that need to cooperate with objects in the scene, have to use the features of Scene managers.

For managing objects in the scene, there are many algorithms and techniques of scene management. most of them use tree structures to hold them. the programmers had to use software rasterizer to draw polygons in 3D space before new graphics accelerators appeared. because of that reducing the number of polygons and ordering them from back to front were some of the important issues. in this regard objects in the scene managers were usually polygons and the algorithms generally try to split the scene into separated polygons. nowadays hardware rasterizers have different behaviors.

However, rendering a large number of small objects, each made from a few polygons imposes a big strain on today’s GPUs and rendering libraries. Graphics APIs such as Direct3D and OpenGL are not designed to efficiently render a small number of polygons thousands of times per frame (Wloka 2003).

Today most scene managers don’t split scenes to separate polygons and the algorithms try to manage batches ( meshes, instances, … ) by their location instead of polygons. in addition, there are hybrid scene systems that use different algorithms to manage the scene. for instance, using Octree to partition the space and BSP to separate meshes into polygons and vice versa. anyway, choosing and implementing an appropriate scene management algorithm depends on the genre of the game.

To implement various kinds of scene graphs in SeganX engine, there is a ::SceneManager interface that contains necessary virtual abstract functions. we can easily implement our scene algorithm by writing down a new scene manager class which is derived from the interface, mentioned before. after that we can pass it to the ::Scene class to let the engine use our scene system instead of its default scene manager.
some things like this :

    //  interface of scene manager
    class SEGAN_API SceneManager
    {
    public:
        /*!
        fill the node list by founded nodes in the frustum.
        NOTE: this function called by many parts of core/rendering/AI/etc and should be fast as possible.
        */

        virtual void GetNodesByFrustum(const Frustum& frustum, IN_OUT ArrayPNode& nodeList) = 0;
    ...
    };
   
    //  our new scene manager derived from SceneManager
    class MySceneManager : public SceneManager
    {
    public:
        virtual void GetNodesByFrustum(const Frustum& frustum, IN_OUT ArrayPNode& nodeList);
    ...
    };
   
    //  implement our new scene manager to the engine
    MySceneManager pSceneManager = SEGAN_NEW( MySceneManager );
    Scene::Initialize( pSceneManager );
    ...

Currently, the engine has a default scene manager that uses Spherical Bounding Volume Hierarchy (SBVH) to manage the objects in the scene by their bounding sphere. supporting dynamic objects and removing the compile step to create the tree are some of my algorithm features. all nodes can insert/remove/update in run time mode, collecting and gathering nodes is guaranteed and the performance is acceptable. but using a sphere as a bounding volume has basically some drawbacks and no required accuracy. the main disadvantage of using SBVH is sinking spheres which cause it to traverse useless nodes in the tree.

Scene manager in debug mode

however simple and fast collision detection for spheres ( in comparison with others ) makes the algorithm faster and more acceptable.

scene manager in debug mode draws the sphere of each sector

The heart of the algorithm is the place where we choose a leaf of node ( Sector in my tree ) to traverse the tree to find an appropriate position for a new sector when we want to insert or update a node. in this situation, there are three sectors, two sectors from the node of the tree and our new one. at first, look, comparing two distances of sectors that compute by the center of their spheres between our new sector and the others is a good solution. but not actually! contributing more parameters like the third distance and radius of spheres to choose the next sector to traverse the tree can greatly affect the form of the tree.

Here is my function implementation to find the nearest node to the specified sphere of a new node. I used this function just to insert a new node to the scene manager:

inline void FindNearestSectorTo(const PSector root, const Sphere& sphere, IN_OUT PSector& result)
{
    static float dis = 0.0f;
    if ( !root ) return;

    if ( !sphere.Intersect(root->m_sphere, dis) || root->m_node)
    {
        if ( distance_Point_Point_sqr(root->m_sphere.center, sphere.center) < distance_Point_Point_sqr(result->m_sphere.center, sphere.center) )
            result = root;
        return;
    }

    if (root->m_left && root->m_left->m_node && root->m_right->m_node)
    {
        float dis_left = distance_Sector_Point_sqr( root->m_left, sphere.center);
        float dis_right = distance_Sector_Point_sqr( root->m_right, sphere.center);
        float dis_left_right = distance_Sector_Sector_sqr(root->m_left, root->m_right);
        PSector res = NULL;

        if (root->m_left && dis_left<dis_left_right && dis_left<dis_right)
            res = root->m_left;
        else if (root->m_right && dis_right<dis_left_right && dis_right<dis_left)
            res = root->m_right;
        else
            res = root;

        if ( distance_Point_Point_sqr(res->m_sphere.center, sphere.center) < distance_Point_Point_sqr(result->m_sphere.center, sphere.center) )
            result = res;
    }
    else
    {
        FindNearestSectorTo( root->m_left, sphere, result );
        FindNearestSectorTo( root->m_right, sphere, result );
    }
}

As you can see I used three parameters the distance between a point and left sector, point and right sector, and in addition distance between the left sector and right sector. certainly, there are many better algorithms for choosing the right sector and the code still needs more optimization.