Hi,
I'm drawing country maps with irrlicht, and it's working really nice! I've got many shapefiles with data that I want to draw on those maps, like roads, but I don't know how to do it. I read the lines from the shapefile (.shp), this obviously can't be done inside the main loop.
I wanna have several layers (such as roads, rivers, conservation areas, powerplants, etc), and turn each of them on/off. I thought about drawing them before the program loads, so I can load them as different textures of the same terrain, but new options would increase too much the sets needed (e.g. terrain+road, terrain+river, terrain+road+river), and the lines (of roads, rivers, etc) should be usually thinner than my pixel (which is 1km wide).
If I draw the lines in a bitmap (such as ITexture or IImage, and I don't know how to do this in run time), I guess it would be too much pixelized (except if the bitmap is too big, which is not a convenient option). So the solution gotta be drawing the lines over the scenenode, not the texture, but I didn't realize how.
Can anyone help me please?
drawing lines in terrain
-
- Posts: 24
- Joined: Mon May 25, 2009 2:18 pm
- Location: Brazil
- Contact:
drawing lines in terrain
I feel, therefore I am.
-
- Admin
- Posts: 14143
- Joined: Wed Apr 19, 2006 9:20 pm
- Location: Oldenburg(Oldb), Germany
- Contact:
You can use draw3DLine or even better the EPT_LINES primitive type. With the latter you can put all shape points into one array, build the index list for it, and draw all lines in one go. This will only work for the same sized lines, though, and only for OpenGL (D3D does not support line thickness). Otherwise you'd have to draw thin quads which are aligned with the terrain in a similar fashion.
-
- Posts: 24
- Joined: Mon May 25, 2009 2:18 pm
- Location: Brazil
- Contact:
Thanks hybrid. But what do you mean "same sized lines": same thickness or same length (or anything else)? Here in Brazil it only works with OpenGL, so that wouldn't be a limitation right now (but I want my code to be as portable as possible, so...)
I think the other option is the one (draw thin quads). But it doesn't make sense to create 4 vertices to draw a line (in huge maps with lots of lines this could mess up our limited third-world memory
The draw3Dline sounds good, I've tried them, but didn't work. This is part of the code:
// when it's reading the shapefile (before the main loop, when the terrain is already loaded with altitude and texture, and after certain messages (e.g. after I reload it all for another country))
v1.X = P1.X;
v1.Z = P1.Y;
v1.Y = terrain->getHeight(P1.X,P1.Y);
v2.X = P2.X;
v2.Z = P2.Y;
v2.Y = terrain->getHeight(P2.X,P2.Y);
driver->draw3DLine(v1,v2,cor);
// that's it?
I think maybe I should use this, but I don't have any idea how:
// If you need access to the terrain data you can also do this directly via the following code fragment.
scene::CDynamicMeshBuffer* buffer = new scene::CDynamicMeshBuffer(video::EVT_2TCOORDS, video::EIT_16BIT);
terrain->getMeshBufferForLOD(*buffer, 0);
video::S3DVertex2TCoords* data = (video::S3DVertex2TCoords*)buffer->getVertexBuffer().getData();
// Work on data or get the IndexBuffer with a similar call.
buffer->drop(); // When done drop the buffer again.
Thanks again for any help.
Oh yeah, you can download my project here (it's working):
http://voxel.dl.sourceforge.net/sourcef ... n/SN3d.zip
or enter sourceforge to change mirror site. Look for release SN-0.4. (SN-0.3 has a lot more of information, but all in 2d).
I think the other option is the one (draw thin quads). But it doesn't make sense to create 4 vertices to draw a line (in huge maps with lots of lines this could mess up our limited third-world memory
The draw3Dline sounds good, I've tried them, but didn't work. This is part of the code:
// when it's reading the shapefile (before the main loop, when the terrain is already loaded with altitude and texture, and after certain messages (e.g. after I reload it all for another country))
v1.X = P1.X;
v1.Z = P1.Y;
v1.Y = terrain->getHeight(P1.X,P1.Y);
v2.X = P2.X;
v2.Z = P2.Y;
v2.Y = terrain->getHeight(P2.X,P2.Y);
driver->draw3DLine(v1,v2,cor);
// that's it?
I think maybe I should use this, but I don't have any idea how:
// If you need access to the terrain data you can also do this directly via the following code fragment.
scene::CDynamicMeshBuffer* buffer = new scene::CDynamicMeshBuffer(video::EVT_2TCOORDS, video::EIT_16BIT);
terrain->getMeshBufferForLOD(*buffer, 0);
video::S3DVertex2TCoords* data = (video::S3DVertex2TCoords*)buffer->getVertexBuffer().getData();
// Work on data or get the IndexBuffer with a similar call.
buffer->drop(); // When done drop the buffer again.
Thanks again for any help.
Oh yeah, you can download my project here (it's working):
http://voxel.dl.sourceforge.net/sourcef ... n/SN3d.zip
or enter sourceforge to change mirror site. Look for release SN-0.4. (SN-0.3 has a lot more of information, but all in 2d).
I feel, therefore I am.
-
- Admin
- Posts: 14143
- Joined: Wed Apr 19, 2006 9:20 pm
- Location: Oldenburg(Oldb), Germany
- Contact:
The line rendering in OpenGL is not the fastest on all machines, so don't expect too good performance with single call line rendering. For the EPT_LINES you need to group same thickness, because the Material will only contain one thickness per array. Then performance would be much better with a large batch of lines drawn at once. Depending on the card a quad per line can be even better, because most low-end cards have very poor line rendering. Moreover, you have more flexibility with that. And with VBOs the extra two points won't hurt too much.
-
- Posts: 24
- Joined: Mon May 25, 2009 2:18 pm
- Location: Brazil
- Contact:
Thanks for the information, hybrid. I'm basing myself in the example 3 (from the tutorial), I already got the tetraeder to appear together with my map.
"With the latter you can put all shape points into one array, build the index list for it, and draw all lines in one go."
How do I build the index list? I did:
typedef video::S3DVertex TQuad [4];
TQuad Vertice;
vector<TQuad> Quad;
driver->drawIndexedTriangleList(&Vertice[0], 4, &indices[0], 4);
in the example 3, Vertice was a array of 4 S3DVertex. How it will change here? I didn't quite understand. An example would be really nice.
Another one: can I do a single bounding box for each bunch of same-width lines/quads? Or should I do one for each quad?
Thanks again.
"With the latter you can put all shape points into one array, build the index list for it, and draw all lines in one go."
How do I build the index list? I did:
typedef video::S3DVertex TQuad [4];
TQuad Vertice;
vector<TQuad> Quad;
driver->drawIndexedTriangleList(&Vertice[0], 4, &indices[0], 4);
in the example 3, Vertice was a array of 4 S3DVertex. How it will change here? I didn't quite understand. An example would be really nice.
Another one: can I do a single bounding box for each bunch of same-width lines/quads? Or should I do one for each quad?
Thanks again.
I feel, therefore I am.
-
- Admin
- Posts: 14143
- Joined: Wed Apr 19, 2006 9:20 pm
- Location: Oldenburg(Oldb), Germany
- Contact:
A bounding box is attached to each meshbuffer, so just do this for as few meshbuffers as possible.
I think you want to call &Quad[0] instead of &Vertice[0]. The full call would be driver->drawIndexedTriangleList(&Quad[0], 4*Quad.size(), &indices[0], indices.size());
indices is a vector of s16, where every 6 indices make up one quad. Since you will reuse the last two points of each quad you can make the indices like this:
0,1,3, 0,3,2,
2,3,5, 2,5,4, etc.
I think you want to call &Quad[0] instead of &Vertice[0]. The full call would be driver->drawIndexedTriangleList(&Quad[0], 4*Quad.size(), &indices[0], indices.size());
indices is a vector of s16, where every 6 indices make up one quad. Since you will reuse the last two points of each quad you can make the indices like this:
0,1,3, 0,3,2,
2,3,5, 2,5,4, etc.
-
- Posts: 24
- Joined: Mon May 25, 2009 2:18 pm
- Location: Brazil
- Contact:
Well, now I think I understand what the indices do (they do 2 triangles to form a rectangle, that will be my line, right?).
I tried with
typedef video::S3DVertex TQuad[4];
but this array didn't work. Now I'm putting all the vertex together in one vector (Quad).
// by the way, in my version of irrlicht (1.5), indices are u16.
vector<u16> indices;
video::S3DVertex Q;
vector<video::S3DVertex> Quad;
video::SColor cor = video::SColor(128,128,128,128);
// 1,1,1 below is the direction of physics normal reaction force? I want to draw the lines ON the texture - does the normal matter here?
Q = video::S3DVertex(v1.X,v1.Y,v1.Z, 1,1,1,cor, 0, 1); // and what do the varying last two parameters mean?
Quad.push_back(Q);
Q = video::S3DVertex(v1.X,v1.Y,v1.Z, 1,0,0,cor, 1, 1); Quad.push_back(Q);
Q = video::S3DVertex(v2.X,v2.Y,v2.Z, 0,1,1,cor, 1, 0); Quad.push_back(Q);
Q = video::S3DVertex(v2.X,v2.Y,v2.Z, 0,0,1,cor, 0, 0); Quad.push_back(Q);
indices.push_back(k*2-2); //k is the number of the point (from the shapefile, a "curve" in the road)
indices.push_back(k*2-1);
indices.push_back(k*2+1);
indices.push_back(k*2-2);
indices.push_back(k*2+1);
indices.push_back(k*2);
driver->setMaterial(material); // for a black or gray line I don't know if I need this?
driver->setTransform(video::ETS_WORLD, AbsoluteTransformation); // no idea what this does
driver->drawIndexedTriangleList(&Quad[0], Quad.size(), &indices[0], indices.size()); // HERE IT CRASHES. ANY IDEA WHY?
I tried with
typedef video::S3DVertex TQuad[4];
but this array didn't work. Now I'm putting all the vertex together in one vector (Quad).
// by the way, in my version of irrlicht (1.5), indices are u16.
vector<u16> indices;
video::S3DVertex Q;
vector<video::S3DVertex> Quad;
video::SColor cor = video::SColor(128,128,128,128);
// 1,1,1 below is the direction of physics normal reaction force? I want to draw the lines ON the texture - does the normal matter here?
Q = video::S3DVertex(v1.X,v1.Y,v1.Z, 1,1,1,cor, 0, 1); // and what do the varying last two parameters mean?
Quad.push_back(Q);
Q = video::S3DVertex(v1.X,v1.Y,v1.Z, 1,0,0,cor, 1, 1); Quad.push_back(Q);
Q = video::S3DVertex(v2.X,v2.Y,v2.Z, 0,1,1,cor, 1, 0); Quad.push_back(Q);
Q = video::S3DVertex(v2.X,v2.Y,v2.Z, 0,0,1,cor, 0, 0); Quad.push_back(Q);
indices.push_back(k*2-2); //k is the number of the point (from the shapefile, a "curve" in the road)
indices.push_back(k*2-1);
indices.push_back(k*2+1);
indices.push_back(k*2-2);
indices.push_back(k*2+1);
indices.push_back(k*2);
driver->setMaterial(material); // for a black or gray line I don't know if I need this?
driver->setTransform(video::ETS_WORLD, AbsoluteTransformation); // no idea what this does
driver->drawIndexedTriangleList(&Quad[0], Quad.size(), &indices[0], indices.size()); // HERE IT CRASHES. ANY IDEA WHY?
I feel, therefore I am.
-
- Posts: 24
- Joined: Mon May 25, 2009 2:18 pm
- Location: Brazil
- Contact:
Hey, hybrid, thanks a lot! It worked fine, or almost: the lines are not "attached" to the terrain. Look the screenshot:
The red lines are the roads. Some of them float much above the terrain, others much below it.
My code is:
P = Points[k]; // one of the road points (inside a for-loop)
v.X = dimPais.Width-P.X; // the long axis is inverted (why? no idea)
v.Z = P.Y; // the lat axis
v.Y = terrain->getHeight(v.X,v.Z)+1; // altitude. +1 was meant to put lines on "top" of terrain
Q = video::S3DVertex(v.X*ScaleH*dimPais.Width/dimPais.Height,v.Y*ScaleV,v.Z*ScaleH*dimPais.Width/dimPais.Height,1,1,1,cor,1,1);
// The map is scaled, see other question about it
rquad.push_back(Q);
// Finally, just before driver->endScene()
driver->setTransform(video::ETS_WORLD, identity);
driver->drawVertexPrimitiveList(&rquad[0], rquad.size(), &rind[0], u32(rind.size()/2), video::EVT_STANDARD, scene::EPT_LINES, video::EIT_16BIT);
I think it may be in the driver->setTransform function, but I've seen some examples that called it with identity not initialized (like I did)
Here is another example:
And here the working image in my 2D project:
(I'm gonna complete this question with another one about scaling texture and altitude)
The red lines are the roads. Some of them float much above the terrain, others much below it.
My code is:
P = Points[k]; // one of the road points (inside a for-loop)
v.X = dimPais.Width-P.X; // the long axis is inverted (why? no idea)
v.Z = P.Y; // the lat axis
v.Y = terrain->getHeight(v.X,v.Z)+1; // altitude. +1 was meant to put lines on "top" of terrain
Q = video::S3DVertex(v.X*ScaleH*dimPais.Width/dimPais.Height,v.Y*ScaleV,v.Z*ScaleH*dimPais.Width/dimPais.Height,1,1,1,cor,1,1);
// The map is scaled, see other question about it
rquad.push_back(Q);
// Finally, just before driver->endScene()
driver->setTransform(video::ETS_WORLD, identity);
driver->drawVertexPrimitiveList(&rquad[0], rquad.size(), &rind[0], u32(rind.size()/2), video::EVT_STANDARD, scene::EPT_LINES, video::EIT_16BIT);
I think it may be in the driver->setTransform function, but I've seen some examples that called it with identity not initialized (like I did)
Here is another example:
And here the working image in my 2D project:
(I'm gonna complete this question with another one about scaling texture and altitude)
I feel, therefore I am.