Boost Python 和 OGRE - 具有相同代码的不同结果

Posted

技术标签:

【中文标题】Boost Python 和 OGRE - 具有相同代码的不同结果【英文标题】:Boost Python and OGRE - Different results with equivalent code 【发布时间】:2014-09-07 16:29:18 【问题描述】:

我会重新发布what I posted on the OGRE forums:

我不确定是在这里发帖还是在“在实践中使用 OGRE”论坛发帖更好,但我会试一试,因为这是看板中最常出现的部分。

所以我正在为我自己的在内部使用 OGRE 的框架进行绑定,我已经绑定了核心对象,并且在大多数情况下它们工作正常(输入和窗口工作正常),但我遇到了这个问题我无法深入了解 - Python 应用程序的视口始终为黑色(除了相机,我没有其他对象,只是设置视口的背景颜色)。

奇怪的是 - C++ 中的完全等价物可以正常工作,但 python 绑定的代码却不能。日志中没有显示任何重要的内容。

这是我绑定对象的方法:

#include "boost/python.hpp"
#include "boost/exception/diagnostic_information.hpp"
#include "Demo.hpp"
#include "Demo.cpp"
#include "XMLLevelLoader.h"

void addResourceLocation(const Crimson::String& group, const Crimson::String& loc)

    Ogre::ResourceGroupManager* resmgr = Ogre::ResourceGroupManager::getSingletonPtr();
    resmgr->addResourceLocation(loc, "FileSystem", group);


void initResourceGroup(const Crimson::String& group)

    Ogre::ResourceGroupManager* resmgr = Ogre::ResourceGroupManager::getSingletonPtr();
    resmgr->initialiseResourceGroup(group);


class AppWrapper : public Crimson::Application, public boost::python::wrapper<Crimson::Application>

public:
    void onKeyDown(const SDL_KeyboardEvent& e)
    
        boost::python::override over = this->get_override("onKeyDown");
        if (over)
            over(e);
    
    using Crimson::Application::mQuit;
;

