Game Development Community

Disabling culling of players

by Bryce · in Torque 3D Professional · 12/03/2012 (2:35 pm) · 6 replies

Hey everyone,

I'm looking to see if anyone knows how to disable the "edge" culling of player objects? I've noticed that whenever a player's collision box are out of camera view, the model disappears entirely. I know this has been a feature since TGE, but it's causing inappropriate culling at times, i.e. corpses disappearing when not looking directly at them.


I've got a system of takedown animations built. It's hard to tell in the video, but there are times when the victim disappears entirely from view for split seconds because of how close we are to him. You can see some small-but-noticable culling issues in the first takedown, as well as when I'm viewing the corpses at the end.

Can someone shed some light on this? Is there a way to disable culling? Is there a way to make this "render box" bigger without changing how the player collides with things? Hope I'm being clear enough.

Help is appreciated!
-Bryce

#1
12/03/2012 (4:22 pm)
Weird because all other objects seem to have a much higher margin for when they are culled out..
For making the renderbox bigger I believe you would have to make the bounding box bigger which I don't think is a good idea on player objects.

Very cool takedown animations tho! Very gj on that!
#2
12/04/2012 (1:06 am)
I have the same thing happening with decals, and only at certain angles. I think it has something to do with the viewing frustrum and the checking of objects if inside, but I haven't got any further (it's very low on my priority list right now). BTW I'm using T3D1.1 Final with 1.2 patch.
#3
12/04/2012 (6:26 am)
Corpses get culled because they are using the "standing up" tall rectangle of the player bounds.

Maybe creating a new "dead" pose setting which has it's own very wide bounds setting, and then have it automatically kick in on death.

Alternatively swap the static corpse with a TSstatic object in the final part of the death animation.
#4
12/04/2012 (7:56 am)
Anyway I don't know if you can use this or not but this is the code I use on my meshemitters (because of this) to make sure they are always rendered when necessary
//-----------------------------------------------------------------------------
// processTick
// Changed
//-----------------------------------------------------------------------------
void MeshEmitter::processTick(const Move* move)
{
	Parent::processTick(move);

	// If the object has been culled out we don't want to render the particles. 
	// If it haven't, set the bounds to global so the particles will always be rendered regardless of whether the object is seen or not.
	if(isObjectCulled)
	{
		mGlobalBounds = false;
		setRenderEnabled(false);

		if( mSceneManager )
			mSceneManager->notifyObjectDirty( this );

	}
	else
	{
		setGlobalBounds();
		setRenderEnabled(true);
	}
}

