Coloring A Scene Node

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
so1odo1o
Posts: 32
Joined: Sat Apr 03, 2010 10:29 am

Coloring A Scene Node

Post by so1odo1o »

I am working on a program that turns the nearest node to the camera to be yellow. I have created nodes around the scene using addSphereSceneNode. Currently, it is displaying many black nodes across the scene.

Now what I want to do is turn the nearest node to be yellow. Working in an unlit environment, I was told earlier that I would have to edit the vertex colors. I am having trouble finding out how to edit the vertex colors for a single node. It says I need to access the mesh but I am confused on how to retrieve the mesh from the node.

It seems like a simple problem that I can't seem to understand. Please help me out.
so1odo1o
Posts: 32
Joined: Sat Apr 03, 2010 10:29 am

Post by so1odo1o »

I have changed from using addSphereSceneNode to just creating 2 spherical meshes, a black one and a yellow one. I then used addAnimatedMeshSceneNode to add the nodes to the scene, loading up the black mesh.

Now when I have the node ID, I am able to retrieve the node, but I am still unable to retrieve the mesh from the node. I am assuming I can cast it as an IMeshSceneNode, but I am having trouble doing that.

My code is below:

Code: Select all

scene::IMeshSceneNode* meshnode = smgr->getSceneNodeFromId(someID);
ONE MORE THING:
When I create the yellow mesh, how do I edit the vertex colors so that it will be a yellow sphere. I am using an unlit environment.

Please help me out, thanks.
vitek
Bug Slayer
Posts: 3919
Joined: Mon Jan 16, 2006 10:52 am
Location: Corvallis, OR

Post by vitek »

Yes, it is a relatively simple problem, but if all of the nodes you want to apply this to are the same, I'm going to suggest you do it a bit differently. Anyways, on to your question.

If you have a pointer to an ISceneNode, you can ask it for its actual type. If you find out that you have a mesh scene node, you can safely cast the ISceneNode pointer to IMeshSceneNode. Once you have a pointer to the derived class, you can access the functions of the derived class, one of which gives you access to the underlying IMesh. Now that you have a pointer to an IMesh object, there is just a little work to do. The IMesh contains a series of IMeshBuffer objects. For each of the IMeshBuffer objects, you need to change the vertex color for each of the vertices. This part is a bit tricky because you have to access the vertex data correctly.

You can actually use the IMeshManipulator functions like setVertexColors() or apply() to modify the mesh vertices. This makes things much simpler.

If all of your nodes are the same, I suggest that you create a copy of the original mesh and modify the vertex colors once. Then when you want to highlight one of your nodes, you just swap the mesh used by that scene node...

Code: Select all

// at program startup

scene::IMeshManipulator* manip = smgr->getMeshManipulator ();
scene::IGeometryCreator* geom = smgr->getGeometryCreator ();

// create two sphere meshes...
scene::IMesh* meshes [2];
meshes [0] = geom->createSphereMesh (...);
meshes [1] = manip->createMeshCopy (meshes [0]);

// modify the vertex color of the second mesh
manip->setVertexColors(meshes [1], video::SColor(255, 128, 128, 0));

// you could also use one of the manipulators instead
// manip->apply(scene::SVertex...Manipulator(...), meshes [1]);
Then, you create your nodes...

Code: Select all

smgr->addMeshScneNode(meshes [0], 0, pos, rot, scl);
You keep track of the selected node...

Code: Select all

// this part is probably outside your main loop or is your event receiver
// member data
scene::IMeshSceneNode* prev_selected = 0;

// this part is probably inside your main loop or in your event receiver
// event processing logic.

// your code should be able to get the selected node and make sure it
// is of the correct type.
scene::IMeshSceneNode* next_selected = //...

if (prev_selected != next_selected)
{
  // restore the mesh for the previously selected node
  if (prev_selected)
    prev_selected->setMesh (meshes [0]);

  // set the newly selected node to use the modified mesh
  if (next_selected)
    next_selected->setMesh (meshes [1]);

  // cache pointer to selected node
  prev_selected = next_selected;
}
Also, if you have a bunch of black nodes it is likely because you have lighting enabled, and you don't have any lights. If you want to not use lighting, you need to disable lighting on every node in the scene. i.e., you need to call node->setMaterialFlag(video::EMF_LIGHTING, false) for each node.

Travis
vitek
Bug Slayer
Posts: 3919
Joined: Mon Jan 16, 2006 10:52 am
Location: Corvallis, OR

Post by vitek »

so1odo1o wrote:

Code: Select all

scene::IMeshSceneNode* meshnode = smgr->getSceneNodeFromId(someID);
This code is not correct. The function getSceneNodeFromId() returns an ISceneNode*, and the compiler can't convert from ISceneNode* to IMeshSceneNode* unless you ask nicely.

Code: Select all

scene::ISceneNode* node = smgr->getSceneNodeFromId(someID);
if (node && node->getType() == scene::ESNT_MESH)
{
  scene::IMeshSceneNode* mesh_node = (scene::IMeshSceneNode*)node;

  // do other stuff here...
}
Travis
so1odo1o
Posts: 32
Joined: Sat Apr 03, 2010 10:29 am

Post by so1odo1o »

