GroundCover Atlas Changes
by J.C. Smith · in Torque Game Engine Advanced · 03/19/2008 (8:40 am) · 31 replies
DISCLAIMER: This is unoptimized code and a lot of areas are just hacked in where they should really get their own settings which can be read in. But I just did this port quickly today while porting the 1.7 changes into the Repopulation client. I had to disable the lightmap stuff also unfortunately due to differences between Atlas and legacy terrain, though I may add a method for that later this week if I have time. But this will get the groundcover changes working for you on Atlas... at the cost of removing the ability to use it on Legacy. I'm tired and lazy so just posted it in here in its entirety.
groundcover.h code:
groundcover.h code:
//-----------------------------------------------------------------------------
// Torque Ground Cover
// Copyright (C) Sickhead Games, LLC
//-----------------------------------------------------------------------------
#ifndef _GROUNDCOVER_H_
#define _GROUNDCOVER_H_
#ifndef _SCENEOBJECT_H_
#include "sceneGraph/sceneObject.h"
#endif
#ifndef _FRUSTRUMCULLER_H_
#include "util/frustrumCuller.h"
#endif
#ifndef _GFXTEXTUREHANDLE_H_
#include "gfx/gfxTextureHandle.h"
#endif
#ifndef _GFX_GFXPRIMITIVEBUFFER_H_
#include "gfx/gfxPrimitiveBuffer.h"
#endif
//jc
#ifndef _ATLASINSTANCE2_H_
#include "atlas/runtime/atlasinstance2.h"
#endif
//class TerrainBlock; //jc
class GroundCoverCell;
class ShaderData;
class TSShapeInstance;
class LightAllocator;
class GroundCover : public SceneObject
{
public:
GroundCover();
DECLARE_CONOBJECT(GroundCover);
static void consoleInit();
static void initPersistFields();
bool onAdd();
void onRemove();
void inspectPostApply();
// Network
U32 packUpdate( NetConnection *, U32 mask, BitStream *stream );
void unpackUpdate( NetConnection *, BitStream *stream );
// Rendering
bool prepRenderImage( SceneState *state, const U32 stateKey, const U32 startZone, const bool modifyBaseState );
void renderObject( SceneState *state, RenderInst *ri );
// Editor
void onTerrainUpdated( U32 flags, const Point2I& min, const Point2I& max ); //jc
/// Sets the global ground cover LOD scalar which controls
/// the percentage of the maximum designed cover to put down.
/// It scales both rendering cost and placement CPU performance.
/// Returns the actual value set.
static F32 setQualityScale( F32 scale ) { return smQualityScale = mClampF( scale, 0.0f, 1.0f ); }
/// Returns the current quality scale... see above.
static F32 getQualityScale() { return smQualityScale; }
protected:
friend class GroundCoverCell;
typedef SceneObject Parent;
enum
{
/// This is the max number of ground cover types allowed.
NumCoverTypes = 6,
};
/// This RNG seed is saved and sent to clients
/// for generating the same cover.
S32 mRandomSeed;
/// The name of the terrain object which we're
/// generating ground cover for.
StringTableEntry mTerrainName;
/// The ghost id of the terrain object on the client side.
U32 mTerrainGhostId;
/// The terrain object we're generating ground cover on.
SimObjectPtr<AtlasInstance> mTerrainBlock;
/// This is the outer generation radius from
/// the current camera position.
F32 mRadius;
// Offset along the Z axis to render the ground cover.
F32 mZOffset;
/// This is less than or equal to mRadius and
/// defines when fading of cover elements begins.
F32 mFadeRadius;
#22
You continue to surprise me with your TGEA prowess!
04/01/2008 (11:57 am)
Wow, that looks amazing J.C.You continue to surprise me with your TGEA prowess!
#23
Another thing that could definitely use improvement is the way I'm layering, it causes the areas where there are no foliage to wind up being noticably blocky. I'm thinking having a less dense version of clutter on the edges of the layers would cover that up, though haven't tried it yet.
@Gerard: For the most part this is just modified code based on the work that Tom and GG did on the groundcover. Just porting over those features to Atlas with some slight tweaks to accomodate for the difference in the two types of terrain. Credit belongs to them for the most part, but since I'm going through and doing it anyway I figured I'd share. The multiple detail textures is something new though, but it's still a work in progress, the screenshots don't show much of it.
04/01/2008 (12:04 pm)
@Tom: Yeah I agree. I did that with the foliage replicator previously and it had better results. I actually just switched over to a wider texture today when snapping those shots to fill things in a bit more. Definitely the auto-facing sticks out though.Another thing that could definitely use improvement is the way I'm layering, it causes the areas where there are no foliage to wind up being noticably blocky. I'm thinking having a less dense version of clutter on the edges of the layers would cover that up, though haven't tried it yet.
@Gerard: For the most part this is just modified code based on the work that Tom and GG did on the groundcover. Just porting over those features to Atlas with some slight tweaks to accomodate for the difference in the two types of terrain. Credit belongs to them for the most part, but since I'm going through and doing it anyway I figured I'd share. The multiple detail textures is something new though, but it's still a work in progress, the screenshots don't show much of it.
#24
Other than that use the value from the layer texture and a random to soften the hard edges. Be sure that the random is calculated along with the other randoms or you can loose the determinism of the ground cover placement.
04/01/2008 (12:40 pm)
@JC - First off use a higher resolution layering texture. Our original implementation was tied to the TerrainPainter which is why we had to use a 256x256. In this case your not limited by that.Other than that use the value from the layer texture and a random to soften the hard edges. Be sure that the random is calculated along with the other randoms or you can loose the determinism of the ground cover placement.
#25
You need to add this into groundcover.cpp:
modify the OnAdd to look like this:
OnRemove should look like this:
Add this to the end of the packupdate, just before the return 0;
Then add this to the end of unpackupdate:
Now move over to groundcover.h and add this to the public area:
Add this into the protected area:
05/02/2008 (7:19 am)
It should be noted that this needs to be changed slightly as of 1.0 final. This is just a merge of the updates in the code.You need to add this into groundcover.cpp:
void GroundCover::onGhostAlwaysDone()
{
if ( isServerObject() )
{
StringTableEntry terrainName = mTerrainName;
// if ( !terrainName || !terrainName[0] )
terrainName = StringTable->insert( "AtlasTerrain" );
mTerrainBlock = dynamic_cast<AtlasInstance*>(Sim::findObject("AtlasTerrain")); //jc
//mTerrainBlock = dynamic_cast<TerrainBlock*>( Sim::findObject( terrainName ) );
mTerrainGhostId = 0;
setMaskBits( TerrainBlockMask );
}
else
{
mTerrainBlock = NULL;
}
}modify the OnAdd to look like this:
bool GroundCover::onAdd()
{
if (!Parent::onAdd())
{
return false;
}
// We don't use any bounds.
mObjBox.min.set(-1e5, -1e5, -1e5);
mObjBox.max.set( 1e5, 1e5, 1e5);
resetWorldBox();
// Prepare some client side things.
if ( isClientObject() )
{
mBBShader = NULL;
if ( !Sim::findObject( "GroundCoverShaderData", mBBShader ) )
Con::warnf("GroundCover - failed to locate billboard shader GroundCoverShaderData!");
mLightAllocator = new LightAllocator();
_initShapes();
}
addToScene();
NetConnection::smGhostAlwaysDone.notify( this, &GroundCover::onGhostAlwaysDone );
return true;
}OnRemove should look like this:
void GroundCover::onRemove()
{
Parent::onRemove();
_deleteCells();
_deleteShapes();
// jc
//if ( isClientObject() && mTerrainBlock )
// mTerrainBlock->mUpdateSignal.remove( this, &GroundCover::onTerrainUpdated );
NetConnection::smGhostAlwaysDone.remove( this, &GroundCover::onGhostAlwaysDone );
mTerrainBlock = NULL;
mBBShader = NULL;
SAFE_DELETE( mLightAllocator );
removeFromScene();
}Add this to the end of the packupdate, just before the return 0;
if (stream->writeFlag(mask & TerrainBlockMask))
{
U32 ghostId = -1;
if ( mTerrainBlock )
ghostId = connection->getGhostIndex( mTerrainBlock );
stream->write( ghostId );
}Then add this to the end of unpackupdate:
if (stream->readFlag())
stream->read( &mTerrainGhostId );Now move over to groundcover.h and add this to the public area:
void onGhostAlwaysDone();
Add this into the protected area:
enum MaskBits {
InitialUpdateMask = Parent::NextFreeMask,
TerrainBlockMask = InitialUpdateMask << 1,
NextFreeMask = TerrainBlockMask << 1
};
#26
11/15/2008 (11:44 am)
I tried to get this to work in 1.71 and it compiled fine, but the shapes dont show up on the terrain. Is there anything that needs to be added for 1.71?
#27
11/16/2008 (1:52 am)
Shoot me an email and I'll send you a working copy. Not sure what changes I made since then off hand and busy time at work don't have a chance to look over it. I have a working copy here though.
#28
11/23/2008 (11:45 pm)
J.C., is the best email to reach you at the one in your public profile? I sent you an email last week. I've had some issues similar to Adam -- in some cases groundcover fails to appear at all. I've made some additions to the code you posted and am interested in merging my changes in with your latest version. Once everything is working 100% for me I'll post the complete code.
#29
11/24/2008 (7:49 am)
Hmm yeah it should be, try sending again, might have gotten eaten by my spam filter. I'll look in there though.
#30
11/24/2008 (10:08 am)
Wao great work !!! ;-)
#31
11/24/2008 (10:17 am)
@JC, no problem. I sent it again (its from my gmail address -- my firstname . lastname @ gmail).
Associate Tom Spilman
Sickhead Games
I would suggest modifying GroundCover to support billboards that are not camera aligned. You just need to generate a random rotation, pass it to the shader, and use that rotation to generate the correct up/right vectors for the billboard.
This should be a visual improvement with this style of wide billboards and could be made an optional feature per cover type in the GroundCover object.