Can't See 3D Lines Drawn

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

Can't See 3D Lines Drawn

Post by so1odo1o »

I am having trouble displaying 3D lines using draw3DLine.

In my program I have a list of "GraphNodes" which contain the id and the coordinate of the nodes. I am successful in rendering the sphere nodes at the correct positions.

It is when I have to draw the 3D lines that is bugging me. I go through a file that contains 2 ids of the nodes to connect. I use those ids to find the nodes and connect their coordinates with draw3DLine.

I am sure that the nodes I get from the ids and coordinates I pass into draw3D line are correct. It is just that draw3Dline isn't doing what I expect it to do. All I see when I run the program is the sphere nodes.

Here is a portion of my code beginning where I create the scene:

Code: Select all

	// Create nodes in scene editor
	IrrlichtDevice *device =
		createDevice(video::EDT_OPENGL, core::dimension2d<u32>(640, 480));
	video::IVideoDriver* driver = device->getVideoDriver();
    scene::ISceneManager* smgr = device->getSceneManager();
	
	// Add nodes to graph
	for(int i = 0; i < num; i++)
	{
		GraphNode gn = nodes.at(i);

		smgr->addSphereSceneNode(1.0f, 16, 0, gn.getName(), 
			core::vector3df(gn.getX(), gn.getY(), gn.getZ()));
	}

	// Create relationships by searching through vector
	while(!myfile.eof())
	{
		string p1, p2;
		getline(myfile, p1, ' ');
		getline(myfile, p2);
		int id1, id2;
		istringstream str2int1(p1);
		istringstream str2int2(p2);
		str2int1 >> id1;
		str2int2 >> id2;

		driver->draw3DLine(
			smgr->getSceneNodeFromId(id1)->getPosition(),
			smgr->getSceneNodeFromId(id2)->getPosition());
	}

	// Add camera
	smgr->addCameraSceneNodeFPS();
	device->getCursorControl()->setVisible(false);

	int lastFPS = -1;

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

			int fps = driver->getFPS();

			if (lastFPS != fps)
			{
					lastFPS = fps;
			}
        }
        else
		{
			device->yield();
        }
	}

	myfile.close();
	device->drop();
B@z
Posts: 876
Joined: Thu Jan 31, 2008 5:05 pm
Location: Hungary

Post by B@z »

you have to call drawLine3D every time u want it to see, between driver->beginScene and driver->endScene
also, u might want to set the material, and the transformation, check the API for that
Image
Image
so1odo1o
Posts: 32
Joined: Sat Apr 03, 2010 10:29 am

Post by so1odo1o »

I've changed my code above to put what you said between beginscene and endscene. But it still isn't showing up.

Code: Select all

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

			while(!myfile.eof())
			{
				string p1, p2;
				getline(myfile, p1, ' ');
				getline(myfile, p2);
				int id1, id2;
				istringstream str2int1(p1);
				istringstream str2int2(p2);
				str2int1 >> id1;
				str2int2 >> id2;
				
				video::SMaterial m; 
				m.Lighting=false; 
				driver->setMaterial(m); 
				driver->setTransform(video::ETS_WORLD, core::matrix4());
				driver->draw3DLine(
					smgr->getSceneNodeFromId(id1)->getPosition(),
					smgr->getSceneNodeFromId(id2)->getPosition());
			}	

			smgr->drawAll();
			driver->endScene();

			int fps = driver->getFPS();

			if (lastFPS != fps)
			{
					lastFPS = fps;
			}
        }
        else
		{
			device->yield();
        }
vitek
Bug Slayer
Posts: 3919
Joined: Mon Jan 16, 2006 10:52 am
Location: Corvallis, OR

Post by vitek »

Your new code has nearly the same problem as the old code. If you want to see the lines, you have to draw them between the beginScene() and endScene() calls.

As you currently have it, the file myfile will be read from start to end on the first pass through the main loop. On every pass after that, the file will already be at eof and your inner loop will be skipped.

Looking at your code, I have some suggestions.

You have code to read two integers from a file. So you read two strings (separated by whitespace) from the file, convert those strings into streams, and then read integers from the streams. It would be much simpler and cheaper to read the integers from the file directly.

Another issue is that you are attempting to parse the file on every pass through the main loop. Parsing is expensive. I suggest that, unless you expect the file to change while the program is running, you parse the file once, and store the result in a collection of some type.

Since you're setting the world transform to the identity matrix, you need to draw your lines in world coordinates. If any of your scene nodes have a parent other than the root node, you need to use the absolute transform of the node to get the actual position, otherwise the lines won't appear in the right places.

One final suggestion would be to avoid setting the material and world transform to the same thing over and over again. Just set it once and use it.

In the end, you should get something like this...

Code: Select all

struct pair_of_id
{
  int id1, id2;
};

core::array<pair_of_id> ids;

// parse id list into array before our loop below
std::ifstream myfile("my_file.txt");
while (!myfile.eof())
{
  // simple code to parse pairs of integers from a file
  pair_of_id pid;
  myfile >> pid.id1 >> pid.id2;

  ids.push_back(pid);
}