For some reason, the nodes are staying black.

Here is my code so far:

Code: Select all

	// Add nodes to graph
	scene::IMeshManipulator* manip = smgr->getMeshManipulator();

	scene::IMesh* meshes[2];
	meshes[0] = smgr->getGeometryCreator()->createSphereMesh(1.0, 16U, 16U);
	meshes[1] = manip->createMeshCopy(meshes[0]);
	manip->setVertexColors(meshes[1], video::SColor(255, 128, 128, 0));

	for(int i = 0; i < num; i++)
	{
		GraphNode gn = nodes.at(i);
		smgr->addMeshSceneNode(meshes[0], 0, gn._id, core::vector3df(gn._x,gn._y,gn._z));
	}

Main loop :

Code: Select all


    while(device->run())
	{
		if (device->isWindowActive())
        {
			driver->beginScene(true, true, video::SColor(255,200,200,200));

			// Set material
			video::SMaterial m;
			m.Lighting = false;
			driver->setMaterial(m);

			// Set world transform
			core::matrix4 identity;
			driver->setTransform(video::ETS_WORLD, identity);

...

			for(int i = 0; i < ids.size(); i++)
			{
				// Draw lines
				driver->draw3DLine(
					smgr->getSceneNodeFromId(ids[i].id1)->getAbsolutePosition(),
					smgr->getSceneNodeFromId(ids[i].id2)->getAbsolutePosition(),
					video::SColor(255,0,0,0));
			}

			// Find nearest node here
			core::vector3df camPos = smgr->getActiveCamera()->getAbsolutePosition();
			int oldID = nodes[0]._id;
			int newID = oldID;
			float smallestDist = camPos.getDistanceFrom(
				smgr->getSceneNodeFromId(nodes[0]._id)->getAbsolutePosition());
			for(int i = 0; i < num; i++)
			{
				float dist = camPos.getDistanceFrom(
					smgr->getSceneNodeFromId(nodes[i]._id)->getAbsolutePosition());
				if(dist <= smallestDist)
				{
					smallestDist = dist;
					newID = nodes[i]._id;

					scene::IMeshSceneNode* old_node = (scene::IMeshSceneNode*) smgr->getSceneNodeFromId(oldID);
					scene::IMeshSceneNode* new_node = (scene::IMeshSceneNode*) smgr->getSceneNodeFromId(newID);
					old_node->setMesh(meshes[0]);
					new_node->setMesh(meshes[1]);
I then tried adding meshes[1] after it hadbeen manipulated instead of meshes[0] above, but the nodes still appear as black.
vitek
Bug Slayer
Posts: 3919
Joined: Mon Jan 16, 2006 10:52 am
Location: Corvallis, OR

Post by vitek »

I'm pretty sure you didn't read this...
vitek wrote: Also, if you have a bunch of black nodes it is likely because you have lighting enabled, and you don't have any lights. If you want to not use lighting, you need to disable lighting on every node in the scene. i.e., you need to call node->setMaterialFlag(video::EMF_LIGHTING, false) for each node.
You have three choices...
  1. Disable lighting for every node in the scene (or just the ones you want) by calling node->setMaterialFlag(video::EMF_LIGHTING, false).
  2. Leave lighting enabled and turn on some ambient light with smgr->setAmbientLight(video::SColorf(.2f, .2f, .2f)).
  3. Leave lighting enabled and create a dynamic light with smgr->addLightSceneNode().
Travis
so1odo1o
Posts: 32
Joined: Sat Apr 03, 2010 10:29 am

Post by so1odo1o »

Sorry, I forgot to update my other post, but I did disable the lighting for each node right after:

Code: Select all

	// Add nodes to graph
	scene::IMeshManipulator* manip = smgr->getMeshManipulator();

	scene::IMesh* meshes[2];
	meshes[0] = smgr->getGeometryCreator()->createSphereMesh(1.0, 16U, 16U);
	meshes[1] = manip->createMeshCopy(meshes[0]);
	manip->setVertexColors(meshes[1], video::SColor(255, 128, 128, 0));

	for(int i = 0; i < num; i++)
	{
		GraphNode gn = nodes.at(i);
		scene::IMeshSceneNode* node = 
			smgr->addMeshSceneNode(meshes[0], 0, gn._id, core::vector3df(gn._x,gn._y,gn._z));
		if(node)
		{
			node->setMaterialFlag(video::EMF_LIGHTING, false);
		}
	}
Right now, random nodes are currently turning white. (No sign of yellow). Does it matter if I had done this later during beginScene and endScene:

Code: Select all

core::matrix4 identity;
driver->setTransform(video::ETS_WORLD, identity);
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

Well, you might want to turn off lighting for the yellow node as well :roll:
Also, next time keep with your original thread, makes this confusion a little less painful.
so1odo1o
Posts: 32
Joined: Sat Apr 03, 2010 10:29 am

Post by so1odo1o »

Ahh, that did the job. I assumed if I had set the material of the node to unlit, any meshes loaded into it would also be assumed to be unlit. Thank you very much.
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

setting a mesh also updates the materials. This is required because meshes can have different numbers of materials etc. You can change the value of the mesh, though, to avoid multiple calls to this method.
Post Reply