{"id":570,"date":"2011-03-29T13:12:59","date_gmt":"2011-03-29T09:42:59","guid":{"rendered":"http:\/\/www.blog.seganx.com\/?p=570"},"modified":"2024-03-18T17:03:00","modified_gmt":"2024-03-18T17:03:00","slug":"scene-manager","status":"publish","type":"post","link":"https:\/\/sajad-b.com\/?p=570","title":{"rendered":"Scene Manager"},"content":{"rendered":"<p>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.<\/p>\n<p>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.<\/p>\n<p>However, rendering a large number of small objects, each made from a few polygons imposes a big strain on today&#8217;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).<\/p>\n<p>Today most scene managers don&#8217;t split scenes to separate polygons and the algorithms try to manage batches ( meshes, instances, &#8230; ) 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.<\/p>\n<p>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.<br \/>\nsome things like this :<\/p>\n<div class=\"codecolorer-container cpp railscasts\" style=\"overflow:auto;white-space:nowrap;width:100%;\"><div class=\"cpp codecolorer\">&nbsp; &nbsp; <span class=\"co1\">\/\/ &nbsp;interface of scene manager<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw2\">class<\/span> SEGAN_API SceneManager<br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw2\">public<\/span><span class=\"sy4\">:<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"coMULTI\">\/*!<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; fill the node list by founded nodes in the frustum.<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; NOTE: this function called by many parts of core\/rendering\/AI\/etc and should be fast as possible.<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; *\/<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw2\">virtual<\/span> <span class=\"kw4\">void<\/span> GetNodesByFrustum<span class=\"br0\">&#40;<\/span><span class=\"kw4\">const<\/span> Frustum<span class=\"sy3\">&amp;<\/span> frustum, IN_OUT ArrayPNode<span class=\"sy3\">&amp;<\/span> nodeList<span class=\"br0\">&#41;<\/span> <span class=\"sy1\">=<\/span> <span class=\"nu0\">0<\/span><span class=\"sy4\">;<\/span><br \/>\n&nbsp; &nbsp; ...<br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><span class=\"sy4\">;<\/span><br \/>\n&nbsp; &nbsp; <br \/>\n&nbsp; &nbsp; <span class=\"co1\">\/\/ &nbsp;our new scene manager derived from SceneManager<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw2\">class<\/span> MySceneManager <span class=\"sy4\">:<\/span> <span class=\"kw2\">public<\/span> SceneManager<br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw2\">public<\/span><span class=\"sy4\">:<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw2\">virtual<\/span> <span class=\"kw4\">void<\/span> GetNodesByFrustum<span class=\"br0\">&#40;<\/span><span class=\"kw4\">const<\/span> Frustum<span class=\"sy3\">&amp;<\/span> frustum, IN_OUT ArrayPNode<span class=\"sy3\">&amp;<\/span> nodeList<span class=\"br0\">&#41;<\/span><span class=\"sy4\">;<\/span><br \/>\n&nbsp; &nbsp; ...<br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><span class=\"sy4\">;<\/span><br \/>\n&nbsp; &nbsp; <br \/>\n&nbsp; &nbsp; <span class=\"co1\">\/\/ &nbsp;implement our new scene manager to the engine<\/span><br \/>\n&nbsp; &nbsp; MySceneManager pSceneManager <span class=\"sy1\">=<\/span> SEGAN_NEW<span class=\"br0\">&#40;<\/span> MySceneManager <span class=\"br0\">&#41;<\/span><span class=\"sy4\">;<\/span><br \/>\n&nbsp; &nbsp; Scene<span class=\"sy4\">::<\/span><span class=\"me2\">Initialize<\/span><span class=\"br0\">&#40;<\/span> pSceneManager <span class=\"br0\">&#41;<\/span><span class=\"sy4\">;<\/span><br \/>\n&nbsp; &nbsp; ...<\/div><\/div>\n<p>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.<\/p>\n<div id=\"attachment_583\" style=\"width: 725px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/i0.wp.com\/sajad-b.com\/wp-content\/uploads\/2011\/03\/SBVH2.jpg?ssl=1\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-583\" class=\"wp-image-583 size-full\" title=\"Scene manager in debug mode\" src=\"https:\/\/i0.wp.com\/sajad-b.com\/wp-content\/uploads\/2011\/03\/SBVH2.jpg?resize=625%2C389&#038;ssl=1\" alt=\"\" width=\"625\" height=\"389\" srcset=\"https:\/\/i0.wp.com\/sajad-b.com\/wp-content\/uploads\/2011\/03\/SBVH2.jpg?w=715&amp;ssl=1 715w, https:\/\/i0.wp.com\/sajad-b.com\/wp-content\/uploads\/2011\/03\/SBVH2.jpg?resize=300%2C187&amp;ssl=1 300w\" sizes=\"auto, (max-width: 625px) 100vw, 625px\" \/><\/a><p id=\"caption-attachment-583\" class=\"wp-caption-text\">Scene manager in debug mode<\/p><\/div>\n<p>however simple and fast collision detection for spheres ( in comparison with others ) makes the algorithm faster and more acceptable.<\/p>\n<div id=\"attachment_581\" style=\"width: 663px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/i0.wp.com\/sajad-b.com\/wp-content\/uploads\/2011\/03\/SBVH1.jpg?ssl=1\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-581\" class=\"wp-image-581 size-full\" title=\"spheres of sectors in debug mode\" src=\"https:\/\/i0.wp.com\/sajad-b.com\/wp-content\/uploads\/2011\/03\/SBVH1.jpg?resize=625%2C596&#038;ssl=1\" alt=\"\" width=\"625\" height=\"596\" srcset=\"https:\/\/i0.wp.com\/sajad-b.com\/wp-content\/uploads\/2011\/03\/SBVH1.jpg?w=653&amp;ssl=1 653w, https:\/\/i0.wp.com\/sajad-b.com\/wp-content\/uploads\/2011\/03\/SBVH1.jpg?resize=300%2C286&amp;ssl=1 300w\" sizes=\"auto, (max-width: 625px) 100vw, 625px\" \/><\/a><p id=\"caption-attachment-581\" class=\"wp-caption-text\">scene manager in debug mode draws the sphere of each sector<\/p><\/div>\n<p>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.<\/p>\n<p>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:<\/p>\n<div class=\"codecolorer-container cpp railscasts\" style=\"overflow:auto;white-space:nowrap;width:100%;\"><div class=\"cpp codecolorer\"><span class=\"kw2\">inline<\/span> <span class=\"kw4\">void<\/span> FindNearestSectorTo<span class=\"br0\">&#40;<\/span><span class=\"kw4\">const<\/span> PSector root, <span class=\"kw4\">const<\/span> Sphere<span class=\"sy3\">&amp;<\/span> sphere, IN_OUT PSector<span class=\"sy3\">&amp;<\/span> result<span class=\"br0\">&#41;<\/span><br \/>\n<span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw4\">static<\/span> <span class=\"kw4\">float<\/span> dis <span class=\"sy1\">=<\/span> <span class=\"nu17\">0.0f<\/span><span class=\"sy4\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">if<\/span> <span class=\"br0\">&#40;<\/span> <span class=\"sy3\">!<\/span>root <span class=\"br0\">&#41;<\/span> <span class=\"kw1\">return<\/span><span class=\"sy4\">;<\/span><br \/>\n<br \/>\n&nbsp; &nbsp; <span class=\"kw1\">if<\/span> <span class=\"br0\">&#40;<\/span> <span class=\"sy3\">!<\/span>sphere.<span class=\"me1\">Intersect<\/span><span class=\"br0\">&#40;<\/span>root<span class=\"sy2\">-<\/span><span class=\"sy1\">&gt;<\/span>m_sphere, dis<span class=\"br0\">&#41;<\/span> <span class=\"sy3\">||<\/span> root<span class=\"sy2\">-<\/span><span class=\"sy1\">&gt;<\/span>m_node<span class=\"br0\">&#41;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">if<\/span> <span class=\"br0\">&#40;<\/span> distance_Point_Point_sqr<span class=\"br0\">&#40;<\/span>root<span class=\"sy2\">-<\/span><span class=\"sy1\">&gt;<\/span>m_sphere.<span class=\"me1\">center<\/span>, sphere.<span class=\"me1\">center<\/span><span class=\"br0\">&#41;<\/span> <span class=\"sy1\">&lt;<\/span> distance_Point_Point_sqr<span class=\"br0\">&#40;<\/span>result<span class=\"sy2\">-<\/span><span class=\"sy1\">&gt;<\/span>m_sphere.<span class=\"me1\">center<\/span>, sphere.<span class=\"me1\">center<\/span><span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#41;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; result <span class=\"sy1\">=<\/span> root<span class=\"sy4\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">return<\/span><span class=\"sy4\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><br \/>\n<br \/>\n&nbsp; &nbsp; <span class=\"kw1\">if<\/span> <span class=\"br0\">&#40;<\/span>root<span class=\"sy2\">-<\/span><span class=\"sy1\">&gt;<\/span>m_left <span class=\"sy3\">&amp;&amp;<\/span> root<span class=\"sy2\">-<\/span><span class=\"sy1\">&gt;<\/span>m_left<span class=\"sy2\">-<\/span><span class=\"sy1\">&gt;<\/span>m_node <span class=\"sy3\">&amp;&amp;<\/span> root<span class=\"sy2\">-<\/span><span class=\"sy1\">&gt;<\/span>m_right<span class=\"sy2\">-<\/span><span class=\"sy1\">&gt;<\/span>m_node<span class=\"br0\">&#41;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw4\">float<\/span> dis_left <span class=\"sy1\">=<\/span> distance_Sector_Point_sqr<span class=\"br0\">&#40;<\/span> root<span class=\"sy2\">-<\/span><span class=\"sy1\">&gt;<\/span>m_left, sphere.<span class=\"me1\">center<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy4\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw4\">float<\/span> dis_right <span class=\"sy1\">=<\/span> distance_Sector_Point_sqr<span class=\"br0\">&#40;<\/span> root<span class=\"sy2\">-<\/span><span class=\"sy1\">&gt;<\/span>m_right, sphere.<span class=\"me1\">center<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy4\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw4\">float<\/span> dis_left_right <span class=\"sy1\">=<\/span> distance_Sector_Sector_sqr<span class=\"br0\">&#40;<\/span>root<span class=\"sy2\">-<\/span><span class=\"sy1\">&gt;<\/span>m_left, root<span class=\"sy2\">-<\/span><span class=\"sy1\">&gt;<\/span>m_right<span class=\"br0\">&#41;<\/span><span class=\"sy4\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; PSector res <span class=\"sy1\">=<\/span> <span class=\"kw2\">NULL<\/span><span class=\"sy4\">;<\/span><br \/>\n<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">if<\/span> <span class=\"br0\">&#40;<\/span>root<span class=\"sy2\">-<\/span><span class=\"sy1\">&gt;<\/span>m_left <span class=\"sy3\">&amp;&amp;<\/span> dis_left<span class=\"sy1\">&lt;<\/span>dis_left_right <span class=\"sy3\">&amp;&amp;<\/span> dis_left<span class=\"sy1\">&lt;<\/span>dis_right<span class=\"br0\">&#41;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; res <span class=\"sy1\">=<\/span> root<span class=\"sy2\">-<\/span><span class=\"sy1\">&gt;<\/span>m_left<span class=\"sy4\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">else<\/span> <span class=\"kw1\">if<\/span> <span class=\"br0\">&#40;<\/span>root<span class=\"sy2\">-<\/span><span class=\"sy1\">&gt;<\/span>m_right <span class=\"sy3\">&amp;&amp;<\/span> dis_right<span class=\"sy1\">&lt;<\/span>dis_left_right <span class=\"sy3\">&amp;&amp;<\/span> dis_right<span class=\"sy1\">&lt;<\/span>dis_left<span class=\"br0\">&#41;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; res <span class=\"sy1\">=<\/span> root<span class=\"sy2\">-<\/span><span class=\"sy1\">&gt;<\/span>m_right<span class=\"sy4\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">else<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; res <span class=\"sy1\">=<\/span> root<span class=\"sy4\">;<\/span><br \/>\n<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">if<\/span> <span class=\"br0\">&#40;<\/span> distance_Point_Point_sqr<span class=\"br0\">&#40;<\/span>res<span class=\"sy2\">-<\/span><span class=\"sy1\">&gt;<\/span>m_sphere.<span class=\"me1\">center<\/span>, sphere.<span class=\"me1\">center<\/span><span class=\"br0\">&#41;<\/span> <span class=\"sy1\">&lt;<\/span> distance_Point_Point_sqr<span class=\"br0\">&#40;<\/span>result<span class=\"sy2\">-<\/span><span class=\"sy1\">&gt;<\/span>m_sphere.<span class=\"me1\">center<\/span>, sphere.<span class=\"me1\">center<\/span><span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#41;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; result <span class=\"sy1\">=<\/span> res<span class=\"sy4\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">else<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; FindNearestSectorTo<span class=\"br0\">&#40;<\/span> root<span class=\"sy2\">-<\/span><span class=\"sy1\">&gt;<\/span>m_left, sphere, result <span class=\"br0\">&#41;<\/span><span class=\"sy4\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; FindNearestSectorTo<span class=\"br0\">&#40;<\/span> root<span class=\"sy2\">-<\/span><span class=\"sy1\">&gt;<\/span>m_right, sphere, result <span class=\"br0\">&#41;<\/span><span class=\"sy4\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><br \/>\n<span class=\"br0\">&#125;<\/span><\/div><\/div>\n<p>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.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>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 [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"nf_dc_page":"","_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[7],"tags":[15,38,39,49],"class_list":["post-570","post","type-post","status-publish","format-standard","hentry","category-engine","tag-bvh","tag-sbvh","tag-scene-manager","tag-spherical-bounding-volume-hierarchy"],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/sajad-b.com\/index.php?rest_route=\/wp\/v2\/posts\/570","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/sajad-b.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/sajad-b.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/sajad-b.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/sajad-b.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=570"}],"version-history":[{"count":4,"href":"https:\/\/sajad-b.com\/index.php?rest_route=\/wp\/v2\/posts\/570\/revisions"}],"predecessor-version":[{"id":868,"href":"https:\/\/sajad-b.com\/index.php?rest_route=\/wp\/v2\/posts\/570\/revisions\/868"}],"wp:attachment":[{"href":"https:\/\/sajad-b.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=570"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/sajad-b.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=570"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/sajad-b.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=570"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}