BOOST_PYTHON_MODULE(PyEngine)

    using namespace boost::python;
    def("initResourceGroup", initResourceGroup);
    def("addResourceLocation", addResourceLocation);

    enum_<SDL_Scancode>("SDL_Scancode");

    class_<Ogre::ColourValue>("Color", init<const float, const float, const float, const float>())
        .def_readwrite("r", &Ogre::ColourValue::r)
        .def_readwrite("g", &Ogre::ColourValue::g)
        .def_readwrite("b", &Ogre::ColourValue::b)
        .def_readwrite("a", &Ogre::ColourValue::a);

    class_<Ogre::Viewport>("Viewport", init<Ogre::Camera* , Ogre::RenderTarget*, float, float, float, float, int>())
        .def("setBackgroundColour", &Ogre::Viewport::setBackgroundColour);

    class_<Crimson::WindowInfo>("WindowInfo")
        .def_readonly("renderWnd", &Crimson::WindowInfo::renderWnd)
        .def_readonly("sdlWnd", &Crimson::WindowInfo::sdlWnd)
        .def("addViewport", &Crimson::WindowInfo::addViewport, return_value_policy<reference_existing_object>())
        .def("getAspectRatio", &Crimson::WindowInfo::getAspectRatio)
        .def("getWidth", &Crimson::WindowInfo::getWidth)
        .def("getHeight", &Crimson::WindowInfo::getHeight);

    class_<Crimson::Kernel>("Kernel")
        .def("initialize", &Crimson::Kernel::initialize)
        .def("createRenderWindow", &Crimson::Kernel::createRenderWindow, return_value_policy<reference_existing_object>())
        .def("getWindowInfo", &Crimson::Kernel::getWindowInfo, return_value_policy<reference_existing_object>())
        .def("destroy", &Crimson::Kernel::destroy)
        .def("render", &Crimson::Kernel::render);

    class_<Crimson::Actor>("Actor", init<Crimson::Level*, const Crimson::String&, Crimson::Actor*>())
        .def("setPosition", static_cast<void(Crimson::Actor::*)(const Crimson::Vector3&)>(&Crimson::Actor::setPosition))
        .def("getPosition", &Crimson::Actor::getPosition);

    class_ <Crimson::Mesh, bases<Crimson::Actor>>("Mesh", init<Crimson::Level*, const Crimson::String&, const Crimson::String&, Crimson::Actor*>());

    class_ <Crimson::Camera, bases<Crimson::Actor>>("Camera", init<Crimson::Level*, const Crimson::String&, Crimson::Actor*>())
        .def("setAspectRatio", &Crimson::Camera::setAspectRatio);

    class_<rapidxml::xml_node<>, boost::noncopyable>("xml_node", init<rapidxml::node_type>())
        .def("first_node", &rapidxml::xml_node<>::first_node, return_value_policy<reference_existing_object>());

    class_<rapidxml::xml_document<>, boost::noncopyable>("xml_document")
        .def("first_node", &rapidxml::xml_document<>::first_node, return_value_policy<reference_existing_object>())
        .def("parse", &rapidxml::xml_document<>::parse<0>);

    class_<Crimson::Level>("Level", init<Crimson::Kernel*>())
        .def("initialize", &Crimson::Level::initialize)
        .def("destroy", &Crimson::Level::destroy)
        .def("createActor", &Crimson::Level::createActor, return_value_policy<reference_existing_object>())
        .def("createMesh", &Crimson::Level::createMesh, return_value_policy<reference_existing_object>())
        .def("createCamera", &Crimson::Level::createCamera, return_value_policy<reference_existing_object>());

    class_<Crimson::XMLLevelLoader>("XMLLevelLoader", init<Crimson::String>())
        .def("load", &Crimson::XMLLevelLoader::load)
        .def("loadFileAsString", &Crimson::XMLLevelLoader::loadFileAsString)
        .def("loadResources", &Crimson::XMLLevelLoader::loadResources)
        .staticmethod("loadFileAsString")
        .staticmethod("loadResources");

    class_<AppWrapper, boost::noncopyable>("Application")
        .def("initialize", &Crimson::Application::initialize)
        .def("destroy", &Crimson::Application::destroy)
        .def("onKeyDown", &Crimson::Application::onKeyDown)
        .def("start", &Crimson::Application::start)
        .def("updateGraphics", &Crimson::Application::updateGraphics)
        .def("updateInput", &Crimson::Application::updateInput)
        .def("isRunning", &Crimson::Application::isRunning)
        .def("quit", &Crimson::Application::quit)
        .def("getKernel", &Crimson::Application::getKernel, return_value_policy<reference_existing_object>());

    class_<SDL_Keysym>("SDL_Keysym")
        .def_readonly("mod", &SDL_Keysym::mod)
        .def_readonly("scancode", &SDL_Keysym::scancode);

    class_<SDL_KeyboardEvent>("SDL_KeyboardEvent")
        .def_readonly("keysym", &SDL_KeyboardEvent::keysym);

    class_<Ogre::Vector3>("Vector3", init<const float, const float, const float>())
        .def_readwrite("x", &Ogre::Vector3::x)
        .def_readwrite("y", &Ogre::Vector3::y)
        .def_readwrite("z", &Ogre::Vector3::z);

Python 代码(空白视口):

import sys
from PyEngine import *

# Class definition
class TestPythonApp(Application):
    def initialize(self):
        Application.initialize(self)

        mLevel = Level(self.getKernel())
        mLevel.initialize()

        mCamera = mLevel.createCamera("test", None)
        vp = self.getKernel().getWindowInfo().addViewport(mCamera)
        vp.setBackgroundColour(Color(0.8, 0, 0, 1))
    def start(self):
        while self.isRunning():
            self.updateInput()
            self.updateGraphics(1)

    mLevel  = None
    mCamera = None

# /Class definition

# Script execution
app = TestPythonApp()
app.initialize()
app.start()
app.destroy()

C++ 等效项(彩色视口):

-- 标题

#ifndef PYAPP_HPP
#define PYAPP_HPP
#include "Application.h"
#include "XMLLevelLoader.h"

class PythonApp : public Crimson::Application

public:
    bool initialize();
    void start();

protected:
    Crimson::Camera*    mCamera;
    Crimson::Level*     mLevel;
;
#endif

