Game Development Community

Procedural road object (help?)

by Dan Keller · in Torque Game Engine · 03/18/2008 (2:30 pm) · 62 replies

I made an object that automatically renders a curved road from a path. Well, it's more of a proof of concept, but it works fairly well. I'm having two problems, though:
*it ignores fog when rendering and sometimes doesn't render at all
*I have absolutely no idea how to get collision working.

Both of these are areas of the engine I know very little about. So here are the files. Can anyone help me on this?

fxRoad.h
fxRoad.cc
And yes, I know the object is re-calculated every frame, that's temporary.

Oh and thanks to Melv May for the fxRenderObject code that this is based on.

66.49.245.246/road.jpg
#21
04/22/2008 (5:40 pm)
If i were working on this my first order of business would be to clean things up.

First generate the geometry for the road in manageable road sections... say no less than 100 meters in length at a time... and store it along with its bounding box. Don't regen it every frame.

You can then use that to setup static VBs for rendering and generate the Opcode::MeshInterface for each road section.

After all than then go implement castRay() and buildPolyList() to make collision work.

Honestly i think its just too messy at the moment for someone to be able to jump in and make anything work.
#22
04/22/2008 (7:42 pm)
Well, it's just a proof of concept right now; I'll clean it up once it actually works.

And Ron, thanks for the rendering code, I was wondering why there was no texture :)
#23
04/22/2008 (8:01 pm)
NP Dan. All I ask is you share this once you get it working. I would love to use this. If you need help with the polysoup integration let me know.
#24
05/05/2008 (6:24 pm)
Dan, did you get this to actually work with my rendering code? If so do you have a test map I could look at to see what I may have done wrong in setting this up?
#25
05/20/2008 (2:50 pm)
Hey Dan any new word on this?
#26
05/21/2008 (10:19 am)
I still can't get it to work.
#27
05/21/2008 (2:40 pm)
Ok is it not visible? No collision? Since I don't have a map that worked before to see if I properly implemented it, I couldn't tell if it was me or the code.

I am more than willing to help out on this, just let me know what is wrong, or even better, send me a map that should have something visible in it.
#28
11/15/2008 (12:40 pm)
Dan if you are still tracking this, email me at my profile's public email about this. I have gotten the roads to work in TGEA with only a couple of things to do and I would like to send you the copy.

1. I am experiencing flicker with the roads, no idea why just yet.

2. Adding collision. This should be fairly simple for either Polysoup or PhysX.
#29
11/15/2008 (3:50 pm)
You know what? Anyone that wants a copy of my version just email me and I will send them to you with one stipulation, if you fix those two things above, you have to share it with me.
#30
11/21/2008 (1:40 am)
As it turns out the flicker is not so much of a flicker as the road disappears at certain camera angles. I am not sure, but this seems to be an issue with visibility culling. However I have the culling set to none using GFX->setCullMode(GFXCullNone); so that makes no sense.

Someone had suggested to me that it could be a bounds issue but during the onAdd function the bounds are set using setGlobalBounds() which should cover that.

Any suggestions on what might cause this?

My rendering code:

bool fxRoad::prepRenderImage(	SceneState* state, const U32 stateKey, const U32, /*startZone*/
										const bool /*modifyBaseZoneState*/)
{
	// Return if last state.
	if (isLastState(state, stateKey)) return false;
	// Set Last State.
	setLastState(state, stateKey);

   // Is Object Rendered?
   if (state->isObjectRendered(this))
   {
	   RenderInst *ri = gRenderInstManager.allocInst();
	   ri->obj = this;
	   ri->state = state;
	   ri->type = RenderInstManager::RIT_Object;
	   ri->translucent = false;
	   gRenderInstManager.addInst(ri);
   }

   return true;
}

//------------------------------------------------------------------------------

void fxRoad::renderObject(SceneState* state, RenderInst*)
{
	if (gEditingMission)
		updateRoad();
	// Calculate Elapsed Time and take new Timestamp.
	S32 Time = Platform::getVirtualMilliseconds();
	F32 ElapsedTime = (Time - mLastRenderTime) * 0.001f;
	mLastRenderTime = Time;

	// Return if we don't have a texture.
	if (!mTextureHandle) return;


	MatrixF proj = GFX->getProjectionMatrix();
	RectI viewport = GFX->getViewport();
	
	MatrixF world = GFX->getWorldMatrix();
	TSMesh::setCamTrans( world );
	TSMesh::setSceneState( state );
	TSMesh::setObject(this);

	state->setupBaseProjection();
	
	GFX->pushWorldMatrix();

	gClientSceneGraph->getLightManager()->sgSetupLights(this);

	GFX->disableShaders();

	// Setup our rendering state (alpha blending).
	GFX->setCullMode(GFXCullNone);

	GFX->setAlphaBlendEnable( true );
	GFX->setAlphaTestEnable( true );
	GFX->setSrcBlend(GFXBlendSrcAlpha);
	GFX->setDestBlend(GFXBlendInvSrcAlpha);	
	GFX->setAlphaFunc(GFXCmpGreater);
	GFX->setAlphaRef(0);
	GFX->setTextureStageColorOp(0, GFXTOPModulate);
    GFX->setTextureStageColorOp(1, GFXTOPDisable);

	GFX->setTexture(0, mTextureHandle);
	
	// Transform by the objects' transform e.g move it.
	GFX->multWorld(getTransform());
	// Set Colour/Alpha.
	PrimBuild::color4f(1,1,1,1);
	
	PrimBuild::begin(GFXTriangleStrip, mNodes.size()*mDetail+4);
	U32 i;
	for (i = 0; i<=arraypt; i++) 
	{
		PrimBuild::texCoord2f(texcs[i].x, texcs[i].y);
		PrimBuild::vertex3f(verts[i].x, verts[i].y, verts[i].z);
	}
	PrimBuild::end();

	if (!mBorderTextureHandle)
		return;

	GFX->setTexture(0, mBorderTextureHandle); //border texture

	PrimBuild::begin(GFXTriangleStrip, mNodes.size()*mDetail+4);
	for (i = 0; i<=arraypt; i++) 
	{
		PrimBuild::texCoord2f(lBTexcs[i].x, lBTexcs[i].y);
		PrimBuild::vertex3f(lBorderVerts[i].x, lBorderVerts[i].y, lBorderVerts[i].z);
	}
	PrimBuild::end();

	PrimBuild::begin(GFXTriangleStrip, mNodes.size()*mDetail+4);
	for (i = 0; i<=arraypt; i++) 
	{
		PrimBuild::texCoord2f(rBTexcs[i].x, rBTexcs[i].y);
		PrimBuild::vertex3f(rBorderVerts[i].x, rBorderVerts[i].y, rBorderVerts[i].z);
	}
	PrimBuild::end();
	
	GFX->setAlphaBlendEnable(false);
	GFX->setAlphaTestEnable( false );
	GFX->setTextureStageColorOp(0, GFXTOPDisable);
	GFX->setTextureStageColorOp(1, GFXTOPDisable);
	GFX->setProjectionMatrix( proj );
	GFX->setViewport( viewport );
	gClientSceneGraph->getLightManager()->sgResetLights();
	GFX->popWorldMatrix();
}
#31
11/21/2008 (5:13 am)
Quote:As it turns out the flicker is not so much of a flicker as the road disappears at certain camera angles. I am not sure, but this seems to be an issue with visibility culling.

The same thing always seems to happen when you do any low-level OpenGL polygons very close to the terrain. I always assumed it was just an OpenGL rendering error, putting the wrong surface in front.

For example, I do oilslicks and skid marks as types of decal, and offset them by maybe 0.2m from the ground to stop this happening.
#32
11/21/2008 (9:07 am)
I had though that too but that isn't the case here. You see the problem did not exist until I started porting it over to TGEA. Therefore the issue is there. Also, I tried setting the thing well up from the terrain, the problem was still there.

Here is a quick video that shows what I am seeing.
i72.photobucket.com/albums/i192/DTDA/th_Ashes_FXRoad-1.jpg
#33
11/21/2008 (10:07 am)
@Ron - Looks to me like the object/world bounding box isn't being set correctly.
#34
11/21/2008 (10:34 am)
You were right Tom. It wasn't that I wasn't setting it, it was WHEN I was setting it that was the problem. I simply moved that code to the end of my computations function and it works great now.

Now I just need to set the looping option for it and get the collisions working.
#35
12/06/2008 (10:35 am)
Having now got this to compile, how do I go about using it? how do I get it into the editor to make use of it?
#36
12/06/2008 (10:43 am)
There are instructions on how to add this resource to the editor at the top of the .cc file.
#37
12/07/2008 (1:27 pm)
Ta, I'm not that big on reading. tends to leave me tearing hair out. gotta start reading
#38
06/13/2009 (8:29 am)
hi all, any one can help me? Can you send me the final working code for TGE 1.5.2? thanks
#39
08/15/2009 (3:56 am)
this works great but how do i get the road to conect together???
#40
01/19/2010 (8:29 am)
Official threadomancy because I think this project deserves it. I'm just registering my intent to get this working properly... probably not soon, but eventually ;).

First things I noticed after adding it to a fresh 1.5.2, in the Barebones mission - the crossbow no longer works, and Kork is frozen jittering in place. Not good.

EDIT: I don't think calling setGlobalBounds is the right way to fix the rendering thing. That means the road will always be checked for rendering and collision. But it's not what's causing the issues with AIPlayers and Projectiles - that seems to be something messed up with the rendering code, it's not cleaning up after itself or something. Interestingly, if I go into the editor I can see Kork's marker running happily around the level, while his body stays jittering where it was when I created the road. I can also see projectile markers being created when I shoot, but nothing is rendered.

EDIT:
This
mObjBox = Box3F(*mNodes.begin(), *mNodes.end()); // i guess
Seems to be screwing the object box up. However, it doesn't reset the world box, so that's okay isn't it?
Wait, maybe not. Let's try and fix it.

EDIT: well, just knocking that line out fixes the jitter for me :P. Still need to add a better solution for the world box, though.



EDIT: Whoah. Removing all the update logic from renderObject fixes everything. Kork and Projectiles are back, and the road actually goes away when you delete it. That's weird. Anyway, I shouldn't complain when solutions are simpler than I anticipate :P.

EDIT: Here's a replacement for the code I listed above:
//Update object box with nodes
   for(U32 i = 0; i < mNodes.size(); i++)
   {
      mObjBox.min.setMin(mNodes[i]);
      mObjBox.max.setMax(mNodes[i]);
   }
   resetWorldBox();
   setRenderTransform(mObjToWorld);
I stuck all that code formerly from renderObject into an update() method, which I call at the end of onAdd, in onEditorPostApply, and in unpackUpdate if we've had an update.
But for some reason the box is still really tall.
Oh, I know why. Just default it to 0 size and that'll solve it.



EDIT: Okay, so one of the biggest problems seems to be that the path is created all at one height for me. I thought the idea was to snap to the terrain at each node, but instead it's snapping to the terrain at only one node, so all the other points end up being above or below the terrain.

First order of business: getting rid of the fixed-size array, which I think is what's causing the crash I get when I create a path with too high detail and too many path markers (reducing either solves the crash).

Second: making the road follow the path instead of the terrain. I don't want any terrain snapping, and I want the path to follow the rotation of each marker.

Third: adding customisability, primarily in shaping the path. Since I won't be snapping the path to the terrain, I want to allow you to adjust the height of the borders at every node, as well as their angle. This should be defined by the scale of each path node, I guess - Z scale determines the height of the border, X scale determines how wide the border is at its base. Also I'd like to optionally render a bottom surface, which just stretches between the bottoms of the borders.

Fourth: fog and collision! For collision, I've heard that Atlas returns each triangle as a convex, so I think I'll need to do something like that. Also, of course, split the road into several sub-objects with their own boxes to make collision detection more efficient.