diff --git a/Engine/source/T3D/fx/groundCover.cpp b/Engine/source/T3D/fx/groundCover.cpp index a760d930d..80c60142e 100644 --- a/Engine/source/T3D/fx/groundCover.cpp +++ b/Engine/source/T3D/fx/groundCover.cpp @@ -316,7 +316,7 @@ U32 GroundCoverCell::renderShapes( const TSRenderState &rdata, camVector = inst.point - state->getDiffuseCameraPosition(); dist = getMax( camVector.len(), 0.01f ); - worldMat.set( EulerF(0, 0, inst.rotation), inst.point ); + worldMat.set( EulerF(inst.normal.x, inst.normal.y, inst.rotation), inst.point ); // TSShapeInstance::render() uses the // world matrix for the RenderInst. @@ -423,6 +423,7 @@ U32 GroundCover::smStatRenderedBillboards = 0; U32 GroundCover::smStatRenderedBatches = 0; U32 GroundCover::smStatRenderedShapes = 0; F32 GroundCover::smDensityScale = 1.0f; +F32 GroundCover::smFadeScale = 1.0f; ConsoleDocClass( GroundCover, "@brief Covers the ground in a field of objects (IE: Grass, Flowers, etc)." @@ -494,8 +495,15 @@ GroundCover::GroundCover() mWindScale[i] = 1.0f; + mMinSlope[i] = 0.0f; mMaxSlope[i] = 0.0f; + mConformToNormal[i] = false; + mMinRotX[i] = 0.0f; + mMaxRotX[i] = 0.0f; + mMinRotY[i] = 0.0f; + mMaxRotY[i] = 0.0f; + mMinElevation[i] = -99999.0f; mMaxElevation[i] = 99999.0f; @@ -566,8 +574,16 @@ void GroundCover::initPersistFields() addField( "windScale", TypeF32, Offset( mWindScale, GroundCover ), MAX_COVERTYPES, "The wind effect scale." ); + addField( "minSlope", TypeF32, Offset(mMinSlope, GroundCover), MAX_COVERTYPES, "The minimum slope angle in degrees for placement."); + addField( "maxSlope", TypeF32, Offset( mMaxSlope, GroundCover ), MAX_COVERTYPES, "The maximum slope angle in degrees for placement." ); + addField("conformToNormal",TypeBool, Offset(mConformToNormal, GroundCover), MAX_COVERTYPES, "Use the terrain's slope for angle"); + addField("minRotX", TypeF32, Offset(mMinRotX, GroundCover), MAX_COVERTYPES, "minumum amount of rotation along the X axis to add"); + addField("maxRotX", TypeF32, Offset(mMaxRotX, GroundCover), MAX_COVERTYPES, "maximum amount of rotation along the X axis to add"); + addField("minRotY", TypeF32, Offset(mMinRotY, GroundCover), MAX_COVERTYPES, "minumum amount of rotation along the Y axis to add"); + addField("maxRotY", TypeF32, Offset(mMaxRotY, GroundCover), MAX_COVERTYPES, "maximum amount of rotation along the Y axis to add"); + addField( "minElevation", TypeF32, Offset( mMinElevation, GroundCover ), MAX_COVERTYPES, "The minimum world space elevation for placement." ); addField( "maxElevation", TypeF32, Offset( mMaxElevation, GroundCover ), MAX_COVERTYPES, "The maximum world space elevation for placement." ); @@ -613,6 +629,8 @@ void GroundCover::consoleInit() { Con::addVariable( "$pref::GroundCover::densityScale", TypeF32, &smDensityScale, "A global LOD scalar which can reduce the overall density of placed GroundCover.\n" "@ingroup Foliage\n"); + Con::addVariable("$pref::GroundCover::fadeScale", TypeF32, &smFadeScale, "A global fade scalar which can reduce the overall rendered distance of placed GroundCover.\n" + "@ingroup Foliage\n"); Con::addVariable( "$GroundCover::renderedCells", TypeS32, &smStatRenderedCells, "Stat for number of rendered cells.\n" "@ingroup Foliage\n"); @@ -720,7 +738,13 @@ U32 GroundCover::packUpdate( NetConnection *connection, U32 mask, BitStream *str stream->write( mSizeExponent[i] ); stream->write( mWindScale[i] ); + stream->write( mMinSlope[i] ); stream->write( mMaxSlope[i] ); + stream->writeFlag(mConformToNormal[i]); + stream->write(mMinRotX[i]); + stream->write(mMaxRotX[i]); + stream->write(mMinRotY[i]); + stream->write(mMaxRotY[i]); stream->write( mMinElevation[i] ); stream->write( mMaxElevation[i] ); @@ -785,7 +809,13 @@ void GroundCover::unpackUpdate( NetConnection *connection, BitStream *stream ) stream->read( &mSizeExponent[i] ); stream->read( &mWindScale[i] ); + stream->read( &mMinSlope[i] ); stream->read( &mMaxSlope[i] ); + mConformToNormal[i] = stream->readFlag(); + stream->read(&mMinRotX[i]); + stream->read(&mMaxRotX[i]); + stream->read(&mMinRotY[i]); + stream->read(&mMaxRotY[i]); stream->read( &mMinElevation[i] ); stream->read( &mMaxElevation[i] ); @@ -1142,7 +1172,14 @@ GroundCoverCell* GroundCover::_generateCell( const Point2I& index, F32 flipBB = -1.0f; // Precompute a few other type specific values. + const bool typeConformToNormal = mConformToNormal[type]; + const F32 typeMinRotX = (mMaxRotX[type] > mMinRotX[type]) ? mMinRotX[type] : mMaxRotX[type]; + const F32 typeMaxRotX = (mMaxRotX[type] > mMinRotX[type]) ? mMaxRotX[type] : mMinRotX[type]; + const F32 typeMinRotY = (mMaxRotY[type] > mMinRotY[type]) ? mMinRotY[type] : mMaxRotY[type]; + const F32 typeMaxRotY = (mMaxRotY[type] > mMinRotY[type]) ? mMaxRotY[type] : mMinRotY[type]; + const F32 typeSizeRange = mSizeMax[type] - mSizeMin[type]; + const F32 typeMinSlope = mMinSlope[type]; const F32 typeMaxSlope = mMaxSlope[type]; const F32 typeMaxElevation = mMaxElevation[type]; const F32 typeMinElevation = mMinElevation[type]; @@ -1253,11 +1290,22 @@ GroundCoverCell* GroundCover::_generateCell( const Point2I& index, continue; } + if (!mIsZero(typeMinSlope)) + { + if (mAcos(normal.z) < mDegToRad(typeMinSlope)) + continue; + } point.set( cp.x, cp.y, h ); p.point = point; p.rotation = rotation; p.normal = normal; - + if (!typeConformToNormal) + { + p.normal.y = 0; + p.normal.x = 0; + } + p.normal.x += rand.randF(typeMinRotX, typeMaxRotX); + p.normal.y += rand.randF(typeMinRotY, typeMaxRotY); // Grab the terrain lightmap color at this position. // // TODO: Can't we remove this test? The terrain @@ -1562,7 +1610,8 @@ void GroundCover::prepRenderImage( SceneRenderState *state ) F32 screenScale = state->getWorldToScreenScale().y / state->getViewport().extent.y; // Set the far distance for billboards. - mCuller.setFarDist( mRadius * screenScale ); + F32 radius = mRadius * smFadeScale; + mCuller.setFarDist(radius * screenScale ); F32 cullScale = 1.0f; if ( state->isReflectPass() ) @@ -1571,7 +1620,7 @@ void GroundCover::prepRenderImage( SceneRenderState *state ) // Setup our shader const data. // Must be done prior to submitting our render instance. - mShaderConstData.fadeInfo.set( mFadeRadius * cullScale * screenScale, mRadius * cullScale * screenScale ); + mShaderConstData.fadeInfo.set( mFadeRadius * smFadeScale * cullScale * screenScale, radius * cullScale * screenScale ); const F32 simTime = Sim::getCurrentTime() * 0.001f; @@ -1649,7 +1698,7 @@ void GroundCover::prepRenderImage( SceneRenderState *state ) rdata.setLightQuery( &query ); // TODO: Add a special fade out for DTS? - mCuller.setFarDist( mShapeCullRadius ); + mCuller.setFarDist( mShapeCullRadius*smFadeScale); for ( S32 i = 0; i < mCellGrid.size(); i++ ) { diff --git a/Engine/source/T3D/fx/groundCover.h b/Engine/source/T3D/fx/groundCover.h index 256f6770e..6679777ca 100644 --- a/Engine/source/T3D/fx/groundCover.h +++ b/Engine/source/T3D/fx/groundCover.h @@ -151,6 +151,13 @@ public: /// Returns the current quality scale... see above. static F32 getQualityScale() { return smDensityScale; } + /// Sets the global ground cover fade scalar which controls + /// the percentage of the maximum designed distance to display cover. + /// Returns the actual value set. + static F32 setFadeScale(F32 scale) { return smFadeScale = mClampF(scale, 0.0f, 1.0f); } + + /// Returns the current fade scale... see above. + static F32 getFadeScale() { return smFadeScale; } protected: enum MaskBits @@ -255,6 +262,7 @@ protected: /// down. It scales both rendering cost and placement /// CPU performance. static F32 smDensityScale; + static F32 smFadeScale; String mMaterialName; Material *mMaterial; @@ -282,9 +290,19 @@ protected: /// The wind effect scale. F32 mWindScale[MAX_COVERTYPES]; + /// The maximum slope angle in degrees for placement. + F32 mMinSlope[MAX_COVERTYPES]; + /// The maximum slope angle in degrees for placement. F32 mMaxSlope[MAX_COVERTYPES]; + /// conform the x/y rotations to gorund normal + bool mConformToNormal[MAX_COVERTYPES]; + F32 mMinRotX[MAX_COVERTYPES]; + F32 mMaxRotX[MAX_COVERTYPES]; + F32 mMinRotY[MAX_COVERTYPES]; + F32 mMaxRotY[MAX_COVERTYPES]; + /// The minimum world space elevation for placement. F32 mMinElevation[MAX_COVERTYPES];