Game Development Community

dev|Pro Game Development Curriculum

TGEA GroundCover Terrain Surface Reference

by Leslie Young · 07/18/2008 (12:46 pm) · 16 comments

Download Code File

This is a port of TGEA 1.7 port of twSurfaceReference to work with GroundCover.
You can watch a Video of this in action.

Step 1

Note: If you allready followed the TGEA 1.7 port of twSurfaceReference resource you will not need to do Step 1, which is...
Copy twSurfaceReference.cpp and twSurfaceReference.h from the provided ZIP file to engine/T3D/fx/ and then add those files to your project.

[edit - forgot to mention this, which is part of previous resource]
You will also need to do the following.

In engine/console/sim.h add below this line
DeclareNamedSet(sgMissionLightingFilterSet);
the following
DeclareNamedSet(twSurfaceSet);

and in engine/console/sim.cpp add below these lines
ImplementNamedGroup(ChunkFileGroup)
ImplementNamedSet(sgMissionLightingFilterSet)
the following
ImplementNamedSet(twSurfaceSet);

and in engine/console/simManager.cpp add below these lines
InstantiateNamedSet(BehaviorSet);
InstantiateNamedSet(sgMissionLightingFilterSet);
the following
InstantiateNamedSet(twSurfaceSet);

Sep 2

Open engine/T3D/fx/groundCover.h

find
static void initPersistFields();

put below it
bool GetTerrainTextures(float,Point3F&, U8 *);

find
F32 mNormalizedProbability[NumCoverTypes];

put below it
bool mSurfaceExclusionMode[NumCoverTypes];
U32  mTheSurface[NumCoverTypes];

Your done with groundCover.h
Now open engine/T3D/fx/groundCover.cpp

find
#include "sceneGraph/lightAllocator.h"
#include "T3D/fx/windEmitter.h"

put below it
#include "twSurfaceReference.h"

find (in GroundCover::GroundCover)
mBillboardAspectScales[i] = 1.0f;
mNormalizedProbability[i] = 0.0f;

put below it
mSurfaceExclusionMode[i] = false;         
mTheSurface[i] = (U32)twSurfaceReference::eAny;

find (in void GroundCover::initPersistFields)
dSprintf( fieldName, sizeof( fieldName ), "clumpRadius%d", i );
addField( fieldName, TypeF32, Offset( mClumpRadius[i], GroundCover ) );

put below it
dSprintf( fieldName, sizeof( fieldName ), "SurfaceExclusionMode%d", i );
addField( fieldName, TypeBool, Offset( mSurfaceExclusionMode[i], GroundCover ) );
dSprintf( fieldName, sizeof( fieldName ), "SurfaceType%d", i );
addField( fieldName, TypeEnum, Offset( mTheSurface[i], GroundCover ), 1, &gSurfaceTypeTable );

find (in U32 GroundCover::packUpdate)
stream->writeString( mShapeFilenames[i] );

put below it
stream->writeFlag( mSurfaceExclusionMode[i] );
stream->write( mTheSurface[i] );

find (in void GroundCover::unpackUpdate)
mShapeFilenames[i] = stream->readSTString();

put below it
mSurfaceExclusionMode[i] = stream->readFlag();
stream->read( &mTheSurface[i] );

find (in GroundCoverCell* GroundCover::_generateCell)
// Do we need to check slope?
         if ( !isZero( typeMaxSlope ) )
         {
            if (mAcos(normal.z) > mDegToRad(typeMaxSlope))
               continue;
         }

         point.set( cp.x, cp.y, h );

put below it
// -------------------------------------------------------------------------------------------------
if ((twSurfaceReference::ESurfaceType)mTheSurface[type]) // if we are checking for specific surfaces and not just 'any'
{
	if ( BaseSurfaces[(twSurfaceReference::ESurfaceType)mTheSurface[type]].isAvailable)
	{
		U8 alphas[TerrainBlock::MaterialGroups];
		if (GetTerrainTextures(4000.0f, point, alphas))
		{
			bool skip = mSurfaceExclusionMode[type];
			for (int i=0; i < TerrainBlock::MaterialGroups; i++)
			{
				if (alphas[ i] != BaseSurfaces[(twSurfaceReference::ESurfaceType)mTheSurface[type]].alphas[ i])
				{
					skip = !mSurfaceExclusionMode[type]; // even one non-match means this is not the same surface
					break;
				}
			}
			if (skip) continue; // don't place here
		}
	}
}
// -------------------------------------------------------------------------------------------------

got to end of the file and add
bool GroundCover::GetTerrainTextures(float distance, Point3F& pt, U8 *alphas)
{
	RayInfo rInfo;

   if (gClientContainer.castRay(pt, Point3F(pt.x, pt.y, pt.z - distance ), TerrainObjectType, &rInfo))
   {
   U32 CollisionType = rInfo.object->getTypeMask();

      if (CollisionType & TerrainObjectType)
      {
		   TerrainBlock* ter = static_cast<TerrainBlock*>(rInfo.object);
		   Point2I gPos;
		   const MatrixF & mat = ter->getTransform();

		   Point3F origin;
		   mat.getColumn(3, &origin);
		   F32 squareSize = (F32) ter->getSquareSize();
		   F32 halfSquareSize = squareSize / 2;

		   float x = (pt.x - origin.x + halfSquareSize) / squareSize;
		   float y = (pt.y - origin.y + halfSquareSize) / squareSize;

		   ter->getMaterialAlpha(Point2I(x,y), alphas);
		   return true;
      }
   }
   return false;
}

COMPILE.

Sep 3

If you allready followed the TGEA 1.7 port of twSurfaceReference resource you do not need to do the following, however you might have to check creator.ed.cs for TGEA1.7.1 as the array index could be wrong, see my code below.

Script changes

Open game\tools\missionEditor\gui\objectBuilderGui.ed.gui and find
function ObjectBuilderGui::buildfxFoliageReplicator(%this)
{
	%this.className = "fxFoliageReplicator";
	%this.process();
}

put below it
function ObjectBuilderGui::buildtwSurfaceReference(%this)      
{      	
	%this.className = "twSurfaceReference";      	
	%this.process();      
}

Open game\tools\missiodeditor\scripts\editors\creator.ed.cs and find
%Environment_Item[16] = "TerrainBlock";
%Environment_Item[17] = "MegaTerrain";
%Environment_Item[18] = "Atlas";

put below it
%Environment_Item[19] = "twSurfaceReference";

