简体   繁体   English

OGRE3D SceneManager如何真正找到* any * SceneNode?

[英]How can the OGRE3D SceneManager really find *any* SceneNode?

TL;DR; TL; DR;

How can the SceneManager actually find any SceneNode regardless of where it happens to be in the graph when: 在以下情况下, SceneManager如何实际找到任何SceneNode 无论它在图表中的位置如何

  1. The SceneManager::createSceneNode(...) method explicitly claims that the nodes created are not part of the graph?¹, and SceneManager::createSceneNode(...)方法明确声明创建的节点不是图的一部分?¹,
  2. 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不会知道新生儿的存在


Background 背景

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. 我查看了BspSceneManagerBspSceneNode只是为了看看我是否能找到别的东西,但是空了。


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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM