⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fxfoliagereplicator.cc

📁 五行MMORPG引擎系统V1.0
💻 CC
📖 第 1 页 / 共 5 页
字号:
	// Initialise parents' persistent fields.
	Parent::initPersistFields();

	// Add out own persistent fields.
	addGroup( "Debugging" );	
	addField( "UseDebugInfo",		TypeBool,		Offset( mFieldData.mUseDebugInfo,			fxFoliageReplicator ) );	
	addField( "DebugBoxHeight",		TypeF32,		Offset( mFieldData.mDebugBoxHeight,			fxFoliageReplicator ) );	
	addField( "HideFoliage",		TypeBool,		Offset( mFieldData.mHideFoliage,			fxFoliageReplicator ) );
	addField( "ShowPlacementArea",	TypeBool,		Offset( mFieldData.mShowPlacementArea,		fxFoliageReplicator ) );
	addField( "PlacementAreaHeight",TypeS32,		Offset( mFieldData.mPlacementBandHeight,	fxFoliageReplicator ) );
	addField( "PlacementColour",	TypeColorF,		Offset( mFieldData.mPlaceAreaColour,		fxFoliageReplicator ) );
	endGroup( "Debugging" );	

	addGroup( "Media" );	
	addField( "Seed",				TypeS32,		Offset( mFieldData.mSeed,					fxFoliageReplicator ) );
	addField( "FoliageFile",		TypeFilename,	Offset( mFieldData.mFoliageFile,			fxFoliageReplicator ) );
	addField( "FoliageCount",		TypeS32,		Offset( mFieldData.mFoliageCount,			fxFoliageReplicator ) );
	addField( "FoliageRetries",		TypeS32,		Offset( mFieldData.mFoliageRetries,			fxFoliageReplicator ) );
	endGroup( "Media" );	

	addGroup( "Area" );	
	addField( "InnerRadiusX",		TypeS32,		Offset( mFieldData.mInnerRadiusX,			fxFoliageReplicator ) );	
	addField( "InnerRadiusY",		TypeS32,		Offset( mFieldData.mInnerRadiusY,			fxFoliageReplicator ) );	
	addField( "OuterRadiusX",		TypeS32,		Offset( mFieldData.mOuterRadiusX,			fxFoliageReplicator ) );	
	addField( "OuterRadiusY",		TypeS32,		Offset( mFieldData.mOuterRadiusY,			fxFoliageReplicator ) );	
	endGroup( "Area" );	

	addGroup( "Dimensions" );	
	addField( "MinWidth",			TypeF32,		Offset( mFieldData.mMinWidth,				fxFoliageReplicator ) );	
	addField( "MaxWidth",			TypeF32,		Offset( mFieldData.mMaxWidth,				fxFoliageReplicator ) );	
	addField( "MinHeight",			TypeF32,		Offset( mFieldData.mMinHeight,				fxFoliageReplicator ) );	
	addField( "MaxHeight",			TypeF32,		Offset( mFieldData.mMaxHeight,				fxFoliageReplicator ) );	
	addField( "FixAspectRatio",		TypeBool,		Offset( mFieldData.mFixAspectRatio,			fxFoliageReplicator ) );	
	addField( "FixSizeToMax",		TypeBool,		Offset( mFieldData.mFixSizeToMax,			fxFoliageReplicator ) );	
	addField( "OffsetZ",			TypeF32,		Offset( mFieldData.mOffsetZ,				fxFoliageReplicator ) );	
	addField( "RandomFlip",			TypeBool,		Offset( mFieldData.mRandomFlip,				fxFoliageReplicator ) );	
	endGroup( "Dimensions" );	

	addGroup( "Culling" );	
	addField( "UseCulling",			TypeBool,		Offset( mFieldData.mUseCulling,				fxFoliageReplicator ) );	
	addField( "CullResolution",		TypeS32,		Offset( mFieldData.mCullResolution,			fxFoliageReplicator ) );	
	addField( "ViewDistance",		TypeF32,		Offset( mFieldData.mViewDistance,			fxFoliageReplicator ) );	
	addField( "ViewClosest",		TypeF32,		Offset( mFieldData.mViewClosest,			fxFoliageReplicator ) );	
	addField( "FadeInRegion",		TypeF32,		Offset( mFieldData.mFadeInRegion,			fxFoliageReplicator ) );	
	addField( "FadeOutRegion",		TypeF32,		Offset( mFieldData.mFadeOutRegion,			fxFoliageReplicator ) );	
	addField( "AlphaCutoff",		TypeF32,		Offset( mFieldData.mAlphaCutoff,			fxFoliageReplicator ) );	
	addField( "GroundAlpha",		TypeF32,		Offset( mFieldData.mGroundAlpha,			fxFoliageReplicator ) );	
	endGroup( "Culling" );	

	addGroup( "Animation" );	
	addField( "SwayOn",				TypeBool,		Offset( mFieldData.mSwayOn,					fxFoliageReplicator ) );	
	addField( "SwaySync",			TypeBool,		Offset( mFieldData.mSwaySync,				fxFoliageReplicator ) );	
	addField( "SwayMagSide",		TypeF32,		Offset( mFieldData.mSwayMagnitudeSide,		fxFoliageReplicator ) );	
	addField( "SwayMagFront",		TypeF32,		Offset( mFieldData.mSwayMagnitudeFront,		fxFoliageReplicator ) );	
	addField( "MinSwayTime",		TypeF32,		Offset( mFieldData.mMinSwayTime,			fxFoliageReplicator ) );	
	addField( "MaxSwayTime",		TypeF32,		Offset( mFieldData.mMaxSwayTime,			fxFoliageReplicator ) );	
	endGroup( "Animation" );	

	addGroup( "Lighting" );	
	addField( "LightOn",			TypeBool,		Offset( mFieldData.mLightOn,				fxFoliageReplicator ) );	
	addField( "LightSync",			TypeBool,		Offset( mFieldData.mLightSync,				fxFoliageReplicator ) );	
	addField( "MinLuminance",		TypeF32,		Offset( mFieldData.mMinLuminance,			fxFoliageReplicator ) );	
	addField( "MaxLuminance",		TypeF32,		Offset( mFieldData.mMaxLuminance,			fxFoliageReplicator ) );	
	addField( "LightTime",			TypeF32,		Offset( mFieldData.mLightTime,				fxFoliageReplicator ) );	
	endGroup( "Lighting" );	

	addGroup( "Restrictions" );	
	addField( "AllowOnTerrain",		TypeBool,		Offset( mFieldData.mAllowOnTerrain,			fxFoliageReplicator ) );
	addField( "AllowOnInteriors",	TypeBool,		Offset( mFieldData.mAllowOnInteriors,		fxFoliageReplicator ) );
	addField( "AllowOnStatics",		TypeBool,		Offset( mFieldData.mAllowStatics,			fxFoliageReplicator ) );	
	addField( "AllowOnWater",		TypeBool,		Offset( mFieldData.mAllowOnWater,			fxFoliageReplicator ) );
	addField( "AllowWaterSurface",	TypeBool,		Offset( mFieldData.mAllowWaterSurface,		fxFoliageReplicator ) );
	addField( "AllowedTerrainSlope",TypeS32,		Offset( mFieldData.mAllowedTerrainSlope,	fxFoliageReplicator ) );
	endGroup( "Restrictions" );	
}

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