-- Source:
bool PythonApp::initialize()

    Application::initialize();

    mLevel = new Crimson::Level(mKernel);
    mLevel->initialize();
    mCamera = mLevel->createCamera("cam");
    Ogre::Viewport* vp = mKernel->getWindowInfo()->addViewport(mCamera);
    vp->setBackgroundColour(Ogre::ColourValue(0.7f, 0.8f, 0.7f));

    return true;


void PythonApp::start()

    while (isRunning())
    
        updateInput();
        updateGraphics(1);
    


int main(int argc, char* argv[])

    PythonApp game;
    game.initialize();
    game.start();
    game.destroy();

    return 0;

我做了检查 - mBackColor(在 Ogre::Viewport 中)已通过 Python 正确设置,所以这不是问题。

此外,如果我将渲染循环放在initialize() 函数内,Python 代码会因某种原因正常工作,但如果它不在此范围内,则不会。正因为如此,我觉得这是一个上下文问题(也许当解释器退出初始化函数或其他东西时数据被破坏了。

这是奇怪的 Python 代码:

import sys
from PyEngine import *

# Class definition
class TestPythonApp(Application):
    def initialize(self):
        Application.initialize(self)

        mLevel = Level(self.getKernel())
        mLevel.initialize()

        mCamera = mLevel.createCamera("test", None)
        vp = self.getKernel().getWindowInfo().addViewport(mCamera)
        vp.setBackgroundColour(Color(0.8, 0, 0, 1))
        self.start() # Moved line app.start() to here.
    def start(self):
        while self.isRunning():
            self.updateInput()
            self.updateGraphics(1)

    mLevel  = None
    mCamera = None

# /Class definition

# Script execution
app = TestPythonApp()
app.initialize()
#app.start() # This moved up to initialize makes it work
app.destroy()

-- 关于我的框架的一些信息:内核包含和调用Ogre::RootmLevel 包含一个场景管理器,mCamera 是一个普通的 OGRE 相机,只是通过我自己的 API 包装以方便使用 WindowInfo 是另一个处理窗口设置(在 OGRE 和 SDL 之间)的包装类,我只是在我的 updateGraphics(delta) 函数中调用 renderOneFrame()

那么我做错了什么,与 C++ 调用具有相同调用的 python 代码导致不同的结果?

【问题讨论】:

【参考方案1】:

好的,所以在设置了很多断点之后,我发现当解释器退出函数 initialize() 时,它破坏了 mLevelmCamera 对象,因为(我是 Python 新手)我忘记了在 Python 中 self/this 不是隐含的,因此我的对象由于 Ogre::SceneManager 的破坏而被破坏(在删除 mLevel 时)。

更新(工作)代码:

import sys
from PyEngine import *

# Class definition
class TestPythonApp(Application):
    def initialize(self):
        Application.initialize(self)

        self.mLevel = Level(self.getKernel())
        self.mLevel.initialize()

        self.mCamera = self.mLevel.createCamera("test", None)
        self.mViewport = self.getKernel().getWindowInfo().addViewport(self.mCamera)
        self.mViewport.setBackgroundColour(Color(0.8, 0, 0, 1))
        print("Object: %s, of size: %d" % (self.mViewport, sys.getsizeof(self.mViewport)))
        #self.start();
    def start(self):
        while self.isRunning():
            self.updateInput()
            self.updateGraphics(1)

    mLevel   = None
    mViewport = None
    mCamera      = None

# /Class definition

# Script execution
app = TestPythonApp()
print("Initing");
app.initialize()
print("Object: %s, of size: %d" % (app.mViewport, sys.getsizeof(app.mViewport)))
app.start() # This moved up to initialize makes it work
app.destroy()

【讨论】:

那么,这个问题解决了吗?通过在Ogre3D forums 阅读您自己的答案,我认为是这样。如果是,请将您自己的答案标记为“已接受”。 是的,我想我当时由于某种原因无法接受自己的答案,现在完成了。

以上是关于Boost Python 和 OGRE - 具有相同代码的不同结果的主要内容,如果未能解决你的问题,请参考以下文章

用mingw编译Ogitor

Boost python,使用命名空间调用函数对象

C++ 网络程序设计:Boost Asio、序列化和 OStream

Boost python getter/setter 同名

提升几何相交会产生奇怪的结果

ogre引擎