And this is an old isObjectCulled code (right now I use: state->getCullingState().isCulled(this) instead) isObjectCulled method i used:
(next comment)
#5
12/04/2012 (10:06 am)
bool RadiusMeshEmitter::isObjectCulled()
{
	PROFILE_SCOPE(rm_isObjectCulled);
	// Must have a connection and control object
	GameConnection* conn = GameConnection::getConnectionToServer();
	if (!conn) return true;
	GameBase * control = dynamic_cast<GameBase*>(conn->getControlObject());
	if (!control) return true;

	// Get control camera info
	MatrixF cam;
	Point3F camPos;
	VectorF camDir;
	//cam = conn->getCameraObject()->getTransform();
	conn->getControlCameraTransform(0,&cam);
	cam.getColumn(3, &camPos);
	cam.getColumn(1, &camDir);

	F32 camFov;
	conn->getControlCameraFov(&camFov);
	camFov = mDegToRad(camFov) / 2;

	// Visible distance info
	F32 visDistance = gClientSceneGraph->getVisibleDistance();
	F32 visDistanceSqr = visDistance * visDistance;

	// Collision info. We're going to be running LOS tests and we
	// don't want to collide with the control object.
	static U32 losMask = TerrainObjectType | InteriorObjectType | ShapeBaseObjectType;

	SimObject* SB = dynamic_cast<SimObject*>(Sim::findObject(emitMesh));
	if(!SB)
		SB = dynamic_cast<SimObject*>(Sim::findObject(atoi(emitMesh)));

	// All ghosted objects are added to the server connection group,
	// so we can find all the shape base objects by iterating through
	// our current connection.
	ShapeBase* shape = dynamic_cast< ShapeBase* >(SB);
	//GameBase* GB = dynamic_cast< GameBase* >(SB);
	TSStatic* TSshape = dynamic_cast<TSStatic*>(SB);
	if ( shape ) {
		// Target pos to test, if it's a player run the LOS to his eye
		// point, otherwise we'll grab the generic box center.
		Point3F shapePos;
		if (shape->getTypeMask() & PlayerObjectType) 
		{
			MatrixF eye;

			// Use the render eye transform, otherwise we'll see jittering
			shape->getRenderEyeTransform(&eye);
			eye.getColumn(3, &shapePos);
		} 
		else 
		{
			// Use the render transform instead of the box center
			// otherwise it'll jitter.
			MatrixF srtMat = shape->getRenderTransform();
			srtMat.getColumn(3, &shapePos);
		}
		VectorF shapeDir = shapePos - camPos;

		// Test to see if it's in range
		F32 shapeDist = shapeDir.lenSquared();
		if (shapeDist == 0 || shapeDist > visDistanceSqr)
			return true;
		shapeDist = mSqrt(shapeDist);

		// Test to see if it's within our viewcone, this test doesn't
		// actually match the viewport very well, should consider
		// projection and box test.
		shapeDir.normalize();
		F32 dot = mDot(shapeDir, camDir);
		if (dot < camFov)
			return true;

		// Don't raytest, if the object is slightly below the terrain (houses etc)
		//  - then a ray test will exclude it, ruining the effect.

		// Test to see if it's behind something, and we want to
		// ignore anything it's mounted on when we run the LOS.
		RayInfo info;
		shape->disableCollision();
		control->disableCollision();
		SceneObject *mount = shape->getObjectMount();
		if (mount)
		mount->disableCollision();
		bool los = !gClientContainer.castRay(camPos, shapePos,losMask, &info);
		shape->enableCollision();
		control->enableCollision();
		if (mount)
		mount->enableCollision();
		if (!los)
		return true;

		// The object is not culled
		return false;
	}

	else if( TSshape )
	{
		Point3F shapePos;
		// Use the render transform instead of the box center
		// otherwise it'll jitter.
		MatrixF srtMat = TSshape->getRenderTransform();
		srtMat.getColumn(3, &shapePos);

		VectorF shapeDir = shapePos - camPos;

		// Test to see if it's in range
		F32 shapeDist = shapeDir.lenSquared();
		if (shapeDist == 0 || shapeDist > visDistanceSqr)
			return true;
		shapeDist = mSqrt(shapeDist);

		// Test to see if it's within our viewcone, this test doesn't
		// actually match the viewport very well, should consider
		// projection and box test.
		shapeDir.normalize();
		F32 dot = mDot(shapeDir, camDir);
		if (dot < camFov)
			return true;

		// Don't raytest, if the object is slightly below the terrain (houses etc)
		//  - then a ray test will exclude it, ruining the effect.

		// Test to see if it's behind something, and we want to
		// ignore anything it's mounted on when we run the LOS.
		RayInfo info;
		TSshape->disableCollision();
		control->disableCollision();
		SceneObject *mount = TSshape->getObjectMount();
		if (mount)
		mount->disableCollision();
		bool los = !gClientContainer.castRay(camPos, shapePos,losMask, &info);
		TSshape->enableCollision();
		control->enableCollision();
		if (mount)
		mount->enableCollision();
		if (!los)
		return true;

		// The object is not culled
		return false;
	}
	return true;
}
#6
12/04/2012 (2:37 pm)
Not sure its related, but had this issue when exporting to DTS, exporting to collada resolved my issues with culling objects from the side view. probably totally unrelated!