// then in your main loop
while (device->run())
{
  driver->beginSecne(...);

  // set the material once
  video::SMaterial mat;
  mat.Lighting = false;
  driver->setMaterial(mat);

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

  for (int i = 0; i < ids.size(); ++i)
  {
    // draw the lines in the correct coordinate system
    driver->draw3DLine( 
      smgr->getSceneNodeFromId(ids[i].id1)->getAbsolutePosition(), 
      smgr->getSceneNodeFromId(ids[i].id2)->getAbsolutePosition()); 
  }

  driver->endScene();
}
Travis
so1odo1o
Posts: 32
Joined: Sat Apr 03, 2010 10:29 am

Post by so1odo1o »

Thank you, that helped a lot. The only thing is that the file myfile that I read from does not only include the two integer ids to connect. It contains the number of nodes to draw, the id of each node and its coordinates, and which node ids to connect. For example:

4
1 2.0 3.0 4.0
2 2.0 3.0 8.0
3 5.0 2.0 1.0
4 9.2 7.8 4.1
1 2
1 3
4 3

I have just been using getline to go through each line of the file.

Reading first line, number of nodes:

Code: Select all

	// Read in number of nodes
	string input;
	getline(myfile, input);
	int num;
	istringstream str2int(input);
	str2int >> num;
Reading nodes to draw (GraphNode contains id and coordinates of node):

Code: Select all

// Create objects of all nodes in vector, to keep track
	vector<GraphNode> nodes;
	for(int i = 0; i < num; i++)
	{
		string sn, sx, sy, sz;
		getline(myfile, sn, ' ');
		getline(myfile, sx, ' ');
		getline(myfile, sy, ' ');
		getline(myfile, sz);

		// Node name
		int n = 0;
		// Node coordinates
		float x, y, z;
		istringstream str2int(sn);
		istringstream str2float1(sx);
		istringstream str2float2(sy);
		istringstream str2float3(sz);
		str2int >> n;
		str2float1 >> x;
		str2float2 >> y;
		str2float3 >> z;

		// Push node into vector
		nodes.push_back(GraphNode(n, x, y, z));
	}
And for the relationships to draw 3D lines:

Code: Select all

// Create relationships by searching through vector
	struct pair_of_id
	{
		int id1, id2;
	};

	core::array<pair_of_id> ids;

	while(!myfile.eof())
	{
		pair_of_id pid;
		string p1, p2;
		getline(myfile, p1, ' ');
		getline(myfile, p2);
		istringstream str2int1(p1);
		istringstream str2int2(p2);
		str2int1 >> pid.id1;
		str2int2 >> pid.id2;
		ids.push_back(pid);
	}
I am fairly new to C++ so I chose the first thing I could find which was istringstream. If you could post a more efficient way or another library to look at, that would be great. Thanks.
vitek
Bug Slayer
Posts: 3919
Joined: Mon Jan 16, 2006 10:52 am
Location: Corvallis, OR

Post by vitek »

Code: Select all

// Read in number of nodes 
string input; 
getline(myfile, input); 
int num; 
istringstream str2int(input); 
str2int >> num;
You do not need to parse each space delimited word into a string so you can parse it into a number. The C++ iostreams can do all of the parsing for you. The above code can be reduced down to...

Code: Select all

int num;
myfile >> num;
Same thing for this code...

Code: Select all

vector<GraphNode> nodes; 
for(int i = 0; i < num; i++) 
{ 
   string sn, sx, sy, sz; 
   getline(myfile, sn, ' '); 
   getline(myfile, sx, ' '); 
   getline(myfile, sy, ' '); 
   getline(myfile, sz); 

   // Node name 
   int n = 0; 
   // Node coordinates 
   float x, y, z; 
   istringstream str2int(sn); 
   istringstream str2float1(sx); 
   istringstream str2float2(sy); 
   istringstream str2float3(sz); 
   str2int >> n; 
   str2float1 >> x; 
   str2float2 >> y; 
   str2float3 >> z; 

   // Push node into vector 
   nodes.push_back(GraphNode(n, x, y, z)); 
} 
This could probably be written as...

Code: Select all

vector<GraphNode> nodes; 
nodes.reserve (num);

for (int i = 0; i < num; ++i)
{
  GraphNode node;
  myfile >> node.id
         >> node.x >> node.y >> node.z;
  nodes.push_back(node);
}
Travis
bonsalty
Posts: 120
Joined: Thu Dec 10, 2009 1:30 pm
Location: Budapest,Hungary

Post by bonsalty »

Its always better using customscene nodes, in this case a container class for 3D lines. The good thing with custom scene nodes, you dont have to call it every time when you render it.
Tomi
Ulf
Posts: 281
Joined: Mon Jun 15, 2009 8:53 am
Location: Australia

Post by Ulf »

If you need to set the material before calling draw3DLine to give it a color, then what does the color parameter do?
Because it doesn't seem to make any difference. I seem to need to set a new material each time to change color of line drawing.
I can hear birds chirping
:twisted:

I live in the Eye of Insanity.
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

If you have lighting enabled this might be the case. Otherwise the vertex color will take over, which is set by the parameter.
Ulf
Posts: 281
Joined: Mon Jun 15, 2009 8:53 am
Location: Australia

Post by Ulf »

Thank you. I turned lighting off in the set material. Works fine.
I can hear birds chirping
:twisted:

I live in the Eye of Insanity.
Post Reply