SceneManager
如何实际找到任何SceneNode
,无论它在图表中的位置如何:
SceneManager::createSceneNode(...)
方法明确声明创建的节点不是图表的一部分?¹,和 SceneNode
s可以在没有SceneManager
知识的情况下独立创建自己的孩子吗?²¹ SM不会自动将其创建的场景节点转换为其他节点的子节点(例如root);您必须在该
的节点上手动调用addChild
²客户可以简单地写sceneManager->getRootSceneNode()->createChildSceneNode("Child");
,而SM不会知道新孩子的存在
我正在浏览OGRE3D中的源代码,并在SceneManager
类(>>><<强调添加)中遇到了以下文档:
/** Retrieves a named SceneNode from the scene graph.
@remarks
If you chose to name a SceneNode as you created it, or if you
happened to make a note of the generated name, you can look it
up >>wherever it is in the scene graph<< using this method.
@note Throws an exception if the named instance does not exist
*/
virtual SceneNode* getSceneNode(const String& name) const;
当您查看实施时,您会看到:
SceneNode* SceneManager::getSceneNode(const String& name) const
{
SceneNodeList::const_iterator i = mSceneNodes.find(name);
if (i == mSceneNodes.end())
{
OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, "SceneNode '" + name + "' not found.",
"SceneManager::getSceneNode");
}
return i->second;
}
到目前为止,这么好。我们可以看到,SM会在名为SceneNode
的{{1}}个SceneNodeList
中搜索您请求的mSceneNodes
。我想弄清楚的部分是文档声称它可以找到一个节点“它在场景图中的任何地方”。新SceneNode
仅在使用mSceneNodes
时添加到SceneManager::createSceneNode(...)
列表中。 SM的createSceneNode
方法的文档说(&gt;&gt;&lt;&lt;强调添加):
/** Creates an instance of a SceneNode with a given name.
@remarks
Note that this >>does not add the SceneNode to the scene hierarchy<<.
This method is for convenience, since it allows an instance to
be created for which the SceneManager is responsible for
allocating and releasing memory, which is convenient in complex
scenes.
@par
To include the returned SceneNode in the scene, use the addChild
method of the SceneNode which is to be it's parent.
@par
Note that this method takes a name parameter, which makes the node easier to
retrieve directly again later.
*/
virtual SceneNode* createSceneNode(const String& name);
同时,如果您查看SceneNode
类,它有自己的createChild(const String& name, ...)
方法,显然不将自己的子项添加到SceneManager
中1}}的列表,如下所示:
SceneNode* SceneNode::createChildSceneNode(const Vector3& inTranslate,
const Quaternion& inRotate)
{
return static_cast<SceneNode*>(this->createChild(inTranslate, inRotate));
}
//-----------------------------------------------------------------------
SceneNode* SceneNode::createChildSceneNode(const String& name, const Vector3& inTranslate,
const Quaternion& inRotate)
{
return static_cast<SceneNode*>(this->createChild(name, inTranslate, inRotate));
}
这意味着,如果客户端程序显示node.createChildSceneNode(...);
,则SceneManager
将不意识到新子节点AFAIK的存在,所以它永远不会能够找到它。
我已经研究了一段时间的源代码,但我没有找到这个问题的答案。我查看了BspSceneManager
和BspSceneNode
只是为了看看我是否能发现其他内容,但却显得空洞。
为了完整性/参考,master分支中当前可用的最新提交是:
commit 3b13abbdcce146b2813a6cc3bedf16d1d6084340
Author: mkultra333 <unknown>
Date: Sun May 8 19:31:39 2016 +0800
答案 0 :(得分:4)
难怪这部分让你感到困惑,因为它是十多年前OOP的一部分。有些人喜欢它,有些人讨厌它。
但是,如果您知道要查找的内容,则答案非常简单:
Node::createChild
的代码如下:
Node* newNode = createChildImpl( sceneType );
//...
return newNode;
它实际上将创建委托给createChildImpl
(“实施者”)。此函数是纯虚函数,因此SceneNode
必须重载。
当我们转到SceneNode::createChildImpl
时,我们得到:
Node* SceneNode::createChildImpl(const String& name)
{
return mCreator->_createSceneNode( name );
}
mCreator
是SceneManager
指针变量。您就去了:SceneManager
通过SceneNode
创建createChildSceneNode
时会收到通知。
但请注意,实施(例如BspSceneNode
中的BspSceneManager
)可能会超载createChildImpl
而不会通知SceneManager
;或者他们可能。
在SceneManager::_createSceneNode
内放置断点并检查callstack会为您节省很多麻烦。