How to really "clear" a scene

If you are a new Irrlicht Engine user, and have a newbie-question, this is the forum for you. You may also post general programming questions here.
Post Reply
LesPaul75
Posts: 35
Joined: Tue Jan 22, 2013 8:27 am

How to really "clear" a scene

Post by LesPaul75 »

Hi,

I'm having trouble getting the scene manager to fully clear the current scene.

I have separated my code into lots of different "modes." Modes are things like:

splash_screen_mode
main_menu_mode
graphics_menu_mode
audio_menu_mode
level_1_mode
level_2_mode
...
game_over_mode

Each mode has an "init_scene" member that looks like this (for example):

Code: Select all

void level_1_mode::init_scene(irr::scene::ISceneManager *scene)
{
    m_camera_node = scene->addCameraSceneNode();
    m_camera_node->setUpVector(v3f(0.0f, 0.0f, 1.0f));
    m_camera_node->setFOV(0.6f * math::pi);
 
    irr::scene::ILightSceneNode *light = scene->addLightSceneNode();
    light->getLightData().SpecularColor.set(0.3f, 0.3f, 0.3f);
    light->setLightType(irr::video::ELT_DIRECTIONAL);
    light->setRotation(v3f(45.0f, 135.0f, 0.0f));
 
    m_world_center_node = scene->addEmptySceneNode();
    m_world_center_node->setPosition(v3f(0.0f, -WORLD_RADIUS, 0.0f));
 
    irr::scene::IAnimatedMesh *world_mesh = scene->getMesh("level_a1.obj");
 
    scene->getMeshManipulator()->scale(world_mesh, v3f(WORLD_MODEL_SCALE, WORLD_MODEL_SCALE, WORLD_MODEL_SCALE));
    scene->addMeshSceneNode(world_mesh, m_world_center_node, -1, v3f(0.0f, WORLD_RADIUS, 0.0f));
}
Basically, it just sets up the lights, cameras, and meshes for whatever is happening in this particular mode. Now, the code that actually calls this init_scene() method is the application's main loop, and it works like this:

Code: Select all

    while (m_device->run())
    {
        if (change_to_new_mode)
        {
            // Clear everything from the current mode's scene
            m_scene->clear();
 
            // Switch to the new mode
            m_current_mode = new_mode;
 
            // Initialize the new mode's scene
            m_game_modes[m_current_mode]->init_scene(m_scene);
        }
    }
What I'm seeing is that the call to "m_scene->clear()" isn't really clearing the meshes. They still sort of exist, behind the scenes, which causes problems. If I switch from "level_1_mode" to "main_menu_mode" (which would happen whenever the user presses the ESC key while playing level 1, for example) and then switch back to "level_1_mode" (user changed some menu options and then pressed ESC key again to return to the game), the method level_1_mode::init_scene() gets called a second time, but the world mesh isn't really destroyed and recreated. It's still the same one that was created on the first call, which means that it's already scaled, which means that it gets scaled again and is now the wrong size.

How do I really clear the scene so that all meshes are fully reloaded each time I switch to a new mode? I've experimented and found that completely destroying and recreating the Irrlicht device does the trick, but that isn't very desirable, because it closes the whole window, etc...
hendu
Posts: 2600
Joined: Sat Dec 18, 2010 12:53 pm

Re: How to really "clear" a scene

Post by hendu »

The node did get cleared, but the mesh stayed in the mesh cache. As you modified the mesh directly (instead of scaling the node in the addMeshSceneNode function), the scaling persists.

Keeping the cache is advised, as it speeds up your transitions back and forth. Don't scale the model, scale the node.
Seven
Posts: 1034
Joined: Mon Nov 14, 2005 2:03 pm

Re: How to really "clear" a scene

Post by Seven »

a different approach would be to use a different scenemanager and then switch between them instead. then there is no clearing required, you just render whichever scenemanager happens to be the 'active' one.
LesPaul75
Posts: 35
Joined: Tue Jan 22, 2013 8:27 am

Re: How to really "clear" a scene

Post by LesPaul75 »

hendu wrote:The node did get cleared, but the mesh stayed in the mesh cache. As you modified the mesh directly (instead of scaling the node in the addMeshSceneNode function), the scaling persists.

Keeping the cache is advised, as it speeds up your transitions back and forth. Don't scale the model, scale the node.
I don't remember the reason, but just scaling the node didn't work, so I had to switch to actually scaling the mesh.

Seems like a bug in the caching architecture. Scaling the actual mesh should mark it "dirty" because it is a modification of the data. Reloading should "evict" the dirty copy and load it again. That's how caches (of all kinds) maintain coherency.
Seven wrote:a different approach would be to use a different scenemanager and then switch between them instead. then there is no clearing required, you just render whichever scenemanager happens to be the 'active' one.
I really like this idea because it will save me from having to rebuild the entire scene when switching from "level" to "menu" back and forth. It will obviously mean in increase in memory use.

Thanks.
LesPaul75
Posts: 35
Joined: Tue Jan 22, 2013 8:27 am

Re: How to really "clear" a scene

Post by LesPaul75 »

To follow up, I went with multiple SceneManagers. It works nicely. There is one catch if you go with this approach, though. Suppose your "main" scene is the actual game, and your second scene is the menu. If the player opens the menu and changes graphics options, that will cause the device to be reset, which destroys all scenes. So you'll have to rebuild the main scene when the user exits out of the menu. Not a big deal. I just treat it exactly like saving/loading a game. The whole scene is recreated from a state that was saved before entering the menu scene.

Thanks for the advice.
Marthog
Posts: 31
Joined: Sun Oct 03, 2010 8:33 pm
Contact:

Re: How to really "clear" a scene

Post by Marthog »

I don't think that recreating is a good solution. You can grab the SceneManagers and reuse them for the new device.
Rust fanboy
LesPaul75
Posts: 35
Joined: Tue Jan 22, 2013 8:27 am

Re: How to really "clear" a scene

Post by LesPaul75 »

Marthog wrote:I don't think that recreating is a good solution. You can grab the SceneManagers and reuse them for the new device.
That would be more efficient... is there a particular method to call to "save" a scene manager, or do I just copy it via the standard "=" operator?
LesPaul75
Posts: 35
Joined: Tue Jan 22, 2013 8:27 am

Re: How to really "clear" a scene

Post by LesPaul75 »

After much progress, I've come back to this topic with a related question. First, though, I have an answer to the question I originally asked:
What I'm seeing is that the call to "m_scene->clear()" isn't really clearing the meshes. They still sort of exist, behind the scenes, which causes problems.
The solution to this is to not just clear the scene, but also the scene's mesh cache:

Code: Select all

m_scene->clear();
m_scene->getMeshCache()->clear();
That solves the problems with cached meshes when you re-initialize a scene.

I decided to follow advice and create multiple scene managers. I have one for each "mode," which is convenient. It might be a little wasteful, but not horribly, because only one scene is ever actively doing anything. Only one or two actually have any nodes at any given time. For example, you might be in "level_1_mode" and you press the menu button, so "main_menu_mode" pops up. The scene manager for "level_1_mode" just sits there idle while you move around the menu, then is destroyed when you exit back to the game.

There are two problems I've found with this approach:
1) The multiple scene managers are created with createNewSceneManager(), which I thought meant that I need to drop() them when done. But calling drop() causes a crash at the "delete this;" line in IReferenceCounted::drop(). I don't know why it crashes, because the "this" pointer looks valid and the current reference count is 1 before the call, then gets decremented to 0 as it should.
2) In my menu, I allow the user to change display settings. I do this using a sequence I found here in the forums:

Code: Select all

m_device->closeDevice();
m_device->run();
m_device->drop();
m_device = irr::createDeviceEx(m_create_params);
But that causes big problems in all my scene managers, like nodes disappearing... so I assume they all have to be recreated whenever the device is recreated?
LesPaul75
Posts: 35
Joined: Tue Jan 22, 2013 8:27 am

Re: How to really "clear" a scene

Post by LesPaul75 »

More info on the second issue -- what appears to be happening is that the textures are all wrong. My nodes are still there, I think, but some of them lose their textures or start using the wrong texture. The camera also appears to be in the wrong place -- probably as a result of the screen resolution changing... ?

The only workaround I see is saving the game state and reloading it whenever the graphics settings change, rebuilding the scene. I would love to have an alternative, though, because that's going to be a pretty noticeable delay every time the user changes graphics options.
mongoose7
Posts: 1227
Joined: Wed Apr 06, 2011 12:13 pm

Re: How to really "clear" a scene

Post by mongoose7 »

1. I wouldn't call 'run' after 'closeDevice' as there is no OpenGL/D3D context.
2. 'closeDevice' presumable frees the OpenGL/D3D context, so the texture bindings are lost. After obtaining a new context, there will be no textures, though the textures are probably still in the Irrlicht texture cache.
LesPaul75
Posts: 35
Joined: Tue Jan 22, 2013 8:27 am

Re: How to really "clear" a scene

Post by LesPaul75 »

Ok, so how do I change the graphics settings? I took that code from a post here in the forums.
hendu
Posts: 2600
Joined: Sat Dec 18, 2010 12:53 pm

Re: How to really "clear" a scene

Post by hendu »

I usually just require a restart.
LesPaul75
Posts: 35
Joined: Tue Jan 22, 2013 8:27 am

Re: How to really "clear" a scene

Post by LesPaul75 »

Yeah, I guess I pretty much have to punt at this point and not allow graphics settings to be modified in-game. It's too buggy. Disappointing. I spent a fair amount of time on a nice looking menu system to allow it. Maybe I'll get motivated enough at some point to try debugging the Irrlicht code.
Post Reply