[英]How can the OGRE3D SceneManager really find *any* SceneNode?
How can the SceneManager
actually find any SceneNode
regardless of where it happens to be in the graph when: 在以下情况下,
SceneManager
如何实际找到任何SceneNode
无论它在图表中的位置如何 :
SceneManager::createSceneNode(...)
method explicitly claims that the nodes created are not part of the graph?¹, and SceneManager::createSceneNode(...)
方法明确声明创建的节点不是图的一部分?¹, 和 SceneNode
s can independently create their own children without the SceneManager
's knowledge?² SceneNode
可以在没有SceneManager
知识的情况下独立创建自己的子SceneManager
吗?² ¹ The SM does not automatically turn the scene nodes it creats into children of other nodes (eg root); ¹SM 不会自动将其创建的场景节点转换为其他节点的子节点(例如root); you have to manually call
addChild
on a node for that 您必须在节点上手动调用
addChild
² The client can simply write sceneManager->getRootSceneNode()->createChildSceneNode("Child");
² 客户端可以简单地编写
sceneManager->getRootSceneNode()->createChildSceneNode("Child");
, and the SM wouldn't know about the new child's existence SM不会知道新生儿的存在
I was going over the source code in OGRE3D and came across the following piece of documentation on the SceneManager
class (>> << emphasis added): 我正在浏览OGRE3D中的源代码,并在
SceneManager
类上看到了以下文档(>> << emphasis added):
/** 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;
When you look at the implementation, you see: 查看实现时,您会看到:
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;
}
So far, so good. 到现在为止还挺好。 We can see that the SM searches for your requested
SceneNode
in its own SceneNodeList
named mSceneNodes
. 我们可以看到SM在自己的
SceneNodeList
名为mSceneNodes
请求的SceneNode
。 The part I'm trying to figure out is that the documentation claims it can find a node "wherever it is in the scene graph". 我想弄清楚的部分是文档声称它可以找到一个节点“它在场景图中的任何地方”。 New
SceneNode
s are only added into the mSceneNodes
list when using SceneManager::createSceneNode(...)
. 使用
SceneManager::createSceneNode(...)
时,新的SceneNode
仅添加到mSceneNodes
列表中。 The documentation for the SM's createSceneNode
method says (>> << emphasis added): SM的
createSceneNode
方法的文档说(>> << emphasis added):
/** 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);
At the same time, if you look at the SceneNode
class, it has its own createChild(const String& name, ...)
method, which clearly does not add its own children into the SceneManager
's list, as shown below: 同时,如果你看一下
SceneNode
类,它有自己的createChild(const String& name, ...)
方法,它显然没有将自己的子SceneManager
添加到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));
}
This means that if the client program says node.createChildSceneNode(...);
这意味着如果客户端程序说
node.createChildSceneNode(...);
, the SceneManager
would not be aware of the existence of the new child node, AFAIK, so it'd never be able to find it. ,
SceneManager
不会意识到新的子节点AFAIK的存在,所以它永远无法找到它。
I've been studying the source code for a while now and I've not found an answer to this question. 我已经研究了一段时间的源代码,但我没有找到这个问题的答案。 I looked at the
BspSceneManager
and the BspSceneNode
just to see if I could spot something else, but came up empty. 我查看了
BspSceneManager
和BspSceneNode
只是为了看看我是否能找到别的东西,但是空了。
For the sake of completeness/reference, the most recent commit currently available in the master branch is: 为了完整性/参考,master分支中当前可用的最新提交是:
commit 3b13abbdcce146b2813a6cc3bedf16d1d6084340
Author: mkultra333 <unknown>
Date: Sun May 8 19:31:39 2016 +0800
It's no wonder this part confuses you because it's part of over-OOP from more than a decade ago. 难怪这部分会让你感到困惑,因为它是十多年前OOP的一部分。 Some like it, some hate it.
有些人喜欢它,有些人讨厌它。
The answer however, is quite simple if once you know what to look for: The code for Node::createChild
is the following: 但是,如果您知道要查找的内容,答案非常简单:
Node::createChild
的代码如下:
Node* newNode = createChildImpl( sceneType );
//...
return newNode;
It actually delegates creation to createChildImpl
(the "implementer"). 它实际上将创建委托给
createChildImpl
(“实现者”)。 This function is a pure virtual function, thus SceneNode
must overload. 此函数是纯虚函数,因此
SceneNode
必须重载。
When we go to SceneNode::createChildImpl
, we get: 当我们转到
SceneNode::createChildImpl
,我们得到:
Node* SceneNode::createChildImpl(const String& name)
{
return mCreator->_createSceneNode( name );
}
mCreator
is a SceneManager
pointer variable. mCreator
是一个SceneManager
指针变量。 So there you go: The SceneManager
does get informed when a SceneNode
is created via createChildSceneNode
. 所以你去:当通过
createChildSceneNode
创建SceneNode
时, SceneManager
会得到通知。
Note however an implementation (eg BspSceneNode
in BspSceneManager
) may overload createChildImpl
and not inform the SceneManager
; 但是请注意,实现(例如
BspSceneNode
中的BspSceneManager
)可能会重载createChildImpl
而不会通知SceneManager
; or they may. 或者他们可能。
Placing a breakpoint inside SceneManager::_createSceneNode
and checking out the callstack will save you a lot of headaches though. 在
SceneManager::_createSceneNode
放置一个断点并检出callstack会让你省去很多麻烦。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.