Exemple #1
0
void SweepTest::FindTouchedCCTs(	NxU32 nb_boxes, const NxExtendedBounds3* boxes, const void** box_user_data,
									NxU32 nb_capsules, const NxExtendedCapsule* capsules, const void** capsule_user_data,
									const NxExtendedBounds3& world_box)
{
	NxExtendedVec3 Origin;	// Will be TouchedGeom::mOffset
	world_box.getCenter(Origin);

	// Find touched boxes, i.e. other box controllers
	for(NxU32 i=0;i<nb_boxes;i++)
	{
		if(!world_box.intersect(boxes[i]))
			continue;

		TouchedUserBox* UserBox = (TouchedUserBox*)reserve(mGeomStream, sizeof(TouchedUserBox)/sizeof(NxU32));
		UserBox->mType		= TOUCHED_USER_BOX;
		UserBox->mUserData	= box_user_data[i];
		UserBox->mOffset	= Origin;
		UserBox->mBox		= boxes[i];
	}

	// Find touched capsules, i.e. other capsule controllers
	NxExtendedVec3 Center;
	NxVec3 Extents;
	world_box.getCenter(Center);
	world_box.getExtents(Extents);
	NxMat33 Idt;
	Idt.id();
	for(NxU32 i=0;i<nb_capsules;i++)
	{
		// Do a quick AABB check first, to avoid calling the SDK too much
		const NxF32 r = capsules[i].radius;
		if((capsules[i].p0.x - r > world_box.max.x) || (world_box.min.x > capsules[i].p1.x + r)) continue;
		if((capsules[i].p0.y - r > world_box.max.y) || (world_box.min.y > capsules[i].p1.y + r)) continue;
		if((capsules[i].p0.z - r > world_box.max.z) || (world_box.min.z > capsules[i].p1.z + r)) continue;

		// Do a box-capsule intersect, or skip it? => better to skip it, not really useful now
/*		NxCapsule tmp;
		tmp.radius = capsules[i].radius;
		tmp.p0.x = float(capsules[i].p0.x);
		tmp.p0.y = float(capsules[i].p0.y);
		tmp.p0.z = float(capsules[i].p0.z);
		tmp.p1.x = float(capsules[i].p1.x);
		tmp.p1.y = float(capsules[i].p1.y);
		tmp.p1.z = float(capsules[i].p1.z);
		float d2 = gUtilLib->NxSegmentOBBSqrDist(tmp, NxVec3(float(Center.x), float(Center.y), float(Center.z)), 
											Extents, 
											Idt, NULL, NULL);
		if(d2<capsules[i].radius*capsules[i].radius)*/
		{
			TouchedUserCapsule* UserCapsule = (TouchedUserCapsule*)reserve(mGeomStream, sizeof(TouchedUserCapsule)/sizeof(NxU32));
			UserCapsule->mType		= TOUCHED_USER_CAPSULE;
			UserCapsule->mUserData	= capsule_user_data[i];
			UserCapsule->mOffset	= Origin;
			UserCapsule->mCapsule	= capsules[i];
		}
	}
}
void CCTDebugData::addAABB(const NxExtendedBounds3& bounds, NxU32 color)
{
	NxExtendedVec3 center;
	NxVec3 extents;
	bounds.getCenter(center);
	bounds.getExtents(extents);

	NxBounds3 tmp;
	tmp.setCenterExtents(NxVec3((float)center.x, (float)center.y, (float)center.z), extents);

	addAABB(tmp, color, false);
}
Exemple #3
0
void SweptCapsule::ComputeTemporalBox(const SweepTest& test, NxExtendedBounds3& box, const NxExtendedVec3& center, const NxVec3& direction) const
{
	NxVec3 mExtents(mRadius, mRadius, mRadius);
	mExtents[test.mUpDirection] += mHeight*0.5f;
//mExtents *= 2.0f;

	const NxVec3 SkinExtents = mExtents + NxVec3(test.mSkinWidth, test.mSkinWidth, test.mSkinWidth);

	NxExtendedVec3 tmp = center;
	tmp += direction;

	NxExtendedBounds3 DestBox;
	DestBox.setCenterExtents(tmp, SkinExtents);

	box.setCenterExtents(center, SkinExtents);
	box.add(DestBox);
}
bool BoxController::getWorldBox(NxExtendedBounds3& box) const
	{
	box.setCenterExtents(position, extents);
	return true;
	}
Exemple #5
0
void SweepTest::UpdateTouchedGeoms(	void* user_data, const SweptVolume& swept_volume,
									NxU32 nb_boxes, const NxExtendedBounds3* boxes, const void** box_user_data,
									NxU32 nb_capsules, const NxExtendedCapsule* capsules, const void** capsule_user_data,
									NxU32 group_flags, const NxExtendedBounds3& world_box, const NxGroupsMask* groupsMask)
{
	/*
	- if this is the first iteration (new frame) we have to redo the dynamic objects & the CCTs. The static objects can
	be cached.
	- if this is not, we can cache everything
	*/

	// PT: using "world_box" instead of "mCachedTBV" seems to produce TTP 6207
//#define DYNAMIC_BOX	world_box
#define DYNAMIC_BOX	mCachedTBV

	bool NewCachedBox = false;

	// If the input box is inside the cached box, nothing to do
	if(world_box.isInside(mCachedTBV))
	{
		if(mFirstUpdate)
		{
			mFirstUpdate = false;

			// Only redo the dynamic
			mGeomStream.erase(&mGeomStream[mNbCachedStatic]);
			mWorldTriangles.erase(&mWorldTriangles[mNbCachedT]);
			mWorldEdgeNormals.erase(&mWorldEdgeNormals[mNbCachedEN]);
			mEdgeFlags.erase(&mEdgeFlags[mNbCachedF]);

			FindTouchedGeometry(user_data, DYNAMIC_BOX, mWorldTriangles, swept_volume.GetType()==SWEPT_BOX ? &mWorldEdgeNormals : NULL, mEdgeFlags, mGeomStream, group_flags, false, true, groupsMask);
			FindTouchedCCTs(
				nb_boxes, boxes, box_user_data,
				nb_capsules, capsules, capsule_user_data,
				DYNAMIC_BOX
				);
			gNbPartialUpdates++;
		}
	}
	else
	{
		NewCachedBox = true;

		// Cache BV used for the query
		mCachedTBV = world_box;

		// Grow the volume a bit. The temporal box here doesn't take sliding & collision response into account.
		// In bad cases it is possible to eventually touch a portion of space not covered by this volume. Just
		// in case, we grow the initial volume slightly. Then, additional tests are performed within the loop
		// to make sure the TBV is always correct. There's a tradeoff between the original (artificial) growth
		// of the volume, and the number of TBV recomputations performed at runtime...
		if(1)
		{
			mCachedTBV.scale(mVolumeGrowth);
		}
		else
		{
			NxExtendedVec3 center;	mCachedTBV.getCenter(center);
			NxVec3 extents;	mCachedTBV.getExtents(extents);
/*			NxVec3 scale(mVolumeGrowth, mVolumeGrowth, mVolumeGrowth);
			scale[mUpDirection] = 1.0f;*/
/*			NxVec3 scale(1.0f, 1.0f, 1.0f);
			scale[mUpDirection] = mVolumeGrowth;
			extents.x *= scale.x;
			extents.y *= scale.y;
			extents.z *= scale.z;*/
			extents.x *= 1.8f;
			extents.y += 1.0f;
			extents.z *= 1.8f;
			mCachedTBV.setCenterExtents(center, extents);
		}

		// Gather triangles touched by this box. This covers multiple meshes.
		mWorldTriangles.clear();
		mWorldEdgeNormals.clear();
		mEdgeFlags.clear();
		mGeomStream.clear();
		mCachedTriIndexIndex	= 0;
		mCachedTriIndex[0] = mCachedTriIndex[1] = mCachedTriIndex[2] = 0;

		gNbFullUpdates++;
		FindTouchedGeometry(user_data, mCachedTBV, mWorldTriangles, swept_volume.GetType()==SWEPT_BOX ? &mWorldEdgeNormals : NULL, mEdgeFlags, mGeomStream, group_flags, true, false, groupsMask);
		mNbCachedStatic = mGeomStream.size();
		mNbCachedT = mWorldTriangles.size();
		mNbCachedEN = mWorldEdgeNormals.size();
		mNbCachedF = mEdgeFlags.size();

		FindTouchedGeometry(user_data, DYNAMIC_BOX, mWorldTriangles, swept_volume.GetType()==SWEPT_BOX ? &mWorldEdgeNormals : NULL, mEdgeFlags, mGeomStream, group_flags, false, true, groupsMask);
		// We can't early exit when no tris are touched since we also have to handle the boxes

		FindTouchedCCTs(
			nb_boxes, boxes, box_user_data,
			nb_capsules, capsules, capsule_user_data,
			DYNAMIC_BOX
			);

		mFirstUpdate = false;
	}

	if(debugData)
	{
		debugData->addAABB(mCachedTBV, NewCachedBox ? NX_ARGB_RED : NX_ARGB_GREEN);
		debugData->addAABB(world_box, NX_ARGB_YELLOW);
	}
}
bool CapsuleController::getWorldBox(NxExtendedBounds3& box) const
{
//	box.setCenterExtents(position, NxVec3(radius, height, radius));
    box.setCenterExtents(position, NxVec3(radius, radius+height*0.5f, radius));
    return true;
}
bool FindTouchedGeometry(
	void* user_data,
	const NxExtendedBounds3& worldBounds,		// ### we should also accept other volumes

	TriArray& world_triangles,
	TriArray* world_edge_normals,
	IntArray& edge_flags,
	IntArray& geom_stream,

	NxU32 group_flags,
	bool static_shapes, bool dynamic_shapes, const NxGroupsMask* groupsMask)
	{
	NX_ASSERT(user_data);
	NxScene* scene = (NxScene*)user_data;

	NxExtendedVec3 Origin;	// Will be TouchedGeom::mOffset
	worldBounds.getCenter(Origin);

	// Reserve a stack buffer big enough to hold all shapes in the world. This is a lazy approach that is
	// acceptable here since the total number of shapes is limited to 64K anyway, which would "only" consume
	// 256 Kb on the stack (hence, stack overflow is unlikely).
	// ### TODO: the new callback mechanism would allow us to use less memory here
//	NxU32 total = scene->getNbStaticShapes() + scene->getNbDynamicShapes();
	NxU32 total = scene->getTotalNbShapes();
	NxShape** buffer = (NxShape**)NxAlloca(total*sizeof(NxShape*));

	// Find touched *boxes* i.e. touched objects' AABBs in the world
	// We collide against dynamic shapes too, to get back dynamic boxes/etc
	// TODO: add active groups in interface!

	NxU32 Flags = 0;
	if(static_shapes)	Flags |= NX_STATIC_SHAPES;
	if(dynamic_shapes)	Flags |= NX_DYNAMIC_SHAPES;

	// ### this one is dangerous
	NxBounds3 tmpBounds;	// LOSS OF ACCURACY
	tmpBounds.min.x = (float)worldBounds.min.x;
	tmpBounds.min.y = (float)worldBounds.min.y;
	tmpBounds.min.z = (float)worldBounds.min.z;
	tmpBounds.max.x = (float)worldBounds.max.x;
	tmpBounds.max.y = (float)worldBounds.max.y;
	tmpBounds.max.z = (float)worldBounds.max.z;
	NxU32 nbTouchedBoxes = scene->overlapAABBShapes(tmpBounds, NxShapesType(Flags), total, buffer, NULL, group_flags, groupsMask);

	// Early exit if no AABBs found
	if(!nbTouchedBoxes)	return false;
	NX_ASSERT(nbTouchedBoxes<=total);	// Else we just trashed some stack memory

	// Loop through touched world AABBs
	NxShape** touched = buffer;
	while(nbTouchedBoxes--)
		{
		// Get current shape
		NxShape* shape = *touched++;

		// Filtering

		// Discard all CCT shapes, i.e. kinematic actors we created ourselves. We don't need to collide with them since they're surrounded
		// by the real CCT volume - and collisions with those are handled elsewhere. We use the userData field for filtering because that's
		// really our only valid option (filtering groups are already used by clients and we don't have control over them, clients might
		// create other kinematic actors that we may want to keep here, etc, etc)
		if(size_t(shape->userData)=='CCTS')
			continue;

		// Discard if not collidable
		// PT: this shouldn't be possible at this point since:
		// - the SF flag is only used for compounds
		// - the AF flag is already tested in scene query
		// - we shouldn't get compound shapes here
		if(shape->getFlag(NX_SF_DISABLE_COLLISION))
			continue;

		// Ubi (EA) : Discarding Triggers :
		if ( shape->getFlag(NX_TRIGGER_ENABLE) )
			continue;

		// PT: here you might want to disable kinematic objects.

		// Output shape to stream
		NxShapeType type = shape->getType();
				if(type==NX_SHAPE_SPHERE)		outputSphereToStream((NxSphereShape*)shape, shape, geom_stream, Origin);
		else	if(type==NX_SHAPE_CAPSULE)		outputCapsuleToStream((NxCapsuleShape*)shape, shape, geom_stream, Origin);
		else	if(type==NX_SHAPE_BOX)			outputBoxToStream((NxBoxShape*)shape, shape, geom_stream, Origin);
		else	if(type==NX_SHAPE_MESH)			outputMeshToStream((NxTriangleMeshShape*)shape, shape, geom_stream, world_triangles, world_edge_normals, edge_flags, Origin, tmpBounds);
		else	if(type==NX_SHAPE_HEIGHTFIELD)	outputHeightFieldToStream((NxHeightFieldShape*)shape, shape, geom_stream, world_triangles, world_edge_normals, edge_flags, Origin, tmpBounds);
		else	if(type==NX_SHAPE_CONVEX)		outputConvexToStream((NxConvexShape*)shape, shape, geom_stream, world_triangles, world_edge_normals, edge_flags, Origin, tmpBounds);
		}

	return true;
	}