OGRE3D SceneManager 如何真正找到*任何* SceneNode?
How can the OGRE3D SceneManager really find *any* SceneNode?
TL;DR;
SceneManager
如何才能真正找到任何 SceneNode
,而不管它恰好在图表中的什么位置 当:
SceneManager::createSceneNode(...)
方法明确声明创建的节点 不是 图形的一部分?¹, 和
SceneNode
可以在 SceneManager
不知情的情况下独立创建自己的 children?²
¹ SM不会自动将自己创建的场景节点变成children的其他节点(例如root);你必须在节点上手动调用 addChild
² 客户端只要写sceneManager->getRootSceneNode()->createChildSceneNode("Child");
,SM就不知道新child的存在
背景
我在查看 OGRE3D 中的源代码时发现了以下关于 SceneManager
class 的文档(>> << 添加了重点):
/** 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 在它自己的名为 mSceneNodes
的 SceneNodeList
中搜索您请求的 SceneNode
。我想弄清楚的部分是文档声称它可以找到一个节点 "wherever it is in the scene graph"。新 SceneNode
仅在使用 SceneManager::createSceneNode(...)
时添加到 mSceneNodes
列表中。 SM 的 createSceneNode
方法的文档说 (>> << 添加了重点):
/** 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
class,它有自己的createChild(const String& name, ...)
方法,显然不是 将自己的children加入到SceneManager
的列表中,如下图:
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
将 不会 知道新 child 的存在节点,据我所知,所以它永远找不到它。
我已经研究了一段时间的源代码,但我没有找到这个问题的答案。我查看了 BspSceneManager
和 BspSceneNode
只是想看看我是否能发现其他东西,但结果是空的。
为了 completeness/reference,master 分支中当前可用的最新提交是:
commit 3b13abbdcce146b2813a6cc3bedf16d1d6084340
Author: mkultra333 <unknown>
Date: Sun May 8 19:31:39 2016 +0800
难怪这部分会让您感到困惑,因为它是十多年前的过度 OOP 的一部分。有人喜欢有人讨厌。
然而,如果您知道要查找的内容,答案就非常简单:
Node::createChild
的代码如下:
Node* newNode = createChildImpl( sceneType );
//...
return newNode;
它实际上将创建委托给createChildImpl
("implementer")。此函数是纯虚函数,因此SceneNode
必须重载。
当我们转到 SceneNode::createChildImpl
时,我们得到:
Node* SceneNode::createChildImpl(const String& name)
{
return mCreator->_createSceneNode( name );
}
mCreator
是一个 SceneManager
指针变量。所以你去了:当通过 createChildSceneNode
.
创建 SceneNode
时,SceneManager
确实会收到通知
但是请注意,一个实现(例如 BspSceneManager
中的 BspSceneNode
)可能会使 createChildImpl
过载并且不会通知 SceneManager
;或者他们可能。
在 SceneManager::_createSceneNode
中放置一个断点并检查调用堆栈会让您省去很多麻烦。
TL;DR;
SceneManager
如何才能真正找到任何 SceneNode
,而不管它恰好在图表中的什么位置 当:
SceneManager::createSceneNode(...)
方法明确声明创建的节点 不是 图形的一部分?¹, 和SceneNode
可以在SceneManager
不知情的情况下独立创建自己的 children?²
¹ SM不会自动将自己创建的场景节点变成children的其他节点(例如root);你必须在节点上手动调用 addChild
² 客户端只要写sceneManager->getRootSceneNode()->createChildSceneNode("Child");
,SM就不知道新child的存在
背景
我在查看 OGRE3D 中的源代码时发现了以下关于 SceneManager
class 的文档(>> << 添加了重点):
/** 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 在它自己的名为 mSceneNodes
的 SceneNodeList
中搜索您请求的 SceneNode
。我想弄清楚的部分是文档声称它可以找到一个节点 "wherever it is in the scene graph"。新 SceneNode
仅在使用 SceneManager::createSceneNode(...)
时添加到 mSceneNodes
列表中。 SM 的 createSceneNode
方法的文档说 (>> << 添加了重点):
/** 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
class,它有自己的createChild(const String& name, ...)
方法,显然不是 将自己的children加入到SceneManager
的列表中,如下图:
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
将 不会 知道新 child 的存在节点,据我所知,所以它永远找不到它。
我已经研究了一段时间的源代码,但我没有找到这个问题的答案。我查看了 BspSceneManager
和 BspSceneNode
只是想看看我是否能发现其他东西,但结果是空的。
为了 completeness/reference,master 分支中当前可用的最新提交是:
commit 3b13abbdcce146b2813a6cc3bedf16d1d6084340
Author: mkultra333 <unknown>
Date: Sun May 8 19:31:39 2016 +0800
难怪这部分会让您感到困惑,因为它是十多年前的过度 OOP 的一部分。有人喜欢有人讨厌。
然而,如果您知道要查找的内容,答案就非常简单:
Node::createChild
的代码如下:
Node* newNode = createChildImpl( sceneType );
//...
return newNode;
它实际上将创建委托给createChildImpl
("implementer")。此函数是纯虚函数,因此SceneNode
必须重载。
当我们转到 SceneNode::createChildImpl
时,我们得到:
Node* SceneNode::createChildImpl(const String& name)
{
return mCreator->_createSceneNode( name );
}
mCreator
是一个 SceneManager
指针变量。所以你去了:当通过 createChildSceneNode
.
SceneNode
时,SceneManager
确实会收到通知
但是请注意,一个实现(例如 BspSceneManager
中的 BspSceneNode
)可能会使 createChildImpl
过载并且不会通知 SceneManager
;或者他们可能。
在 SceneManager::_createSceneNode
中放置一个断点并检查调用堆栈会让您省去很多麻烦。