Open game\common\clientScripts\missiondownload.cs and find
function clientCmdMissionStartPhase3(%seq,%missionName)
{
   onPhase2Complete();

put below it
StartSurfaceReferencer();

That should be it for scripts

Step 4

How to use.

You will find in Mission Objects -> Environment the twSurfaceReference.
Place this over a piece of terrain that contains some unique texture.
Now check the new object's properties, you want to select a SurfaceType for it.
Lets say you choose "Grass"

Now, go to Mission Objects -> Environment and select GroundCover
GroundCover wants a billboard, so in its properties find the group "Ground Cover Billboard" and find your billboard texture under it.
I found that GroundCover work as follow.
There are 6 "Ground Cover Type" groups.
For each you can specify a shape to use as groundcover.
Lets say you only wanted to use 3 shapes, the other 3 will make use of the billboard you specified.
This is important to know cause you might notice your Billboards still rendering over areas you did not want.
Easy to fix, just make sure to select for each of the Ground Cover Types a SurfaceType, which by default is Any.

ok, so since you created a twSurfaceReference with surfacetype previously you can just go and set all the SurfaceType properties for each of the Ground Cover Types to "Grass"
and everything will render on your grass texture where ever its used on your terrain and stay off your other textures.

Nice thing about GroundCover is that you could add a second twSurfaceReference over another texture, lets say some sand like texture and then give it a surfaceType if Dirt for example.
Now you can go set one of your Ground Cover Types' SurfaceType to Dirt and that shape will render on the dirt only ;)

Note: whenever you add a new twSurfaceReference or GroundCOver object, save and exit and reload the mission else you might not otice updates.

#1
07/15/2008 (2:45 pm)
Few screenshots,

In the first one you can see the GroundCover staying off my path.

www.sentient-dreams.com/miscfiles/kbm/gc2.jpg
and in the second one I created a second twSurfaceReference for the dirt and in my GroundCover selected it for the one plant type so it will grow on the dirt and not the grass.

www.sentient-dreams.com/miscfiles/kbm/gc1.jpg
#2
07/18/2008 (1:58 pm)
Now that's great.
#3
07/18/2008 (10:42 pm)
My game crashes when I add a twSurfaceInspector object. No errors in console, just crash. I am using TGEA 1.7 if that matters.
#4
07/18/2008 (10:46 pm)
I am also trying it on a MegaTerrain, but that shouldnt matter since its just a terrain block (shouldnt it?).
#5
07/19/2008 (7:29 am)
@Adam, I did not make twSurfaceInspector so I don't know why it would crash. Did you check console log for a clue? Normally I go off to a corner of the map (where I won't be editing anything and then paint a texture there (5+ hard brush) and then place the twSurfaceInspector there. Might be that you got some blended texture perhaps and the twSurfaceInspector can't figure out what ot use?

If that doesn't work try normal terrain to see if that works. If it does then twSurfaceInspector probably don't like MegaTerrain :(
#6
07/19/2008 (12:09 pm)
I tried it on a fresh install of 1.7 and 1.71 and they both crash. In both consoles, I see that this is printed:

twSurfaceReference - Cannot locate the 'twSurfaceSet', this is bad!

I dont know what is happening, but its for Mega Terrains and just single terrains, 1.7 and 1.71 so no matter what I do, it crashes. Are you sure you didnt forget something to add somewhere? Has anyone else got this working at all?
#7
07/19/2008 (12:24 pm)
Well I am dumb, I forgot to include the console/sim changes in the twSurfaceReference resource. It works well now, thanks!
#8
07/20/2008 (1:18 am)
Glad you got it to work ;)
#9
08/17/2008 (9:00 am)
Great resource!
#10
08/28/2008 (8:03 am)
Leslie i have a problem, when i put any ground cover type the game crash :( any help? i use TGEA 1.7.1
#11
08/28/2008 (8:09 am)
aaaah a question, in ground cover type, the shape is a dts?
#12
08/28/2008 (8:11 am)
Yes, shapes must be DTS not textures (to be used as billboards)

Under Ground Cover Billboard you may spaecify a texture that will be used in all cases where you did not provide a DTS for the "Ground Cover Type" .. the 0 to 5 ground covers.
Under each of the Ground Cover Types you can only use DTS.
#13
11/03/2008 (7:50 pm)
Double-plus Awesome!

When I create twSurfaceReference, I had no idea people outside my team would actually use it! And update it and everything! Thanks for this.
#14
02/26/2009 (8:14 am)
Anyone have this working for 1.8.1? I can almost get it..but when I compile I get an error: "cannot find file: 'renderInstance/renderInstMgr.h'"

Not very good at the engine side of things...but I'll post the changes here when I get it figured out
#15
03/18/2009 (11:13 am)
Anyone any luck on getting this working in 1.8.1 yet?

@J, 'renderInstance/renderInstMgr.h' isn't in 1.8.1 but it is in 1.7.1, not that that will be any help :-(
#16
03/18/2009 (12:21 pm)
I would love to help you guys out but I'm lately only working with Unity3D and don't have TGEA 1.8.1 installed.

Which file is asking for renderInstance/renderInstMgr.h ?
Maybe the functionality was moved somewhere else.