Using Splines in Ogre creating a manual mesh
-
- Halfling
- Posts: 79
- Joined: Mon Feb 20, 2006 2:08 am
- Location: CMU, Pittsburgh PA
- Contact:
Using Splines in Ogre creating a manual mesh
So, basically what I want to do is to automatically create a road mesh given information like the center points, how many lanes it is, and what type of road (dirt, highway, etc.).
I've found several places online that allude to using splines to create a smooth element to these roads (going from 4 lanes to 2 lanes without extra "artistic" work, etc).
Is it possible to use Splines while creating a manual mesh in Ogre?
Nate
I've found several places online that allude to using splines to create a smooth element to these roads (going from 4 lanes to 2 lanes without extra "artistic" work, etc).
Is it possible to use Splines while creating a manual mesh in Ogre?
Nate
-
- Halfling
- Posts: 62
- Joined: Mon Feb 07, 2005 9:47 pm
-
- Halfling
- Posts: 79
- Joined: Mon Feb 20, 2006 2:08 am
- Location: CMU, Pittsburgh PA
- Contact:
Here's what I'm thinking for now:
I have splines, using Ogre::SimpleSpline, that run down the road and alongside each segment of the road. I say segment, because I'm using a database that breaks up curves into segments for "compression" purposes.
Then so far down each spline I can call Vector3 Ogre::SimpleSpline::interpolate(Real t) to get the next set points to add to the mesh.
There is a sample code that creates a cube with just vertex information:
http://www.ogre3d.org/wiki/index.php/GeneratingAMesh
So, I think I'll head in that direction if others think it will work.
I have splines, using Ogre::SimpleSpline, that run down the road and alongside each segment of the road. I say segment, because I'm using a database that breaks up curves into segments for "compression" purposes.
Then so far down each spline I can call Vector3 Ogre::SimpleSpline::interpolate(Real t) to get the next set points to add to the mesh.
There is a sample code that creates a cube with just vertex information:
http://www.ogre3d.org/wiki/index.php/GeneratingAMesh
So, I think I'll head in that direction if others think it will work.
-
- Halfling
- Posts: 79
- Joined: Mon Feb 20, 2006 2:08 am
- Location: CMU, Pittsburgh PA
- Contact:
Using this tutorial as a guidline: http://www.ogre3d.org/wiki/index.php/GeneratingAMesh
When specifying how the triangles layout, does the order of the verticies matter? Or will one way make them face down and the other upward? If so, is it counter-clockwise or clockwise that gives the front face?
Additionally, once I create each mesh like this, how would I go about texturing the mesh? Is it even possible if it has a lot of flexibility to its shape?
Thanks Again.
When specifying how the triangles layout, does the order of the verticies matter? Or will one way make them face down and the other upward? If so, is it counter-clockwise or clockwise that gives the front face?
Additionally, once I create each mesh like this, how would I go about texturing the mesh? Is it even possible if it has a lot of flexibility to its shape?
Thanks Again.
-
- Halfling
- Posts: 79
- Joined: Mon Feb 20, 2006 2:08 am
- Location: CMU, Pittsburgh PA
- Contact:
So you can see here that I've gotten it to work.
However, I'm unsure of how to texture map the road now. I'd prefer to be able to map it just like you would find a road in real life, but I'm not sure how to go about mapping this.
I used the generating a mesh code, and currently it only supports changing the colors (which isn't what I'm looking for)...
Any suggestions are very welcome.
Thanks.
However, I'm unsure of how to texture map the road now. I'd prefer to be able to map it just like you would find a road in real life, but I'm not sure how to go about mapping this.
I used the generating a mesh code, and currently it only supports changing the colors (which isn't what I'm looking for)...
Any suggestions are very welcome.
Thanks.
Last edited by gzmzhen on Sat Aug 19, 2006 9:58 pm, edited 1 time in total.
-
- OGRE Expert User
- Posts: 421
- Joined: Fri Jan 07, 2005 9:49 pm
- Location: UK
- x 2
- Contact:
One possibility is to create a texture, tileable in the v direction per instance.
Then you assign a u coordinate of 0.0 and 1.0 for respectivly the left and right side of the road, and a v coordinate depending of the position in the spline.
Per instance, with a position in the spline for 0.0 to 1.0, you can do something like v = position * x; where x is the number of time you want your texture to repeat on the whole spline length.
Notice that u and v coordinates, aren't necessary between 0.0 and 1.0, a greater number will make it repeat, if you use the correct texture addressing mode (material parameter), which is on repeat by default
Then you assign a u coordinate of 0.0 and 1.0 for respectivly the left and right side of the road, and a v coordinate depending of the position in the spline.
Per instance, with a position in the spline for 0.0 to 1.0, you can do something like v = position * x; where x is the number of time you want your texture to repeat on the whole spline length.
Notice that u and v coordinates, aren't necessary between 0.0 and 1.0, a greater number will make it repeat, if you use the correct texture addressing mode (material parameter), which is on repeat by default
-
- Halfling
- Posts: 79
- Joined: Mon Feb 20, 2006 2:08 am
- Location: CMU, Pittsburgh PA
- Contact:
Ok, P - I like that idea. In fact, I think it will work very well.
However, I have no idea where I'd add u,v coordinate stuff inside of the "GeneratingAMesh" code. (see http://www.ogre3d.org/wiki/index.php/GeneratingAMesh)
I'm guessing I'd add it as an additional buffer. For instance, I simply removed the code for the 2nd buffer to get rid of just being able to define colors for each vertex.
However, I'm extremely lost as to where to go from here since this code doesn't really say where it came from. I'll check out the API after I get my current goal accomplished.
However, I have no idea where I'd add u,v coordinate stuff inside of the "GeneratingAMesh" code. (see http://www.ogre3d.org/wiki/index.php/GeneratingAMesh)
I'm guessing I'd add it as an additional buffer. For instance, I simply removed the code for the 2nd buffer to get rid of just being able to define colors for each vertex.
However, I'm extremely lost as to where to go from here since this code doesn't really say where it came from. I'll check out the API after I get my current goal accomplished.
-
- Halfling
- Posts: 79
- Joined: Mon Feb 20, 2006 2:08 am
- Location: CMU, Pittsburgh PA
- Contact:
Here seems to be a solution to my problem:
Started here: http://www.ogre3d.org/phpBB2/viewtopic.php?t=23332
Actual solution here: http://www.ogre3d.org/phpBB2/viewtopic.php?t=23360&
This clearly states that I'll bind them to another channel.
Started here: http://www.ogre3d.org/phpBB2/viewtopic.php?t=23332
Actual solution here: http://www.ogre3d.org/phpBB2/viewtopic.php?t=23360&
This clearly states that I'll bind them to another channel.
-
- Halfling
- Posts: 79
- Joined: Mon Feb 20, 2006 2:08 am
- Location: CMU, Pittsburgh PA
- Contact:
Thank you very much P. That has worked extremely well. Now that I've finally got a bunch of things working together I'll post a shot of the benefits of using a spline. This road has 5 total control pts, and the rest is made automatically.
Future plans include widening that road, creating pebble like valleys to the side of the road (you know the rocks on the sides of roads) and to make the road a bit wider along with a slightly more realistic texture.
Againt P, I can't thank you enough.
Future plans include widening that road, creating pebble like valleys to the side of the road (you know the rocks on the sides of roads) and to make the road a bit wider along with a slightly more realistic texture.
Againt P, I can't thank you enough.
Last edited by gzmzhen on Mon Sep 11, 2006 12:19 am, edited 1 time in total.
- stoneCold
- OGRE Expert User
- Posts: 867
- Joined: Fri Oct 01, 2004 9:13 pm
- Location: Carinthia, Austria
- x 1
The solution is today still the same (except you could use ManualObject, which is easier to handle).ChrisKing wrote:Nice road there.
How did you achieve the seamless texture at the blend? is it a tiled road too?
i read P's solution but i still don't understand how the v=position*x could achieve the seamless effect.
Just create the mesh along the spline...
Code: Select all
ManualObject::position(Ogre::SimpleSpline::interpolate(Real t))
and at the ManualObject you do...
Code: Select all
ManualObject::texcoord(0.0, t * x) //left side vertex of road
ManualObject::texcoord(1.0, t * x) //right side vertex of road
greetings
-
- Halfling
- Posts: 79
- Joined: Mon Feb 20, 2006 2:08 am
- Location: CMU, Pittsburgh PA
- Contact:
-
- Kobold
- Posts: 33
- Joined: Sun Jan 21, 2007 7:24 pm
Hi gzmzhen!
Now, I think that this approach solves part of the problem. Although I haven't followed it through in detail I can see how I could create a street including elevated sidewalks.
I see one problem though that I already encountered when creating streets on an even terrain. What I did and to my understanding it's the same for the approach presented in the other thread, is creating co-planar surfaces for the road with respect to the terrain (the surface of the road is on top of the surface for the terrain). And when you are high above the terrain you get graphics artifacts because (as I understand it) the arithmetic precision of the numbers representing the mesh is insufficient to distinguish the two planes. So my guess was that you would somehow have to construct a single mesh, maybe by cutting out the terrain underneath the road or not constructing it in the first place.
As you might have gathered I'm not a modelling pro In any case I'd be happy to learn how it's done.
Markus
Now, I think that this approach solves part of the problem. Although I haven't followed it through in detail I can see how I could create a street including elevated sidewalks.
I see one problem though that I already encountered when creating streets on an even terrain. What I did and to my understanding it's the same for the approach presented in the other thread, is creating co-planar surfaces for the road with respect to the terrain (the surface of the road is on top of the surface for the terrain). And when you are high above the terrain you get graphics artifacts because (as I understand it) the arithmetic precision of the numbers representing the mesh is insufficient to distinguish the two planes. So my guess was that you would somehow have to construct a single mesh, maybe by cutting out the terrain underneath the road or not constructing it in the first place.
As you might have gathered I'm not a modelling pro In any case I'd be happy to learn how it's done.
Markus
-
- Kobold
- Posts: 30
- Joined: Tue Jan 16, 2007 4:16 am
stoneCold
Say if the tile texture example side white lines you gave is changed to broken white lines then it would not be a tile able (for bends) anymore? Definitely it will still work for straight roads.
something like this:
- - - - - - - - - - -
==========
- - - - - - - - - - -
If i am not wrong the solution using Ogre::SimpleSpline::interpolate is the same as this ?
http://www.freeworld3d.org/tutorials/roadsystem.html
Say if the tile texture example side white lines you gave is changed to broken white lines then it would not be a tile able (for bends) anymore? Definitely it will still work for straight roads.
something like this:
- - - - - - - - - - -
==========
- - - - - - - - - - -
If i am not wrong the solution using Ogre::SimpleSpline::interpolate is the same as this ?
http://www.freeworld3d.org/tutorials/roadsystem.html
-
- Halfling
- Posts: 79
- Joined: Mon Feb 20, 2006 2:08 am
- Location: CMU, Pittsburgh PA
- Contact:
ChrisKing:
So the texturing is not done by "tiling" per se, but rather the coefficient along the road has to deal with the length of the road from one point to the next. For example, I have pt1 and pt2 where pt2 comes after pt1. I can find the distance between the two simply by doing (pt2-pt1).length() and then use that times some scaling factor that scales the texture per distance.
This effectively makes bends look just fine.
The freeworld page you pointed to, is very similar to the method (that I felt was originally) created using the simpleSpline.
Markus,
So, the problem that you're having is (apparently) known as z-fighting. This doesn't occur on all graphics cards. For example, my ATI card at home does not have this problem at all, but my laptop, and work computers have this problem using the NVIDIA GeForce 7900 card.
If you find a solution that gets rid of this without destroying the underlying terrain mesh, sharing it with us would be great =).
One last thing, if you're thinking about implementing something like this keep in mind how you want to create road intersections... it is really a very tough problem to fix and our solution is quite sub-optimal. It uses a little computational geometry to create a clockwise ordering of the points on the ends of the roads at a particular intersection.
Note that my solution is using a road database to put things together, which allows us to have a dynamic road setup at any given execution of the program. So it is essential that we make intersections automatically as well.
Nate
So the texturing is not done by "tiling" per se, but rather the coefficient along the road has to deal with the length of the road from one point to the next. For example, I have pt1 and pt2 where pt2 comes after pt1. I can find the distance between the two simply by doing (pt2-pt1).length() and then use that times some scaling factor that scales the texture per distance.
This effectively makes bends look just fine.
The freeworld page you pointed to, is very similar to the method (that I felt was originally) created using the simpleSpline.
Markus,
So, the problem that you're having is (apparently) known as z-fighting. This doesn't occur on all graphics cards. For example, my ATI card at home does not have this problem at all, but my laptop, and work computers have this problem using the NVIDIA GeForce 7900 card.
If you find a solution that gets rid of this without destroying the underlying terrain mesh, sharing it with us would be great =).
One last thing, if you're thinking about implementing something like this keep in mind how you want to create road intersections... it is really a very tough problem to fix and our solution is quite sub-optimal. It uses a little computational geometry to create a clockwise ordering of the points on the ends of the roads at a particular intersection.
Note that my solution is using a road database to put things together, which allows us to have a dynamic road setup at any given execution of the program. So it is essential that we make intersections automatically as well.
Nate
-
- Goblin
- Posts: 217
- Joined: Thu Oct 24, 2002 4:12 am
- x 1
- Contact:
-
- Halfling
- Posts: 79
- Joined: Mon Feb 20, 2006 2:08 am
- Location: CMU, Pittsburgh PA
- Contact:
I actually took real height information from a NASA database... and then had to write my own version of a terrain manager. Unfortunately, the data was simply a raw file and didn't work with ogreNewt when I first tried to get it to work with any of the normal scene managers (terrain scene manager or the paging scene manager). I'm not sure if this would still be the case if you decided to use one of them.
The lat/long values are aligned by both the tigerDB (road information) and from the Nasa data that was cropped from their databases. (if I find the link to it I'll post it... but just do a little searching if you want to use specific data).
The lat/long values are aligned by both the tigerDB (road information) and from the Nasa data that was cropped from their databases. (if I find the link to it I'll post it... but just do a little searching if you want to use specific data).
-
- Halfling
- Posts: 79
- Joined: Mon Feb 20, 2006 2:08 am
- Location: CMU, Pittsburgh PA
- Contact:
It looks like the code I have already written is somewhat deprecated because of the new ManualObject item. I'll have to look into upgrading it - if I do so successfully I don't mind writing a wiki on it. I'll have to spend some time this weekend looking into it - I'm rather busy with classes until then.
Nate
Nate
-
- Halfling
- Posts: 79
- Joined: Mon Feb 20, 2006 2:08 am
- Location: CMU, Pittsburgh PA
- Contact:
So, I've finally upgraded the code to use Manual Mesh. However, I've not had time yet to put it on to the wiki. I think it would be nice to actually show where the calculations come from, and to describe what a user needs to do to get such code to work properly on their system.
Ultimately though, I'll post the code now. The code takes in the backbone spline, an OgreNewt World object (could be commented out) and the name of the road object (in case you plan on using more than one road). The function returns the actual vertices of the end-pts (for the purpose of making intersections later).
It works best if the ratio of distance between any two points on the spline is close to 1. The closer the better. There are quite a few constants defined in the code that worked for me, but may not work for you - so do fool around with them.
I tried to comment my code, but until I can make a wiki (maybe your questions will help me create it) please do post your questions and I will answer them as quickly as I can.
I hope you enjoy =),
Nate Bauernfeind
Ultimately though, I'll post the code now. The code takes in the backbone spline, an OgreNewt World object (could be commented out) and the name of the road object (in case you plan on using more than one road). The function returns the actual vertices of the end-pts (for the purpose of making intersections later).
It works best if the ratio of distance between any two points on the spline is close to 1. The closer the better. There are quite a few constants defined in the code that worked for me, but may not work for you - so do fool around with them.
I tried to comment my code, but until I can make a wiki (maybe your questions will help me create it) please do post your questions and I will answer them as quickly as I can.
I hope you enjoy =),
Nate Bauernfeind
Code: Select all
float** MeshBuilder::createRoadMesh(SimpleSpline &backbone, OgreNewt::World *mWorld, String rName)
{
Ogre::ManualObject currRoad(rName + "obj");
currRoad.begin("DrivingSim/RoadMat");
// Road "Constants"
Real roadWidth = 7.5; // m
Real roadHeight = 0.3; // m
Real averageDistPerSection = 15.0;
int numRoadPiecesThisSegment;
// TempRoad attributes
Real dist;
int numRoadPiecesTtl;
// for keeping track of the sides
Vector3 lrVector;
Vector3 vertex;
Vector3 lastPt;
Real t; // for interpolation
// save some time from all of the calls to backbone
int numPoints;
int numHorizontalPts = 5;
int n, vertexOffset;
// To add the mesh to the scene.
Entity* rdEntity;
SceneNode* rdSceneNode;
OgreNewt::CollisionPrimitives::TreeCollision *treeCol;
// to create intersections we need this info
float **retVertices = new float*[2];
retVertices[0] = new float[numHorizontalPts*3];
retVertices[1] = new float[numHorizontalPts*3];
// Gets the Road node if it's already there.
try {
rdSceneNode = mSceneMgr->getSceneNode("RoadNode");
}
catch(Ogre::Exception e)
{
rdSceneNode = mSceneMgr->getRootSceneNode()->createChildSceneNode("RoadNode");
}
// check here if we can load it from saved cache / prebuilt
// Define the vertices
numPoints = backbone.getNumPoints();
// we need to count the number of segments totally
numRoadPiecesTtl = -2; // minus first two and last (intersections)
for (int i = 0; i < numPoints-1; i++)
{
dist = (backbone.getPoint(i+1) - backbone.getPoint(i)).length();
numRoadPiecesThisSegment = dist/averageDistPerSection;
if (numRoadPiecesThisSegment == 0) numRoadPiecesThisSegment++;
numRoadPiecesTtl += numRoadPiecesThisSegment;
}
if (numRoadPiecesTtl <= 0)
{
delete[] retVertices[0];
delete[] retVertices[1];
delete[] retVertices;
return NULL;
}
float vCoord = 0;
Vector3 uvOldPt = backbone.interpolate(0,0);
Vector3 uvNewPt;
Vector3 pos, front;
int cnt=0;
Real uCoord[5] = {0,0.03125,0.5,1-0.03125,1};
Real lrVectorMultiplier[5] = {roadWidth*1.45, roadWidth, 0, -roadWidth, -roadWidth*1.45};
Real currHeight;
Vector3 currVertices[5];
// for some reason the first section may only have 1 segment... in this case we need to have lastPt defined
lastPt = backbone.interpolate(0,0.0);
for (int i = 0; i < numPoints-1; i++)
{
dist = (backbone.getPoint(i+1) - backbone.getPoint(i)).length();
numRoadPiecesThisSegment = dist/averageDistPerSection;
if (numRoadPiecesThisSegment == 0) numRoadPiecesThisSegment++;
if (i == 0)
n = 1;
else
n = 0;
// Ogre::LogManager::getSingleton().logMessage("numRoadPiecesThisSeg = " + Ogre::StringConverter::toString(numRoadPiecesThisSegment));
for (; n < numRoadPiecesThisSegment; n++)
{
t = (Real) n / (Real) (numRoadPiecesThisSegment);
uvNewPt = backbone.interpolate(i,t);
vCoord += (uvNewPt-uvOldPt).length()/mTerrainMesh->getTextureRepeat();
uvOldPt = uvNewPt;
// Ogre::LogManager::getSingleton().logMessage("Spline Pt: " + Ogre::StringConverter::toString(uvNewPt));
// create vertices from just the backbone spline
// move left or right
// calc lrVector
vertex = backbone.interpolate(i,t); // vertex is being used as a temporary variable
currHeight = mTerrainMesh->getHeight(vertex);
lastPt.y = vertex.y = 0;
// positive is left vector
front = (vertex-lastPt);
lrVector = front.crossProduct(Vector3::UNIT_Y);
lrVector.normalise();
// end of lrVector calculation
for (int j = 0; j < numHorizontalPts; j++)
{
// create this side piece
currVertices[j] = vertex;
currVertices[j] += lrVector*lrVectorMultiplier[j];
// update height
currVertices[j].y = mTerrainMesh->getHeight(currVertices[j]);
if (currVertices[j].y > currHeight && j != 0 && j != numHorizontalPts-1)
currHeight = currVertices[j].y;
}
for (int j = 1; j < numHorizontalPts-1; j++)
currVertices[j].y = currHeight + roadHeight;
lastPt = currVertices[2];
// finally add vertices
for (int j = 0; j < numHorizontalPts; j++)
{
// get vertex from created values
currRoad.position(currVertices[j]);
currRoad.textureCoord(uCoord[j], vCoord);
if (cnt < 1)
{
retVertices[0][j*3] = currVertices[j].x;
retVertices[0][j*3+1] = currVertices[j].y;
retVertices[0][j*3+2] = currVertices[j].z;
}
else if (cnt >= numRoadPiecesTtl)
{
int k = numHorizontalPts-j-1;
retVertices[1][k*3] = currVertices[j].x;
retVertices[1][k*3+1] = currVertices[j].y;
retVertices[1][k*3+2] = currVertices[j].z;
}
}
/*
if (cnt < 1)
Ogre::LogManager::getSingleton().logMessage("retVertices[0] set");
else if (cnt >= numRoadPiecesTtl)
Ogre::LogManager::getSingleton().logMessage("retVertices[1] set");
*/
cnt++;
} // loop on n
}
for (n = 0; n < numRoadPiecesTtl; n++)
{
// create four: 0,1,4 0,4,3 1,2,5 1,5,4 (0->6 + offset)
for (vertexOffset = n*numHorizontalPts; vertexOffset < (n+1)*numHorizontalPts-1; vertexOffset++) // vertexOffset
{
unsigned short face[3*2] = {vertexOffset + 0,vertexOffset + numHorizontalPts+1, vertexOffset + 1,
vertexOffset + 0,vertexOffset + numHorizontalPts,vertexOffset + numHorizontalPts+1};
for (int j=0; j<6; j++)
currRoad.index(face[j]);
}
}
currRoad.end();
currRoad.convertToMesh(rName+"Mesh");
// add mesh to scene
rdEntity = mSceneMgr->createEntity(rName + "Ent", rName + "Mesh");
rdEntity->setQueryFlags( ROAD_MASK );
rdSceneNode = rdSceneNode->createChildSceneNode();
rdSceneNode->attachObject(rdEntity);
// ogreNewt
treeCol = new OgreNewt::CollisionPrimitives::TreeCollision(mWorld, rdSceneNode, false);
OgreNewt::Body* body = new OgreNewt::Body(mWorld, treeCol);
delete treeCol;
body->attachToNode(rdSceneNode);
body->setPositionOrientation(rdSceneNode->getPosition(), rdSceneNode->getOrientation());
return retVertices;
}
-
- Halfling
- Posts: 79
- Joined: Mon Feb 20, 2006 2:08 am
- Location: CMU, Pittsburgh PA
- Contact:
- jacmoe
- OGRE Retired Moderator
- Posts: 20570
- Joined: Thu Jan 22, 2004 10:13 am
- Location: Denmark
- x 179
- Contact:
Nice!
This begs to be Wiki'ed!
This begs to be Wiki'ed!
/* Less noise. More signal. */
Ogitor Scenebuilder - powered by Ogre, presented by Qt, fueled by Passion.
OgreAddons - the Ogre code suppository.
Ogitor Scenebuilder - powered by Ogre, presented by Qt, fueled by Passion.
OgreAddons - the Ogre code suppository.