Chapter 5 Scenario Management of Pro Ogre 3D Programming

Source: Internet
Author: User

Ogre Scenario Management

Each 3D engine uses scene graph to organize its rendered objects. Scene graph always performs
Optimization: allows you to find, sort, and remove polygon objects near a target object to achieve more efficient rendering. Occasionally, scene graph is also used for collision detection. Sometimes, a separate scene graph can be used by all subsystems in the program, including
Sound Effects and physics.
Ogre uses plug-in mechanism to implement Scenario Management. ScenceManager is only an interface and can have many specific implementations. Ogre allowed
Multiple Scene managers are used in the same scenario at the same time, which brings benefits when switching between different scenarios.

Responsibility of the scenario Manager
1. Create and place movable objects in a scenario, such as light and camera, and access them effectively in graphic traversal.
2. Load and assemble world geometry (it is usually very large and can be stretched around and cannot be moved)
3. Complete the scenario query. For example, you can answer the following question: what objects does a sphere contain when a sphere is drawn at a specific point in the world space?
4. Remove the invisible object and put the visible object into the rendering queue for rendering.
5. Organize from the current rendered perspective and select the illumination direction
6. Set and render all shadows in the scenario
7. Set and render other objects (such as backgrounds and sky boxes) in the scenario)
8. Deliver well-organized content to the rendering system for rendering

Scenario manager type

Analyze the source code to discuss the plug-in loading mechanism and how to use the scenario manager.
The previous chapter mentioned initializing ogre manually, including manually loading the scenario Manager:
Root-> loadPlugin ("Plugin_OctreeSceneManager ");
In fact, the so-called automatic method, Root: Root () will also indirectly call the loadPlugin () method, which is already in the previous notes
(Configuration file Plugins. cfg. Since the specific manager is provided in the form of a plug-in (dll file), let's take a look at how
Load dll. Enter the source code: The number indicates the execution order.
Void Root: loadPlugin (const String & pluginName)
{
// Load plugin library
DynLib * lib = DynLibManager: getSingleton (). load (pluginName); // (1)
// Store for later unload
MPluginLibs. push_back (lib); // (4)
// Call startup function
DLL_START_PLUGIN pFunc = (DLL_START_PLUGIN) lib-> getSymbol ("dllStartPlugin"); // (5)
// This must call installPlugin
PFunc (); // (6)

}
DynLib * DynLibManager: load (const String & filename) // (2)
{
DynLib * pLib = new DynLib (filename );
PLib-> load ();
MLibList [filename] = pLib;
Return pLib;
}
Void DynLib: load () // (3)
{
M_hInst = (DYNLIB_HANDLE) DYNLIB_LOAD (name. c_str ());
}
The macro definition in (3) is as follows:
# If OGRE_PLATFORM = OGRE_PLATFORM_WIN32
# Define DYNLIB_HANDLE hInstance
# Define DYNLIB_LOAD (a) LoadLibrary ()
At this point, the DLL is loaded into the memory. Step (4), mPluginLibs is an STL container that stores the dynamic library pointer.
STEP (5), go to the source code and you can see
Void * DynLib: getSymbol (const String & strName) const throw ()
{
Return (void *) DYNLIB_GETSYM (m_hInst, strName. c_str ());
}
Macro definition: define DYNLIB_GETSYM (a, B) GetProcAddress (a, B). Obviously, it obtains
Function pointer of dllStartPlugin: Look at macro definition: typedef void (* DLL_START_PLUGIN) (void );
It indicates that the DLL_START_PLUGIN parameter is null and the return value is null.
Every dll registered to ogre implements this Convention function. Plugin_OctreeSceneManager
We can find the corresponding definition: it is executed in step (6 ).

OctreePlugin * octreePlugin;
Extern "C" void _ OgreOctreePluginExport dllStartPlugin (void)
{
// Create new scene manager
OctreePlugin = new OctreePlugin (); // (6-1)

// Register
Root: getSingleton (). installPlugin (octreePlugin); // (6-2)

}
After the program is executed in Step 6-1, a OctreePlugin is created in new. Let's take a look at its definition:
Class OctreePlugin: public Plugin
{
Public:
OctreePlugin ();
Const String & getName () const;
Void install ();
Void initialise ();
Void shutdown ();
Void uninstall ();
Protected:
OctreeSceneManagerFactory * mOctreeSMFactory;
TerrainSceneManagerFactory * mTerrainSMFactory;
TerrainPageSourceListenerManager * mTerrainPSListenerManager;

};

We will notice that it contains two factory class pointers: OctreeSceneManagerFactory, TerrainSceneManagerFactory
They are used to produce specific ScenManager and will be discussed later. First read step (6-2:
Void Root: installPlugin (Plugin * plugin)
{
MPlugins. push_back (plugin); // (6-2-1)
Plugin-> install (); // (6-2-2)
// If rendersystem is already initialised, call rendersystem init too
If (mIsInitialised)
{
Plugin-> initialise (); // (6-2-3)
}
}
// (6-2-1) Move the plug-in to the container. Let's see what (6-2-2) has done:
Void OctreePlugin: install ()
{
// Create objects
MOctreeSMFactory = new OctreeSceneManagerFactory ();
MTerrainSMFactory = new TerrainSceneManagerFactory ();
MTerrainPSListenerManager = new TerrainPageSourceListenerManager ();

}
Well, I also said two factory class pointers just now. Now I have built two factories and they can be used to produce things later.
Continue to see (6-2-3 ):
Void OctreePlugin: initialise ()
{
// Register
Root: getSingleton (). addSceneManagerFactory (mOctreeSMFactory );
Root: getSingleton (). addSceneManagerFactory (mTerrainSMFactory );
}
Oh, register the two factories to the Root so that the Root can use them. Ah, this sentence is a bit problematic. Root is only used indirectly,
The direct employer is SceneManagerEnumerator * mSceneManagerEnum; it is included in the Root. So we can see that
Void Root: addSceneManagerFactory (SceneManagerFactory * fact) // (6-2-3-1)
{
MSceneManagerEnum-> addFactory (fact );
}

How can we use this factory to produce SceneManager?
Recall that in the manual initialization process of the previous chapter, we generally use the following statement to create SceneManager:
SceneManager * sceneMgr = root-> createSceneManager (ST_GENERIC); // ()
You can also use
SceneMgr = ogre-> createSceneManager ("OctreeSceneManager"); // (B)
Each factory class uses a string to indicate its type. The strings used by the two factories mentioned above are: "TerrainSceneManager" and "OctreeSceneManager"
(A) the statement will certainly call the factory class method to generate the actual SceneManager. Let's look at the source code for verification:
SceneManager * Root: createSceneManager (const String & typeName,
Const String & instanceName)
{
Return mSceneManagerEnum-> createSceneManager (typeName, instanceName );
}
Continue digging:
SceneManager * SceneManagerEnumerator: createSceneManager (
Const String & typeName, const String & instanceName)
{
SceneManager * inst = 0;
For (Factories: iterator I = mFactories. begin (); I! = MFactories. end (); ++ I)
{
If (* I)-> getMetaData (). typeName = typeName)
{
If (instanceName. empty ())
{
// Generate a name
StringUtil: StrStreamType s;
S <"SceneManagerInstance" <++ mInstanceCreateCount;
Inst = (* I)-> createInstance (s. str ());
}
Else
{
Inst = (* I)-> createInstance (instanceName );
}
Break;
}
}
}
The above code is simple: because the execution (6-2-3-1) has been registered by the actual factory instance. Then traverse each factory instance,
Find the type that matches. After finding the instance, if the name of the scenario manager instance is not specified, the Instance name is used. Then use this name.
Produce an instance. CreateInstance has nothing to do, thanks to new.
SceneManager * OctreeSceneManagerFactory: createInstance (
Const String & instanceName)
{
Return new OctreeSceneManager (instanceName );
}
That's it. The functions of OctreeSceneManager and TerrainSceneManager are provided by a DLL. Their relationship is: class _ OgreOctreePluginExport TerrainSceneManager: public OctreeSceneManager. According to the general class relationship logic,
We know that the general function of a derived class is more powerful than that of a parent class. The parent class is used in general scenarios, and the Child class is applicable to specific scenarios. This logic is correct here. I used to write Reading Notes, run my questions, and stop.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.