BloodyMess Tutorial 3        
NxOgre   This page is related to a deprecated version of NxOgre, called BloodyMess. Some code from here may be adopted to newer versions with sufficient care and knowledge.   NxOgre


Disclaimer: This is not an official NxOgre tutorial. However, it has been revised and edited by the creator of NxOgre and BloodyMess, betajaen.

help Help: For any problems you encounter while working on these tutorials, as well as for detailed questions and propositions, please visit the NxOgre OgreAddons-Forum.

Image You can find the complete code for this tutorial here.

NxOgreCube.png Introduction

In the second tutorial, you learned how to set up out NxOgre world, scene, and render system as well as populate the scene with actors and bodies. Now you will get in contact with the aptly named Visual Debugger. The Visual Debugger is a built-in debugging tool for visually debugging all the physical interactions within our world. You can actually see the collision shapes and bounding boxes as well as all the non-visible actors within our scene such as floors and triggers/volumes (which will be dealt with in the next tutorial).

Visual Debugger Enabled
Visual Debugger Enabled

NxOgreCube.png The Initial Code

Start a new Ogre and NxOgre project in your -IDE. We will create the necessary code to make Ogre run using the ExampleApplication and ExampleFrameListener classes provided by the Ogre Samples.

Note: If you're fairly new with Ogre, it may be worth it modifying Ogre SkyBox sample instead of creating your own Ogre project.


The following code will serve as the basis for this tutorial. It should compile and run without errors.

#include "ExampleApplication.h"

#include <NxOgre.h>
#include <NxOgreOGRE3D.h>

class BloodyMessTutorial3Listener : public ExampleFrameListener
{ 
public:
    BloodyMessTutorial3Listener(RenderWindow *win, Camera *cam) 
        : ExampleFrameListener(win, cam)
    {
        mTimeController = NxOgre::TimeController::getSingleton();
    }

    bool frameStarted(const FrameEvent& evt)
    {
        mTimeController->advance(evt.timeSinceLastFrame);
        return ExampleFrameListener::frameStarted(evt);
    }

protected:
    NxOgre::TimeController* mTimeController;
};

class BloodyMessTutorial3 : public ExampleApplication
{
protected:
    NxOgre::World*            mWorld;
    NxOgre::Scene*            mScene;
    NxOgre::TimeController*        mTimeController;
    OGRE3DRenderSystem*        mRenderSystem;

    OGRE3DBody*            mCube;
    OGRE3DBody*            mCubeTwo;

    void createScene()
    {
        // Set ambient light
        mSceneMgr->setAmbientLight(ColourValue(0.5f, 0.5f, 0.5f));

        // Create a light
        Light* l = mSceneMgr->createLight("MainLight");
        l->setPosition(20, 80, 50);

        // Position the camera
        mCamera->setPosition(0, 20, 80);
        mCamera->lookAt(0, 20, 0);

        // Create the world
        mWorld = NxOgre::World::createWorld();

        // Create scene description
        NxOgre::SceneDescription sceneDesc;
        sceneDesc.mGravity = NxOgre::Vec3(0, -9.8f, 0);
        sceneDesc.mName = "DemoScene";

        // Create scene
        mScene = mWorld->createScene(sceneDesc);

        // Set some physical scene values
        mScene->getMaterial(0)->setStaticFriction(0.5);
        mScene->getMaterial(0)->setDynamicFriction(0.5);
        mScene->getMaterial(0)->setRestitution(0.1);

        // Create render system
        mRenderSystem = new OGRE3DRenderSystem(mScene);

        //Create time controller
        mTimeController = NxOgre::TimeController::getSingleton();

        // Add objects
        mCube = mRenderSystem->createBody(new NxOgre::Box(1, 1, 1), NxOgre::Vec3(0, 40, 0), "cube.1m.mesh");
        mCubeTwo = mRenderSystem->createBody(new NxOgre::Box(1, 1, 1), NxOgre::Vec3(20, 45, 0), "cube.1m.mesh");
        mCubeTwo->addForce(NxOgre::Vec3(-800, -200, 0), NxOgre::Enums::ForceMode_Force);

        // Create floor plane (BloodyMess)
        mScene->createSceneGeometry(new NxOgre::PlaneGeometry(0, NxOgre::Vec3(0, 1, 0)), Matrix44_Identity);

        // Create floor plane (Ogre)
        MovablePlane *plane = new MovablePlane("Plane");
        plane->d = 0;
        plane->normal = Vector3::UNIT_Y;
        Ogre::MeshManager::getSingleton().createPlane("PlaneMesh", 
            ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, 
            *plane, 120, 120, 1, 1, true, 1, 3, 3, Vector3::UNIT_Z);
        Entity *planeEnt = mSceneMgr->createEntity("PlaneEntity", "PlaneMesh");
        planeEnt->setMaterialName("Examples/GrassFloor");

        Ogre::SceneNode* mPlaneNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();
        mPlaneNode->attachObject(planeEnt);
    }