void fxFoliageReplicator::CreateFoliage(void)
{
	F32				HypX, HypY;
	F32				Angle;
	U32				RelocationRetry;
	Point3F			FoliagePosition;
	Point3F			FoliageStart;
	Point3F			FoliageEnd;
	Point3F			FoliageScale;
	bool			CollisionResult;
	RayInfo			RayEvent;

	// Let's get a minimum bounding volume.
	Point3F	MinPoint( -0.5, -0.5, -0.5 );
	Point3F	MaxPoint(  0.5,  0.5,  0.5 );

	// Check Host.
	AssertFatal(isClientObject(), "Trying to create Foliage on Server, this is bad!")

	// Cannot continue without Foliage Texture!
	if (mFieldData.mFoliageFile == "") return;

	// Check that we can position somewhere!
	if (!(	mFieldData.mAllowOnTerrain ||
			mFieldData.mAllowOnInteriors ||
			mFieldData.mAllowStatics ||
			mFieldData.mAllowOnWater))
	{
		// Problem ...
		Con::warnf(ConsoleLogEntry::General, "fxFoliageReplicator - Could not place Foliage, All alloweds are off!");

		// Return here.
		return;
	}

	// Destroy Foliage if we've already got some.
	if (mCurrentFoliageCount != 0) DestroyFoliage();

	// Inform the user if culling has been disabled!
	if (!mFieldData.mUseCulling)
	{
		// Console Output.
		Con::printf("fxFoliageReplicator - Culling has been disabled!");
	}

	// ----------------------------------------------------------------------------------------------------------------------
	// > Calculate the Potential Foliage Nodes Required to achieve the selected culling resolution.
	// > Populate Quad-tree structure to depth determined by culling resolution.
	//
	// A little explanation is called for here ...
	//
	//			The approach to this problem has been choosen to make it *much* easier for
	//			the user to control the quad-tree culling resolution.  The user enters a single
	//			world-space value 'mCullResolution' which controls the highest resolution at
	//			which the replicator will check visibility culling.
	//
	//			example:	If 'mCullResolution' is 32 and the size of the replicated area is 128 radius
	//						(256 diameter) then this results in the replicator creating a quad-tree where
	//						there are 256/32 = 8x8 blocks.  Each of these can be checked to see if they
	//						reside within the viewing frustum and if not then they get culled therefore
	//						removing the need to parse all the billboards that occcupy that region.
	//						Most of the time you will get better than this as the culling algorithm will
	//						check the culling pyramid from the top to bottom e.g. the follow 'blocks'
	//						will be checked:-
	//
	//						 1 x 256 x 256 (All of replicated area)
	//						 4 x 128 x 128 (4 corners of above)
	//						16 x  64 x  64 (16 x 4 corners of above)
	//						etc.
	//
	//
	//	1.		First-up, the replicator needs to create a fixed-list of quad-tree nodes to work with.
	//
	//			To calculate this we take the largest outer-radius value set in the replicator and
	//			calculate how many quad-tree levels are required to achieve the selected 'mCullResolution'.
	//			One of the initial problems is that the replicator has seperate radii values for X & Y.
	//			This can lead to a culling resolution smaller in one axis than the other if there is a
	//			difference between the Outer-Radii.  Unfortunately, we just live with this as there is
	//			not much we can do here if we still want to allow the user to have this kind of
	//			elliptical placement control.
	//
	//			To calculate the number of nodes needed we using the following equation:-
	//
	//			Note:- We are changing the Logarithmic bases from 10 -> 2 ... grrrr!
	//
	//			Cr = mCullResolution
	//			Rs = Maximum Radii Diameter
	//
	//
	//				( Log10( Rs / Cr )       )
	//			int ( ---------------- + 0.5 )
	//				( Log10( 2 )             )
	//
	//					---------|
	//					 \
	//					  \			 n
	//					  /			4
	//					 /
	//					---------|
	//					   n = 0
	//
	//
	//			So basically we calculate the number of blocks in 1D at the highest resolution, then
	//			calculate the inverse exponential (base 2 - 1D) to achieve that quantity of blocks.
	//			We round that upto the next highest integer = e.  We then sum 4 to the power 0->e
	//			which gives us the correct number of nodes required.  e is also stored as the starting
	//			level value for populating the quad-tree (see 3. below).
	//
	//	2.		We then proceed to calculate the billboard positions as normal and calculate and assign
	//			each billboard a basic volume (rather than treat each as a point).  We need to take into
	//			account possible front/back swaying as well as the basic plane dimensions here.
	//			When all the billboards have been choosen we then proceed to populate the quad-tree.
	//
	//	3.		To populate the quad-tree we start with a box which completely encapsulates the volume
	//			occupied by all the billboards and enter into a recursive procedure to process that node.
	//			Processing this node involves splitting it into quadrants in X/Y untouched (for now).
	//			We then find candidate billboards with each of these quadrants searching using the
	//			current subset of shapes from the parent (this reduces the searching to a minimum and
	//			is very efficient).
	//
	//			If a quadrant does not enclose any billboards then the node is dropped otherwise it
	//			is processed again using the same procedure.
	//
	//			This happens until we have recursed through the maximum number of levels as calculated
	//			using the summation max (see equation above).  When level 0 is reached, the current list
	//			of enclosed objects is stored within the node (for the rendering algorithm).
	//
	//	4.		When this is complete we have finished here.  The next stage is when rendering takes place.
	//			An algorithm steps through the quad-tree from the top and does visibility culling on
	//			each box (with respect to the viewing frustum) and culls as appropriate.  If the box is
	//			visible then the next level is checked until we reach level 0 where the node contains
	//			a complete subset of billboards enclosed by the visible box.
	//
	//
	//	Using the above algorithm we can now generate *massive* quantities of billboards and (using the
	//	appropriate 'mCullResolution') only visible blocks of billboards will be processed.
	//
	//	- Melv.
	//			
	// ----------------------------------------------------------------------------------------------------------------------



	// ----------------------------------------------------------------------------------------------------------------------
	// Step 1.
	// ----------------------------------------------------------------------------------------------------------------------

	// Calculate the maximum dimension.
	F32 MaxDimension = 2 * ( (mFieldData.mOuterRadiusX > mFieldData.mOuterRadiusY) ? mFieldData.mOuterRadiusX : mFieldData.mOuterRadiusY );

	// Let's check that our cull resolution is not greater than half our maximum dimension (and less than 1).
	if (mFieldData.mCullResolution > (MaxDimension/2) || mFieldData.mCullResolution < 8)
	{
		// Problem ...
		Con::warnf(ConsoleLogEntry::General, "fxFoliageReplicator - Could create Foliage, invalid Culling Resolution!");
		Con::warnf(ConsoleLogEntry::General, "fxFoliageReplicator - Culling Resolution *must* be >=8 or <= %0.2f!", (MaxDimension/2));

		// Return here.
		return;
	}

	// Take first Timestamp.
	F32 mStartCreationTime = Platform::getRealMilliseconds();

	// Calculate the quad-tree levels needed for selected 'mCullResolution'.
	mQuadTreeLevels = (U32)(mCeil(mLog( MaxDimension / mFieldData.mCullResolution ) / mLog( 2.0f )));

	// Calculate the number of potential nodes required.
	mPotentialFoliageNodes = 0;
	for (U32 n = 0; n <= mQuadTreeLevels; n++)
		mPotentialFoliageNodes += (U32)(mCeil(mPow(4.0f, n)));	// Ceil to be safe!

	// ----------------------------------------------------------------------------------------------------------------------
	// Step 2.
	// ----------------------------------------------------------------------------------------------------------------------

	// Set Seed.
	RandomGen.setSeed(mFieldData.mSeed);

	// Have we setup the Trig Tables?
	if (!mTrigTableInitialised)
	{
		F32 tIdx = 0.0f;

		// No, so setup Tables.
		for (U32 idx = 0; idx < 720; idx++, tIdx+=M_2PI/720.0f)
		{
			mCosTable[idx] = mCos(tIdx);
			mSinTable[idx] = mSin(tIdx);
		}

		// Signal Trig Tables Initialised.
		mTrigTableInitialised = true;
	}

	// Add Foliage.
	for (U32 idx = 0; idx < mFieldData.mFoliageCount; idx++)
	{
		fxFoliageItem*	pFoliageItem;

		// Reset Relocation Retry.
		RelocationRetry = mFieldData.mFoliageRetries;

		// Find it a home ...
		do
		{

			// Calculate a random offset
			HypX	= RandomGen.randF(mFieldData.mInnerRadiusX, mFieldData.mOuterRadiusX);
			HypY	= RandomGen.randF(mFieldData.mInnerRadiusY, mFieldData.mOuterRadiusY);
			Angle	= RandomGen.randF(0, M_2PI);

			// Calculate the new position.
			Point3F randomShapePosLocal;
			randomShapePosLocal.x = HypX * mCos(Angle);
			randomShapePosLocal.y = HypY * mSin(Angle);

			// Transform into world space coordinates
			Point3F shapePosWorld;
			MatrixF objToWorld = getRenderTransform();
			objToWorld.mulP(randomShapePosLocal, &shapePosWorld);
			FoliagePosition = shapePosWorld;

			// Initialise RayCast Search Start/End Positions.
			FoliageStart = FoliageEnd = FoliagePosition;
			FoliageStart.z = 2000.f;
			FoliageEnd.z= -2000.f;

			// Perform Ray Cast Collision on Client.
			CollisionResult = gClientContainer.castRay(	FoliageStart, FoliageEnd, FXFOLIAGEREPLICATOR_COLLISION_MASK, &RayEvent);

			// Did we hit anything?
			if (CollisionResult)
			{
				// For now, let's pretend we didn't get a collision.
				CollisionResult = false;

				// Yes, so get it's type.
				U32 CollisionType = RayEvent.object->getTypeMask();

				// Check Illegal Placements, fail if we hit a disallowed type.
				if (((CollisionType & TerrainObjectType) && !mFieldData.mAllowOnTerrain)	||
					((CollisionType & InteriorObjectType) && !mFieldData.mAllowOnInteriors)	||
					((CollisionType & StaticTSObjectType) && !mFieldData.mAllowStatics)	||
					((CollisionType & WaterObjectType) && !mFieldData.mAllowOnWater) ) continue;

				// If we collided with water and are not allowing on the water surface then let's find the
				// terrain underneath and pass this on as the original collision else fail.
				if ((CollisionType & WaterObjectType) && !mFieldData.mAllowWaterSurface &&
					!gClientContainer.castRay( FoliageStart, FoliageEnd, FXFOLIAGEREPLICATOR_NOWATER_COLLISION_MASK, &RayEvent)) continue;

				// We passed with flying colour so carry on.
				CollisionResult = true;
			}

			// Invalidate if we are below Allowed Terrain Angle.
			if (RayEvent.normal.z < mSin(mDegToRad(90.0f-mFieldData.mAllowedTerrainSlope))) CollisionResult = false;

		// Wait until we get a collision.
		} while(!CollisionResult && --RelocationRetry);

		// Check for Relocation Problem.
		if (RelocationRetry > 0)
		{
			// Adjust Impact point.
			RayEvent.point.z += mFieldData.mOffsetZ;

			// Set New Position.
			FoliagePosition = RayEvent.point;
		}
		else
		{
			// Warning.
			Con::warnf(ConsoleLogEntry::General, "fxFoliageReplicator - Could not find satisfactory position for Foliage!");

			// Skip to next.
			continue;
		}

		// Create our Foliage Item.
		pFoliageItem = new fxFoliageItem;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -