void Sc::ParticleSystemSim::visualizeInteractions(Cm::RenderOutput& out)
{
	out << PxU32(PxDebugColor::eARGB_GREEN) << Cm::RenderOutput::LINES;
	for(PxU32 i=0; i < mParticlePacketShapes.size(); i++)
	{
		ParticlePacketShape* particleShape = mParticlePacketShapes[i];

		ParticleElementRbElementInteraction** interactions = particleShape->getInteractions();
		PxU32 nbInteractions = particleShape->getInteractionsCount();

		while(nbInteractions--)
		{
			ParticleElementRbElementInteraction* interaction = *interactions++;

			PX_ASSERT(interaction->getType() == InteractionType::ePARTICLE_BODY);

			const PxBounds3 bounds = particleShape->getBounds();

			PX_ALIGN(16, PxTransform absPos);
			interaction->getRbShape().getAbsPoseAligned(&absPos);

			out << bounds.getCenter() << absPos.p;
		}
	}
}
void testBoundsMesh(	
	const Gu::InternalTriangleMeshData& meshData,
	const PxTransform& world2Shape,
	const PxTransform& s2w,
	const Cm::FastVertex2ShapeScaling& meshScaling,
	bool idtScaleMesh,
	const PxBounds3& worldBounds,
	PxcContactCellMeshCallback& callback)
{
	// Find colliding triangles.
	// Setup an OBB for the fluid particle cell (in local space of shape)
	// assuming uniform scaling in most cases, using the pose as box rotation
	// if scaling is non-uniform, the bounding box is conservative

	PxBounds3 boundsInMesh;
	PX_ASSERT(!worldBounds.isEmpty());
	boundsInMesh = PxBounds3::transformFast(world2Shape, worldBounds);

	Gu::Box vertexSpaceOBB(boundsInMesh.getCenter(), boundsInMesh.getExtents(), PxMat33(PxIdentity));

	if(!idtScaleMesh)
		meshScaling.transformQueryBounds(vertexSpaceOBB.center, vertexSpaceOBB.extents);

	// Set collider flags (has to be done each time again!)
	Gu::RTreeMidphaseData hmd;
	meshData.mCollisionModel.getRTreeMidphaseData(hmd);	
	MPT_SET_CONTEXT("flui", s2w, meshScaling); PX_UNUSED(s2w);
	Gu::MeshRayCollider::collideOBB(vertexSpaceOBB, true, hmd, callback);
}
Пример #3
0
Bounds3 Bounds3::ToManaged(PxBounds3 bounds)
{
	PxVec3 center = bounds.getCenter();
	PxVec3 extents = bounds.getExtents();

	return Bounds3(MathUtil::PxVec3ToVector3(center - extents), MathUtil::PxVec3ToVector3(center + extents));
}
void physx::Pt::collideCellsWithStaticMesh(ParticleCollData* collData, const LocalCellHash& localCellHash,
                                           const GeometryUnion& meshShape, const PxTransform& world2Shape,
                                           const PxTransform& shape2World, PxReal /*cellSize*/,
                                           PxReal /*collisionRange*/, PxReal proxRadius, const PxVec3& /*packetCorner*/)
{
	PX_ASSERT(collData);
	PX_ASSERT(localCellHash.isHashValid);
	PX_ASSERT(localCellHash.numParticles <= PT_SUBPACKET_PARTICLE_LIMIT_COLLISION);
	PX_ASSERT(localCellHash.numHashEntries <= PT_LOCAL_HASH_SIZE_MESH_COLLISION);

	const PxTriangleMeshGeometryLL& meshShapeData = meshShape.get<const PxTriangleMeshGeometryLL>();

	const TriangleMesh* meshData = meshShapeData.meshData;
	PX_ASSERT(meshData);

	// mesh bounds in world space (conservative)
	const PxBounds3 shapeBounds =
	    meshData->getLocalBoundsFast().transformSafe(world2Shape.getInverse() * meshShapeData.scale);

	const bool idtScaleMesh = meshShapeData.scale.isIdentity();

	Cm::FastVertex2ShapeScaling meshScaling;
	if(!idtScaleMesh)
		meshScaling.init(meshShapeData.scale);

	// process the particle cells
	for(PxU32 c = 0; c < localCellHash.numHashEntries; c++)
	{
		const ParticleCell& cell = localCellHash.hashEntries[c];

		if(cell.numParticles == PX_INVALID_U32)
			continue;

		PxBounds3 cellBounds;

		cellBounds.setEmpty();
		PxBounds3 cellBoundsNew(PxBounds3::empty());

		PxU32* it = localCellHash.particleIndices + cell.firstParticle;
		const PxU32* end = it + cell.numParticles;
		for(; it != end; it++)
		{
			const ParticleCollData& particle = collData[*it];
			cellBounds.include(particle.oldPos);
			cellBoundsNew.include(particle.newPos);
		}
		PX_ASSERT(!cellBoundsNew.isEmpty());
		cellBoundsNew.fattenFast(proxRadius);
		cellBounds.include(cellBoundsNew);

		if(!cellBounds.intersects(shapeBounds))
			continue; // early out if (inflated) cell doesn't intersect mesh bounds

		// opcode query: cell bounds against shape bounds in unscaled mesh space
		PxcContactCellMeshCallback callback(collData, &(localCellHash.particleIndices[cell.firstParticle]),
		                                    cell.numParticles, *meshData, meshScaling, proxRadius, NULL, shape2World);
		testBoundsMesh(*meshData, world2Shape, meshScaling, idtScaleMesh, cellBounds, callback);
	}
}
Пример #5
0
PxBounds3 Sc::ClothCore::getWorldBounds() const
{
	const PxVec3& center = reinterpret_cast<const PxVec3&>(mLowLevelCloth->getBoundingBoxCenter());
	const PxVec3& extent = reinterpret_cast<const PxVec3&>(mLowLevelCloth->getBoundingBoxScale());

	PxBounds3 localBounds = PxBounds3::centerExtents(center, extent);

	PX_ASSERT(!localBounds.isEmpty());
	return PxBounds3::transformFast(getGlobalPose(), localBounds);
}
void physx::Pt::collideWithStaticHeightField(ParticleCollData* particleCollData, PxU32 numCollData,
                                             const GeometryUnion& heightFieldShape, PxReal proxRadius,
                                             const PxTransform& shape2World)
{
	PX_ASSERT(particleCollData);

	const PxHeightFieldGeometryLL& hfGeom = heightFieldShape.get<const PxHeightFieldGeometryLL>();
	const HeightFieldUtil hfUtil(hfGeom);

	for(PxU32 p = 0; p < numCollData; p++)
	{
		ParticleCollData& collData = particleCollData[p];

		PxBounds3 particleBounds = PxBounds3::boundsOfPoints(collData.localOldPos, collData.localNewPos);
		PX_ASSERT(!particleBounds.isEmpty());
		particleBounds.fattenFast(proxRadius);

		HeightFieldAabbTest test(particleBounds, hfUtil);
		HeightFieldAabbTest::Iterator itBegin = test.begin();
		HeightFieldAabbTest::Iterator itEnd = test.end();
		PxVec3 triangle[3];

		collData.localDcNum = 0.0f;
		collData.localSurfaceNormal = PxVec3(0);
		collData.localSurfacePos = PxVec3(0);
		bool hasCC = (collData.localFlags & ParticleCollisionFlags::CC) > 0;

		PxVec3 tmpSurfaceNormal(0.0f);
		PxVec3 tmpSurfacePos(0.0f);
		PxVec3 tmpProxSurfaceNormal(0.0f);
		PxVec3 tmpProxSurfacePos(0.0f);
		PxReal tmpCCTime(collData.ccTime);
		PxReal tmpDistOldToSurface(0.0f);

		for(HeightFieldAabbTest::Iterator it = itBegin; it != itEnd; ++it)
		{
			it.getTriangleVertices(triangle);

			const PxVec3& origin = triangle[0];
			PxVec3 e0, e1;
			e0 = triangle[1] - origin;
			e1 = triangle[2] - origin;

			PxU32 tmpFlags =
			    collideWithMeshTriangle(tmpSurfaceNormal, tmpSurfacePos, tmpProxSurfaceNormal, tmpProxSurfacePos,
			                            tmpCCTime, tmpDistOldToSurface, collData.localOldPos, collData.localNewPos,
			                            origin, e0, e1, hasCC, collData.restOffset, proxRadius);

			updateCollShapeData(collData, hasCC, tmpFlags, tmpCCTime, tmpDistOldToSurface, tmpSurfaceNormal,
			                    tmpSurfacePos, tmpProxSurfaceNormal, tmpProxSurfacePos, shape2World);
		}
	}
}
Пример #7
0
PxBounds3 RTree::refitAll(CallbackRefit& cb)
{
	PxU8* treeNodes8 = PX_IS_X64 ? CAST_U8(get64BitBasePage()) : CAST_U8((mFlags & IS_DYNAMIC) ? NULL : mPages);
	PxBounds3 meshBounds = refitRecursive(treeNodes8, 0, NULL, 0, cb);
	for (PxU32 j = 1; j<mNumRootPages; j++)
		meshBounds.include(   refitRecursive(treeNodes8, j, NULL, 0, cb)   );

#ifdef PX_CHECKED
	validate(&cb);
#endif
	return meshBounds;
}
Пример #8
0
PxBounds3 NpCloth::getWorldBounds(float inflation) const
{
	NP_READ_CHECK(NpActor::getOwnerScene(*this));

	const PxBounds3 bounds = mCloth.getWorldBounds();
	PX_ASSERT(bounds.isValid());

	// PT: unfortunately we can't just scale the min/max vectors, we need to go through center/extents.
	const PxVec3 center = bounds.getCenter();
	const PxVec3 inflatedExtents = bounds.getExtents() * inflation;
	return PxBounds3::centerExtents(center, inflatedExtents);
}
Пример #9
0
void NpSpatialIndex::overlap(const PxBounds3& aabb, 
							 PxSpatialOverlapCallback& callback) const
{
	PX_SIMD_GUARD;
	PX_CHECK_AND_RETURN(aabb.isValid(),			"PxSpatialIndex::overlap: aabb is not valid.");

	flushUpdates();
	OverlapCallback cb(callback);
	PxBoxGeometry boxGeom(aabb.getExtents());
	PxTransform xf(aabb.getCenter());
	Sq::ShapeData shapeData(boxGeom, xf, 0.0f); // temporary rvalue not compatible with PX_NOCOPY 
	mPruner->overlap(shapeData, cb);
}
Пример #10
0
PxBounds3 NpArticulation::getWorldBounds(float inflation) const
{
	NP_READ_CHECK(getOwnerScene());
	PxBounds3 bounds = PxBounds3::empty();

	for(PxU32 i=0; i < mArticulationLinks.size(); i++)
	{
		bounds.include(mArticulationLinks[i]->getWorldBounds());
	}
	PX_ASSERT(bounds.isValid());

	// PT: unfortunately we can't just scale the min/max vectors, we need to go through center/extents.
	const PxVec3 center = bounds.getCenter();
	const PxVec3 inflatedExtents = bounds.getExtents() * inflation;
	return PxBounds3::centerExtents(center, inflatedExtents);
}
Пример #11
0
bool AABBTreeOfVerticesBuilder::ComputeGlobalBox(const PxU32* primitives, PxU32 nb_prims, PxBounds3& global_box) const
{
	// Checkings
	if(!primitives || !nb_prims)	return false;

	// Initialize global box
	global_box.setEmpty();

	// Loop through vertices
	for(PxU32 i=0;i<nb_prims;i++)
	{
		// Update global box
		global_box.include(mVertexArray[primitives[i]]);
	}
	return true;
}
static void tessellateTriangle(PxU32& nbNewTris, const PxTriangle& tr, PxU32 index, TriArray& worldTriangles, IntArray& triIndicesArray, const PxBounds3& cullingBox, const CCTParams& params, PxU16& nbTessellation)
{
	TessParams tp;
	tp.nbNewTris			= 0;
	tp.index				= index;
	tp.worldTriangles		= &worldTriangles;
	tp.triIndicesArray		= &triIndicesArray;
	tp.cullingBoxCenter		= cullingBox.getCenter();
	tp.cullingBoxExtents	= cullingBox.getExtents();
	tp.maxEdgeLength2		= params.mMaxEdgeLength2;
	tp.nbTessellation		= 0;
	tessellateTriangle(&tp, tr.verts[0], tr.verts[1], tr.verts[2]);

	nbNewTris += tp.nbNewTris;
	nbTessellation += tp.nbTessellation;
//	nbTessellation += PxU16(tp.nbNewTris);
}
Пример #13
0
PxBounds3 RTree::refitRecursive(PxU8* treeNodes8, PxU32 top, RTreePage* parentPage, PxU32 parentSubIndex, CallbackRefit& cb)
{
	const PxReal eps = RTREE_INFLATION_EPSILON;
	RTreePage* tn = (RTreePage*)(treeNodes8 + top);
	PxBounds3 pageBound;
	for (PxU32 i = 0; i < RTREE_PAGE_SIZE; i++)
	{
		if (tn->isEmpty(i))
			continue;
		PxU32 ptr = tn->ptrs[i];
		Vec3V childMn, childMx;
		PxBounds3 childBound;
		if (ptr & 1)
		{
			// (ptr-1) clears the isLeaf bit (lowest bit)
			cb.recomputeBounds(ptr-1, childMn, childMx); // compute the bound around triangles
			V3StoreU(childMn, childBound.minimum);
			V3StoreU(childMx, childBound.maximum);
			// AP: doesn't seem worth vectorizing because of transposed layout
			tn->minx[i] = childBound.minimum.x - eps; // update page bounds for this leaf
			tn->miny[i] = childBound.minimum.y - eps;
			tn->minz[i] = childBound.minimum.z - eps;
			tn->maxx[i] = childBound.maximum.x + eps;
			tn->maxy[i] = childBound.maximum.y + eps;
			tn->maxz[i] = childBound.maximum.z + eps;
		} else
			childBound = refitRecursive(treeNodes8, ptr, tn, i, cb);
		if (i == 0)
			pageBound = childBound;
		else
			pageBound.include(childBound);
	}

	if (parentPage)
	{
		parentPage->minx[parentSubIndex] = pageBound.minimum.x - eps;
		parentPage->miny[parentSubIndex] = pageBound.minimum.y - eps;
		parentPage->minz[parentSubIndex] = pageBound.minimum.z - eps;
		parentPage->maxx[parentSubIndex] = pageBound.maximum.x + eps;
		parentPage->maxy[parentSubIndex] = pageBound.maximum.y + eps;
		parentPage->maxz[parentSubIndex] = pageBound.maximum.z + eps;
	}

	return pageBound;
}
Пример #14
0
void NpSpatialIndex::update(PxSpatialIndexItemId id,
							const PxBounds3& bounds)
{
	PX_SIMD_GUARD;
	PX_CHECK_AND_RETURN(bounds.isValid(),		"PxSpatialIndex::update: bounds are not valid.");

	mPruner->updateObjects(&id, &bounds);
	mPendingUpdates = true;
}
Пример #15
0
void NpSpatialIndex::sweep(const PxBounds3& aabb, 
						   const PxVec3& unitDir, 
						   PxReal maxDist, 
						   PxSpatialLocationCallback& callback) const
{
	PX_SIMD_GUARD;

	PX_CHECK_AND_RETURN(aabb.isValid(),									"PxSpatialIndex::sweep: aabb is not valid.");
	PX_CHECK_AND_RETURN(unitDir.isFinite() && unitDir.isNormalized(),	"PxSpatialIndex::sweep: unitDir is not valid.");
	PX_CHECK_AND_RETURN(maxDist > 0.0f,									"PxSpatialIndex::sweep: distance must be positive");

	flushUpdates();
	LocationCallback cb(callback);
	PxBoxGeometry boxGeom(aabb.getExtents());
	PxTransform xf(aabb.getCenter());
	Sq::ShapeData shapeData(boxGeom, xf, 0.0f); // temporary rvalue not compatible with PX_NOCOPY 
	mPruner->sweep(shapeData, unitDir, maxDist, cb);
}
static bool computeMassAndDiagInertia(Ext::InertiaTensorComputer& inertiaComp, 
		PxVec3& diagTensor, PxQuat& orient, PxReal& massOut, PxVec3& coM, bool lockCOM, const PxRigidBody& body, const char* errorStr)
{
	// The inertia tensor and center of mass is relative to the actor at this point. Transform to the
	// body frame directly if CoM is specified, else use computed center of mass
	if (lockCOM)
	{
		inertiaComp.translate(-coM);  // base the tensor on user's desired center of mass.
	}
	else
	{
		//get center of mass - has to be done BEFORE centering.
		coM = inertiaComp.getCenterOfMass();

		//the computed result now needs to be centered around the computed center of mass:
		inertiaComp.center();
	}
	// The inertia matrix is now based on the body's center of mass desc.massLocalPose.p
	
	massOut = inertiaComp.getMass();
	diagTensor = PxDiagonalize(inertiaComp.getInertia(), orient);

	if ((diagTensor.x > 0.0f) && (diagTensor.y > 0.0f) && (diagTensor.z > 0.0f))
		return true;
	else
	{
		Ps::getFoundation().error(PxErrorCode::eDEBUG_WARNING, __FILE__, __LINE__, 
								"%s: inertia tensor has negative components (ill-conditioned input expected). Approximation for inertia tensor will be used instead.", errorStr);

		// keep center of mass but use the AABB as a crude approximation for the inertia tensor
		PxBounds3 bounds = body.getWorldBounds();
		PxTransform pose = body.getGlobalPose();
		bounds = PxBounds3::transformFast(pose.getInverse(), bounds);
		Ext::InertiaTensorComputer it(false);
		it.setBox(bounds.getExtents());
		it.scaleDensity(massOut / it.getMass());
		PxMat33 inertia = it.getInertia();
		diagTensor = PxVec3(inertia.column0.x, inertia.column1.y, inertia.column2.z);
		orient = PxQuat(PxIdentity);

		return true;
	}
}
Пример #17
0
void Sc::ParticleSystemSim::visualizeInteractions(Cm::RenderOutput& out)
{
	out << PxU32(PxDebugColor::eARGB_GREEN) << Cm::RenderOutput::LINES;
	for(PxU32 i=0; i < mParticlePacketShapes.size(); i++)
	{
		ParticlePacketShape* particleShape = mParticlePacketShapes[i];

		Cm::Range<ParticleElementRbElementInteraction*const> interactions = particleShape->getPacketShapeInteractions();
		for (; !interactions.empty(); interactions.popFront())
		{
			ParticleElementRbElementInteraction*const interaction = interactions.front();

			PX_ASSERT(interaction->getType() == PX_INTERACTION_TYPE_PARTICLE_BODY);

			PxBounds3 bounds = particleShape->getBounds();
			out << bounds.getCenter() << interaction->getRbShape().getAbsPose().p;
		}
	}
}
Пример #18
0
void Sc::ParticleSystemSim::visualizeSpatialGrid(Cm::RenderOutput& out)
{
	PxReal packetSize = getCore().getGridSize();

	for (PxU32 i = 0; i < mParticlePacketShapes.size(); i++)
	{
		ParticlePacketShape* particleShape = mParticlePacketShapes[i];

		PxBounds3 bounds = particleShape->getBounds();
		PxVec3 centerGridSpace = bounds.getCenter() / packetSize;		
		
		for (PxU32 d = 0; d < 3; d++)
			bounds.minimum[d] = Ps::floor(centerGridSpace[d]) * packetSize;
		for (PxU32 d = 0; d < 3; d++)
			bounds.maximum[d] = Ps::ceil(centerGridSpace[d]) * packetSize;

		out << PxU32(PxDebugColor::eARGB_BLUE) << Cm::DebugBox(bounds);
	}
}
Пример #19
0
void obj_DroppedItem::UpdateObjectPositionAfterCreation()
{
	if(!PhysicsObject)
		return;

	PxActor* actor = PhysicsObject->getPhysicsActor();
	if(!actor)
		return;

	PxBounds3 pxBbox = actor->getWorldBounds();
	PxVec3 pxCenter = pxBbox.getCenter();

	// place object on the ground, to prevent excessive bouncing
	{
		PxRaycastHit hit;
		PxSceneQueryFilterData filter(PxFilterData(COLLIDABLE_STATIC_MASK, 0, 0, 0), PxSceneQueryFilterFlag::eSTATIC);
		if(g_pPhysicsWorld->raycastSingle(PxVec3(pxCenter.x, pxCenter.y, pxCenter.z), PxVec3(0, -1, 0), 50.0f, PxSceneQueryFlag::eIMPACT, hit, filter))
		{
			SetPosition(r3dPoint3D(hit.impact.x, hit.impact.y+0.1f, hit.impact.z));
		}
	}
}
Пример #20
0
PxSpatialIndexItemId NpSpatialIndex::insert(PxSpatialIndexItem& item,
										    const PxBounds3& bounds)
{
	PX_SIMD_GUARD;
	PX_CHECK_AND_RETURN_VAL(bounds.isValid(),		"PxSpatialIndex::insert: bounds are not valid.", PX_SPATIAL_INDEX_INVALID_ITEM_ID);

	Sq::PrunerHandle output;
	Sq::PrunerPayload payload;
	payload.data[0] = reinterpret_cast<size_t>(&item);
	mPruner->addObjects(&output, &bounds, &payload);
	mPendingUpdates = true;
	return output;
}
void FDestructibleMeshEditorViewportClient::Draw( const FSceneView* View,FPrimitiveDrawInterface* PDI )
{
	FEditorViewportClient::Draw(View, PDI);

#if WITH_APEX
	const bool DrawChunkMarker = true;

	UDestructibleComponent* Comp = PreviewDestructibleComp.Get();
	
	if (Comp)
	{
		if (Comp->DestructibleMesh != NULL && Comp->DestructibleMesh->FractureSettings != NULL)
		{
			if (Comp->DestructibleMesh->ApexDestructibleAsset != NULL)
			{
				NxDestructibleAsset* Asset = Comp->DestructibleMesh->ApexDestructibleAsset;
				const NxRenderMeshAsset* RenderMesh = Asset->getRenderMeshAsset();

				for (uint32 i=0; i < Asset->getChunkCount(); ++i)
				{
					int32 PartIdx = Asset->getPartIndex(i);
					int32 BoneIdx = i+1;

					if ( SelectedChunkIndices.Contains(i) )
					{
						PxBounds3 PBounds = RenderMesh->getBounds(PartIdx);

						FVector Center = P2UVector(PBounds.getCenter()) + Comp->GetBoneLocation(Comp->GetBoneName(BoneIdx));
						FVector Extent = P2UVector(PBounds.getExtents());

						FBox Bounds(Center - Extent, Center + Extent);
						DrawWireBox(PDI, Bounds, FColor::Blue, SDPG_World);
					}
				}
			}
		}
	}
#endif // WITH_APEX
}
Пример #22
0
void ApexParticles::CreateEmitter(NxApexSDK* gApexSDK, NxApexScene* gApexScene)
{
    NxApexEmitterAsset* emitterAsset;
    physx::apex::NxApexAsset* asset = reinterpret_cast<physx::apex::NxApexAsset*>(gApexSDK->getNamedResourceProvider()->getResource(NX_APEX_EMITTER_AUTHORING_TYPE_NAME, "testSpriteEmitter4ParticleFluidIos"));
    if (asset)
    {
        emitterAsset = static_cast<NxApexEmitterAsset*> (asset);
    }
    //NxApexEmitterAsset* emitterAsset = static_cast<NxApexEmitterAsset*> (gApexSDK->createAsset(asParams, "testMeshEmitter4ParticleIos.apb"));
    gApexSDK->forceLoadAssets();

    NxParameterized::Interface* descParams = emitterAsset->getDefaultActorDesc();
    PX_ASSERT(descParams);
    if (!descParams)
    {
        return;
    }

    // Set Actor pose
    //NxParameterized::setParamMat44( *descParams, "initialPose", pose );
    NxApexEmitterActor* emitterActor;
    if(descParams->areParamsOK())
    {
        emitterActor = static_cast<NxApexEmitterActor*>(emitterAsset->createApexActor(*descParams,*gApexScene));
        if(emitterActor)
        {
            emitterActor->setCurrentPosition(PxVec3(0.0f, 1.0f, 0.0f));
            emitterActor->startEmit( true );
            //emitterActor->setLifetimeRange(physx::apex::NxRange<PxF32>(1,5));
            //emitterActor->setRateRange(physx::apex::NxRange<PxF32>(10, 10));
        }
    }

    PxBounds3 b;
    b.setInfinite();

    mRenderVolume = mIofxModule->createRenderVolume(*gApexScene, b, 0, true );
    emitterActor->setPreferredRenderVolume( mRenderVolume );
}
Пример #23
0
bool AABBTreeOfAABBsBuilder::ComputeGlobalBox(const PxU32* primitives, PxU32 nb_prims, PxBounds3& global_box) const
{
	// Checkings
	if(!primitives || !nb_prims)	return false;

	// Initialize global box
	global_box = mAABBArray[primitives[0]];

	// Loop through boxes
	for(PxU32 i=1;i<nb_prims;i++)
	{
		// Update global box
		global_box.include(mAABBArray[primitives[i]]);
	}
	return true;
}
void EmitterGeomSphereShellImpl::computeFillPositions(physx::Array<PxVec3>& positions,
        physx::Array<PxVec3>& velocities,
        const PxTransform& pose,
		const PxVec3& scale,
        float objRadius,
        PxBounds3& outBounds,
        QDSRand&) const
{
	PX_UNUSED(scale);

	const float bigRadius = *mRadius + *mShellThickness;
	const float radiusSquared = bigRadius * bigRadius;
	const float hemisphere = *mHemisphere;
	const float sphereCapBaseHeight = -bigRadius + 2 * bigRadius * hemisphere;
	const float sphereCapBaseRadius = PxSqrt(radiusSquared - sphereCapBaseHeight * sphereCapBaseHeight);
	const float horizontalExtents = hemisphere < 0.5f ? bigRadius : sphereCapBaseRadius;

	// we're not doing anything with the velocities array
	PX_UNUSED(velocities);

	// we don't want anything outside the emitter
	uint32_t numX = (uint32_t)PxFloor(horizontalExtents / objRadius);
	numX -= numX % 2;
	uint32_t numY = (uint32_t)PxFloor((bigRadius - sphereCapBaseHeight) / objRadius);
	numY -= numY % 2;
	uint32_t numZ = (uint32_t)PxFloor(horizontalExtents / objRadius);
	numZ -= numZ % 2;

	for (float x = -(numX * objRadius); x <= bigRadius - objRadius; x += 2 * objRadius)
	{
		for (float y = -(numY * objRadius); y <= bigRadius - objRadius; y += 2 * objRadius)
		{
			for (float z = -(numZ * objRadius); z <= bigRadius - objRadius; z += 2 * objRadius)
			{
				const float magnitudeSquare = PxVec3(x, y, z).magnitudeSquared();
				if ((magnitudeSquare > (*mRadius + objRadius) * (*mRadius + objRadius)) &&
				        (magnitudeSquare < (bigRadius - objRadius) * (bigRadius - objRadius)))
				{
					positions.pushBack(pose.transform(PxVec3(x, y, z)));
					outBounds.include(positions.back());
				}
			}
		}
	}
}
Пример #25
0
static PX_FORCE_INLINE bool planesAABBOverlap(const PxBounds3& a, const PxPlane* p, PxU32& out_clip_mask, PxU32 in_clip_mask)
	{
		//------------------------------------------------------------------------
		// Convert the AABB from (minimum,maximum) form into (center,half-diagonal).
		// Note that we could get rid of these six subtractions and three
		// multiplications if the AABB was originally expressed in (center,
		// half-diagonal) form.
		//------------------------------------------------------------------------

		PxVec3 m = a.getCenter();		// get center of AABB ((minimum+maximum)*0.5f)
		PxVec3 d = a.maximum;	d-=m;	// get positive half-diagonal (maximum - center)

		//------------------------------------------------------------------------
		// Evaluate through all active frustum planes. We determine the relation 
		// between the AABB and a plane by using the concept of "near" and "far"
		// vertices originally described by Zhang (and later by Moeller). Our
		// variant here uses 3 fabs ops, 6 muls, 7 adds and two floating point
		// comparisons per plane. The routine early-exits if the AABB is found
		// to be outside any of the planes. The loop also constructs a new output
		// clip mask. Most FPUs have a native single-cycle fabsf() operation.
		//------------------------------------------------------------------------

		PxU32 Mask				= 1;			// current mask index (1,2,4,8,..)
		PxU32 TmpOutClipMask	= 0;			// initialize output clip mask into empty. 

		while(Mask<=in_clip_mask)				// keep looping while we have active planes left...
		{
			if(in_clip_mask & Mask)				// if clip plane is active, process it..
			{               
				const float NP = d.x*PxAbs(p->n.x) + d.y*PxAbs(p->n.y) + d.z*PxAbs(p->n.z);
				const float MP = m.x*p->n.x + m.y*p->n.y + m.z*p->n.z + p->d;

				if(NP < MP)						// near vertex behind the clip plane... 
					return false;				// .. so there is no intersection..
				if((-NP) < MP)					// near and far vertices on different sides of plane..
					TmpOutClipMask |= Mask;		// .. so update the clip mask...
			}
			Mask+=Mask;							// mk = (1<<plane)
			p++;								// advance to next plane
		}

		out_clip_mask = TmpOutClipMask;			// copy output value (temp used to resolve aliasing!)
		return true;							// indicate that AABB intersects frustum
	}
Пример #26
0
void CreateParticleAABB(ParticleData& particleData, const PxBounds3& aabb, const PxVec3& vel, float distance)
{
	PxVec3 aabbDim = aabb.getExtents() * 2.0f;

	unsigned sideNumX = (unsigned)PxMax(1.0f, physx::shdfnd::floor(aabbDim.x / distance));
	unsigned sideNumY = (unsigned)PxMax(1.0f, physx::shdfnd::floor(aabbDim.y / distance));
	unsigned sideNumZ = (unsigned)PxMax(1.0f, physx::shdfnd::floor(aabbDim.z / distance));

	for(unsigned i=0; i<sideNumX; i++)
		for(unsigned j=0; j<sideNumY; j++)
			for(unsigned k=0; k<sideNumZ; k++)
			{
				if(particleData.numParticles >= particleData.maxParticles) 
					break;

				PxVec3 p = PxVec3(i*distance,j*distance,k*distance);
				p += aabb.minimum;

				particleData.positions[particleData.numParticles] = p;
				particleData.velocities[particleData.numParticles] = vel;
				particleData.numParticles++;
			}
}
Пример #27
0
PxU32 PxBroadPhaseExt::createRegionsFromWorldBounds(PxBounds3* regions, const PxBounds3& globalBounds, PxU32 nbSubdiv, PxU32 upAxis)
{
	PX_CHECK_MSG(globalBounds.isValid(), "PxBroadPhaseExt::createRegionsFromWorldBounds(): invalid bounds provided!");
	PX_CHECK_MSG(upAxis<3, "PxBroadPhaseExt::createRegionsFromWorldBounds(): invalid up-axis provided!");

	const PxVec3& min = globalBounds.minimum;
	const PxVec3& max = globalBounds.maximum;
	const float dx = (max.x - min.x) / float(nbSubdiv);
	const float dy = (max.y - min.y) / float(nbSubdiv);
	const float dz = (max.z - min.z) / float(nbSubdiv);
	PxU32 nbRegions = 0;
	PxVec3 currentMin, currentMax;
	for(PxU32 j=0;j<nbSubdiv;j++)
	{
		for(PxU32 i=0;i<nbSubdiv;i++)
		{
			if(upAxis==0)
			{
				currentMin = PxVec3(min.x, min.y + dy * float(i),   min.z + dz * float(j));
				currentMax = PxVec3(max.x, min.y + dy * float(i+1), min.z + dz * float(j+1));
			}
			else if(upAxis==1)
			{
				currentMin = PxVec3(min.x + dx * float(i),   min.y, min.z + dz * float(j));
				currentMax = PxVec3(min.x + dx * float(i+1), max.y, min.z + dz * float(j+1));
			}
			else if(upAxis==2)
			{
				currentMin = PxVec3(min.x + dx * float(i),   min.y + dy * float(j), min.z);
				currentMax = PxVec3(min.x + dx * float(i+1), min.y + dy * float(j+1), max.z);
			}

			regions[nbRegions++] = PxBounds3(currentMin, currentMax);
		}
	}
	return nbRegions;
}
bool Character::buildMotion(Acclaim::AMCData &amcData, Motion &motion, PxU32 start, PxU32 end)
{
	using namespace Acclaim;

	if  (mASFData == NULL)
		return false;

	motion.mNbFrames = end - start + 1;
	motion.mMotionData = SAMPLE_NEW(MotionData)[motion.mNbFrames];

	// compute bounds of all the motion data on normalized frame
	PxBounds3 bounds = PxBounds3::empty();
	for (PxU32 i = start; i < end; i++)
	{
		Acclaim::FrameData &frameData = amcData.mFrameData[i];

		PxTransform rootTransform(PxVec3(0.0f), EulerAngleToQuat(frameData.mRootOrientation));

		for (PxU32 j = 0; j < mASFData->mNbBones; j++)
		{
			PxTransform t = computeBoneTransform(rootTransform, mASFData->mBones[j], frameData.mBoneFrameData);
			bounds.include(t.p);
		}
	}

	Acclaim::FrameData& firstFrame = amcData.mFrameData[0];
	Acclaim::FrameData& lastFrame = amcData.mFrameData[amcData.mNbFrames-1];

	// compute direction vector
	motion.mDistance = mCharacterScale * (lastFrame.mRootPosition - firstFrame.mRootPosition).magnitude();

	PxVec3 firstPosition = firstFrame.mRootPosition;
	PX_UNUSED(firstPosition);
	PxVec3 firstAngles = firstFrame.mRootOrientation;
	PxQuat firstOrientation = EulerAngleToQuat(PxVec3(0, firstAngles.y, 0));

	for (PxU32 i = 0; i < motion.mNbFrames; i++)
	{
		Acclaim::FrameData& frameData = amcData.mFrameData[i+start];
		MotionData &motionData = motion.mMotionData[i];

		// normalize y-rot by computing inverse quat from first frame
		// this makes all the motion aligned in the same (+ z) direction.
		PxQuat currentOrientation = EulerAngleToQuat(frameData.mRootOrientation);
		PxQuat qdel = firstOrientation.getConjugate() * currentOrientation;
		PxTransform rootTransform(PxVec3(0.0f), qdel);
		
		for (PxU32 j = 0; j < mNbBones; j++)
		{
			PxTransform boneTransform = computeBoneTransform(rootTransform, mASFData->mBones[j], frameData.mBoneFrameData);
			motionData.mBoneTransform[j] = boneTransform;
		}

		//PxReal y = mCharacterScale * (frameData.mRootPosition.y - firstPosition.y) - bounds.minimum.y;
		motionData.mRootTransform = PxTransform(PxVec3(0.0f, -bounds.minimum.y, 0.0f), PxQuat(PxIdentity));
	}

	// now make the motion cyclic by linear interpolating root position and joint angles
	const PxU32 windowSize = 10;
	for (PxU32 i = 0; i <= windowSize; i++)
	{
		PxU32 j = motion.mNbFrames - 1 - windowSize + i;

		PxReal t = PxReal(i) / PxReal(windowSize);

		MotionData& motion_i = motion.mMotionData[0];
		MotionData& motion_j = motion.mMotionData[j];

		// lerp root translation
		PxVec3 blendedRootPos = (1.0f - t) * motion_j.mRootTransform.p  + t * motion_i.mRootTransform.p;
		for (PxU32 k = 0; k < mNbBones; k++)
		{
			PxVec3 pj = motion_j.mRootTransform.p + motion_j.mBoneTransform[k].p;
			PxVec3 pi = motion_i.mRootTransform.p + motion_i.mBoneTransform[k].p;

			PxVec3 p = (1.0f - t) * pj + t * pi;
			motion_j.mBoneTransform[k].p = p - blendedRootPos;
		}
		motion_j.mRootTransform.p = blendedRootPos;
	}

	return true;
}
void Cct::findTouchedGeometry(
	const InternalCBData_FindTouchedGeom* userData,
	const PxExtendedBounds3& worldBounds,		// ### we should also accept other volumes

	TriArray& worldTriangles,
	IntArray& triIndicesArray,
	IntArray& geomStream,

	const CCTFilter& filter,
	const CCTParams& params)
{
	PX_ASSERT(userData);
	
	const PxInternalCBData_FindTouchedGeom* internalData = static_cast<const PxInternalCBData_FindTouchedGeom*>(userData);
	PxScene* scene = internalData->scene;
	Cm::RenderBuffer* renderBuffer = internalData->renderBuffer;

	PxExtendedVec3 Origin;	// Will be TouchedGeom::mOffset
	getCenter(worldBounds, Origin);

	// 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!
	PxSceneQueryFilterFlags sqFilterFlags;
	if(filter.mStaticShapes)	sqFilterFlags |= PxSceneQueryFilterFlag::eSTATIC;
	if(filter.mDynamicShapes)	sqFilterFlags |= PxSceneQueryFilterFlag::eDYNAMIC;
	if(filter.mFilterCallback)
	{
		if(filter.mPreFilter)
			sqFilterFlags |= PxSceneQueryFilterFlag::ePREFILTER;
		if(filter.mPostFilter)
			sqFilterFlags |= PxSceneQueryFilterFlag::ePOSTFILTER;
	}

	// ### this one is dangerous
	const PxBounds3 tmpBounds(toVec3(worldBounds.minimum), toVec3(worldBounds.maximum));	// LOSS OF ACCURACY

	// PT: unfortunate conversion forced by the PxGeometry API
	PxVec3 center = tmpBounds.getCenter(), extents = tmpBounds.getExtents();

	PxShape* hits[100];
	PxU32 size = 100;

	const PxSceneQueryFilterData sceneQueryFilterData = filter.mFilterData ? PxSceneQueryFilterData(*filter.mFilterData, sqFilterFlags) : PxSceneQueryFilterData(sqFilterFlags);

	PxI32 numberHits = scene->overlapMultiple(PxBoxGeometry(extents), PxTransform(center), hits, size, sceneQueryFilterData, filter.mFilterCallback);
	
	for(PxI32 i = 0; i < numberHits; i++)
	{
		PxShape* shape = hits[i];
		if(shape == NULL)
			continue;

		// 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(internalData->cctShapeHashSet->contains(shape))
			continue;

		// Ubi (EA) : Discarding Triggers :
		if(shape->getFlags() & PxShapeFlag::eTRIGGER_SHAPE)
			continue;

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

		// Output shape to stream
		const PxTransform globalPose = getShapeGlobalPose(*shape);

		const PxGeometryType::Enum type = shape->getGeometryType();	// ### VIRTUAL!
		if(type==PxGeometryType::eSPHERE)				outputSphereToStream(shape, globalPose, geomStream, Origin);
		else	if(type==PxGeometryType::eCAPSULE)		outputCapsuleToStream(shape, globalPose, geomStream, Origin);
		else	if(type==PxGeometryType::eBOX)			outputBoxToStream(shape, globalPose, geomStream, worldTriangles, triIndicesArray, Origin, tmpBounds, params, renderBuffer);
		else	if(type==PxGeometryType::eTRIANGLEMESH)	outputMeshToStream(shape, globalPose, geomStream, worldTriangles, triIndicesArray, Origin, tmpBounds, params, renderBuffer);
		else	if(type==PxGeometryType::eHEIGHTFIELD)	outputHeightFieldToStream(shape, globalPose, geomStream, worldTriangles, triIndicesArray, Origin, tmpBounds, params, renderBuffer);
		else	if(type==PxGeometryType::eCONVEXMESH)	outputConvexToStream(shape, globalPose, geomStream, worldTriangles, triIndicesArray, Origin, tmpBounds);
		else	if(type==PxGeometryType::ePLANE)		outputPlaneToStream(shape, globalPose, geomStream, worldTriangles, triIndicesArray, Origin, tmpBounds, params, renderBuffer);
	}
}
static void outputHeightFieldToStream(	PxShape* hfShape, const PxTransform& heightfieldPose, IntArray& geomStream, TriArray& worldTriangles, IntArray& triIndicesArray,
										const PxExtendedVec3& origin, const PxBounds3& tmpBounds, const CCTParams& params, Cm::RenderBuffer* renderBuffer)
{
	PX_ASSERT(hfShape->getGeometryType() == PxGeometryType::eHEIGHTFIELD);
	// Do AABB-mesh query

	PxHeightFieldGeometry hfGeom;
	hfShape->getHeightFieldGeometry(hfGeom);

	PxBoxGeometry boxGeom(tmpBounds.getExtents());
	PxTransform boxPose;
	boxPose.p = tmpBounds.getCenter();
	boxPose.q = PxQuat::createIdentity();

	// Collide AABB against current heightfield
	PxFindOverlapTriangleMeshUtil overlapUtil;
	const PxU32 nbTouchedTris = overlapUtil.findOverlap(boxGeom, boxPose, hfGeom, heightfieldPose);

	const PxVec3 offset(float(-origin.x), float(-origin.y), float(-origin.z));

	TouchedMesh* touchedMesh			= (TouchedMesh*)reserve(geomStream, sizeof(TouchedMesh)/sizeof(PxU32));
	touchedMesh->mType					= TouchedGeomType::eMESH; // ptchernev: seems to work
	touchedMesh->mUserData				= hfShape;
	touchedMesh->mOffset				= origin;
	touchedMesh->mNbTris				= nbTouchedTris;
	touchedMesh->mIndexWorldTriangles	= worldTriangles.size();

	const PxU32* PX_RESTRICT indices = overlapUtil.getResults();

	if(params.mSlopeLimit!=0.0f)
	{
		// Reserve memory for incoming triangles
//		PxTriangle* TouchedTriangles = reserve(worldTriangles, nbTouchedTris);

		// Loop through touched triangles
		PxU32 nbCreatedTris = 0;
		for(PxU32 i=0; i < nbTouchedTris; i++)
		{
			const PxU32 triangleIndex = indices[i];

			// Compute triangle in world space, add to array
			PxTriangle currentTriangle;
			PxMeshQuery::getTriangle(hfGeom, heightfieldPose, triangleIndex, currentTriangle);
			currentTriangle.verts[0] += offset;
			currentTriangle.verts[1] += offset;
			currentTriangle.verts[2] += offset;

			const PxU32 nbNewTris = createInvisibleWalls(params, currentTriangle, worldTriangles, triIndicesArray);
			nbCreatedTris += nbNewTris;
			if(!nbNewTris)
			{
				worldTriangles.pushBack(currentTriangle);

				triIndicesArray.pushBack(triangleIndex);
				nbCreatedTris++;
			}
		}
		touchedMesh->mNbTris = nbCreatedTris;
	}
	else
	{
		// Reserve memory for incoming triangles
		PxTriangle* TouchedTriangles = reserve(worldTriangles, nbTouchedTris);

		// Loop through touched triangles
		for(PxU32 i=0; i < nbTouchedTris; i++)
		{
			const PxU32 triangleIndex = indices[i];

			// Compute triangle in world space, add to array
			PxTriangle& currentTriangle = *TouchedTriangles++;
			PxMeshQuery::getTriangle(hfGeom, heightfieldPose, triangleIndex, currentTriangle);
			currentTriangle.verts[0] += offset;
			currentTriangle.verts[1] += offset;
			currentTriangle.verts[2] += offset;

			triIndicesArray.pushBack(triangleIndex);
		}
	}

	if(gVisualizeTouchedTris)
		visualizeTouchedTriangles(touchedMesh->mNbTris, touchedMesh->mIndexWorldTriangles, &worldTriangles[0], renderBuffer, offset, params.mUpDirection);
}