    // Create a new frame listener
    void createFrameListener()
    {
        mFrameListener = new BloodyMessTutorial3Listener(mWindow, mCamera);
        mRoot->addFrameListener(mFrameListener);
    }
};

#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
#define WIN32_LEAN_AND_MEAN
#include "windows.h"
#endif

#ifdef __cplusplus
extern "C" {
#endif

#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
    INT WINAPI WinMain(HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT)
#else
    int main(int argc, char **argv)
#endif
    {
        // Create application object
        BloodyMessTutorial3 app;

        try {
            app.go();
        } catch(Exception& e) {
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
            MessageBoxA(NULL, e.getFullDescription().c_str(),
                "An exception has occurred!", MB_OK | MB_ICONERROR | MB_TASKMODAL);
#else
            std::cerr << "An exception has occurred: " << e.getFullDescription();
#endif
        }

        return 0;
    }

#ifdef __cplusplus
}
#endif

NxOgreCube.png Initializing the VisualDebugger

First of all, we need to declare three new variables within the private section of our tutorial class:

NxOgre::VisualDebugger*    mVisualDebugger;
OGRE3DRenderable*        mVisualDebuggerRenderable;
Ogre::SceneNode*        mVisualDebuggerNode;


Then, within our createScene() function, after our World has been created, you can then initialize the Visual Debugger:

mVisualDebugger = mWorld->getVisualDebugger();


We now have to create a new OGRE3DRenderable with the type of RenderableType_VisualDebugger. Then we tell our Visual Debugger, that it should use our new OGRE3DRender system. Then we create a new Ogre::SceneNode and attach the renderable Visual Debugger to it. The last step is to set how much debug information we see in our Visual Debugger.

Place all this code after we initialize the Visual Debugger:

mVisualDebuggerRenderable = new OGRE3DRenderable(NxOgre::Enums::RenderableType_VisualDebugger);
mVisualDebugger->setRenderable(mVisualDebuggerRenderable);
mVisualDebuggerNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();
mVisualDebuggerNode->attachObject(mVisualDebuggerRenderable);
mVisualDebugger->setVisualisationMode(NxOgre::Enums::VisualDebugger_ShowAll);

NxOgreCube.png Extending the Framelistener

Some changes need to be done on our framelistener class: two members have to be added, the constructor has to be changed and the frameStarted() function has to be extended a bit. Replace the frame listener class, or modify it to look like the following:

class BloodyMessTutorial3Listener : public ExampleFrameListener
{ 
public:
    BloodyMessTutorial3Listener(RenderWindow *win, Camera *cam, NxOgre::VisualDebugger* visualDebugger, Ogre::SceneNode* node) 
        : ExampleFrameListener(win, cam)
    {
        mTimeController = NxOgre::TimeController::getSingleton();
        mVisualDebugger = visualDebugger;
        mVisualDebuggerNode = node;
    }

    bool frameStarted(const FrameEvent& evt)
    {
        mTimeController->advance(evt.timeSinceLastFrame);
        mVisualDebugger->draw();
        mVisualDebuggerNode->needUpdate();

        return ExampleFrameListener::frameStarted(evt);
    }

protected:
    NxOgre::TimeController*        mTimeController;
    NxOgre::VisualDebugger*        mVisualDebugger;
    Ogre::SceneNode*            mVisualDebuggerNode;
};


You also need to pass the VisualDebugger and its node to our FrameListener class. Therefore the function createFrameListener() should look like this now:

// Create a new frame listener
void createFrameListener()
{
    mFrameListener = new BloodyMessTutorial3Listener(mWindow, mCamera, mVisualDebugger, mVisualDebuggerNode);
    mRoot->addFrameListener(mFrameListener);
}


Compile and run and you will now be able to "visualize" the physics engine at work. This is most helpful when objects in your world are not behaving as they should and allows you to see what is going on.

Note: If you are using NxOgre BloodyMess version 1.5.5, the visual debugger has been disabled. See the release thread for details.

NxOgreCube.png Conclusion

That's it! You have now learned to use the Visual Debugger NxOgre, along with create and add objects to our scene. In the next tutorial we will cover volumes/triggers, which we would not be able to see without the Visual Debugger.