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);
	}
}
Esempio n. 2
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;
}
Esempio n. 3
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);
}
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;
}
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;
}
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());
				}
			}
		}
	}
}
Esempio n. 7
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;
}
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 physx::collideWithStaticMesh(PxU32 numParticles, PxsParticleCollData* collData,
								  PxsFluidParticleOpcodeCache* opcodeCaches, const Gu::GeometryUnion& meshShape,
								  const PxTransform& world2Shape, const PxTransform& shape2World, PxReal /*cellSize*/, PxReal collisionRange, PxReal proxRadius)
{
	PX_ASSERT(collData);
	PX_ASSERT(opcodeCaches);

	const PxTriangleMeshGeometryLL& meshShapeData = meshShape.get<const PxTriangleMeshGeometryLL>();
	
	const bool idtScaleMesh = meshShapeData.scale.isIdentity();
	Cm::FastVertex2ShapeScaling meshScaling;
	if(!idtScaleMesh)
		meshScaling.init(meshShapeData.scale);

	const PxF32 maxCacheBoundsExtent = 4*collisionRange + proxRadius;
	const PxsFluidParticleOpcodeCache::QuantizationParams quantizationParams = 
		PxsFluidParticleOpcodeCache::getQuantizationParams(maxCacheBoundsExtent);

	const Gu::InternalTriangleMeshData* meshData = meshShapeData.meshData;
	PX_ASSERT(meshData);

	bool isSmallMesh = meshData->mNumTriangles <= 0xffff;
	PxU32 cachedTriangleBuffer[PxsFluidParticleOpcodeCache::sMaxCachedTriangles];

	PxVec3 extent(proxRadius);

	for (PxU32 i = 0; i < numParticles; ++i)
	{
		//had to make this non-const to be able to update cache bits
		PxsParticleCollData& particle = collData[i];
		PxsFluidParticleOpcodeCache& cache = opcodeCaches[i];
		
		PxBounds3 bounds;
		{
			bounds = PxBounds3(particle.newPos - extent, particle.newPos + extent); 
			bounds.include(particle.oldPos);
		}
		
		PxU32 numTriangles = 0;
		const PxU32* triangles = NULL;
		bool isCached = cache.read(particle.particleFlags.low, numTriangles, cachedTriangleBuffer, bounds, quantizationParams, &meshShape, isSmallMesh);

		if (isCached)
		{
			triangles = cachedTriangleBuffer;
			if (numTriangles > 0)
			{
				PxVec3 triangleVerts[PxsFluidParticleOpcodeCache::sMaxCachedTriangles*3];
				const PxU32* triangleIndexIt = triangles;
				for (PxU32 j = 0; j < numTriangles; ++j, ++triangleIndexIt)
				{
					Gu::MeshInterface::GetTriangleVerts((PxU32)isSmallMesh, (Cm::MemFetchPtr)meshData->mTriangles, (Cm::MemFetchPtr)meshData->mVertices, *triangleIndexIt,
						triangleVerts[j*3], triangleVerts[j*3 + 1], triangleVerts[j*3 + 2]);
				}	
				
				collData[i].localDcNum = 0.0f;
				collData[i].localSurfaceNormal = PxVec3(0);
				collData[i].localSurfacePos = PxVec3(0);

				collideWithMeshTriangles(collData[i], *meshData, meshScaling, triangleVerts, numTriangles, proxRadius, shape2World);				
			}
		}
		else if ((particle.particleFlags.low & PxvInternalParticleFlag::eGEOM_CACHE_BIT_0) != 0 && (particle.particleFlags.low & PxvInternalParticleFlag::eGEOM_CACHE_BIT_1) != 0)
		{
			// don't update the cache since it's already successfully in use
			PxcContactCellMeshCallback callback(collData, &i, 1, *meshData, meshScaling, proxRadius, NULL, shape2World);
				
			testBoundsMesh(*meshData, world2Shape, shape2World, meshScaling, idtScaleMesh, bounds, callback);		
		}
		else
		{
			// compute new conservative bounds for cache
			PxBounds3 cachedBounds;
			{
				PxVec3 predictedExtent(proxRadius*1.5f);

				//add future newpos + extent
				PxVec3 newPosPredicted = particle.newPos + 3.f*(particle.newPos - particle.oldPos);
				cachedBounds = PxBounds3(newPosPredicted - predictedExtent, newPosPredicted + predictedExtent);
				
				//add next oldpos + extent
				cachedBounds.include(PxBounds3(particle.newPos - predictedExtent, particle.newPos + predictedExtent));
				
				//add old pos
				cachedBounds.include(particle.oldPos);
			}
         
			cache.init(cachedTriangleBuffer);

			//the callback function will call collideWithMeshTriangles()
			PxcContactCellMeshCallback callback(collData, &i, 1, *meshData, meshScaling, proxRadius, &cache, shape2World);

			// opcode query: cache bounds against shape bounds in unscaled mesh space
			testBoundsMesh(*meshData, world2Shape, shape2World, meshScaling, idtScaleMesh, cachedBounds, callback);		
	
			//update cache
			cache.write(particle.particleFlags.low, cachedBounds, quantizationParams, meshShape, isSmallMesh);
		}
	}
}
	//////////////////////////////////////////////////////////////////////////
	// checks if points form a valid AABB cube, if not construct a default CUBE
	static bool checkPointsAABBValidity(PxU32 numPoints, const PxVec3* points, PxU32 stride , float distanceEpsilon,
		float resizeValue, PxVec3& center, PxVec3& scale, PxU32& vcount, PxVec3* vertices, bool fCheck = false)
	{
		const char* vtx = reinterpret_cast<const char *> (points);
		PxBounds3 bounds;
		bounds.setEmpty();

		// get the bounding box		
		for (PxU32 i = 0; i < numPoints; i++)
		{
			const PxVec3& p = *reinterpret_cast<const PxVec3 *> (vtx);
			vtx += stride;

			bounds.include(p);
		}

		PxVec3 dim = bounds.getDimensions();
		center = bounds.getCenter();

		// special case, the AABB is very thin or user provided us with only input 2 points
		// we construct an AABB cube and return it
		if ( dim.x < distanceEpsilon || dim.y < distanceEpsilon || dim.z < distanceEpsilon || numPoints < 3 )
		{
			float len = FLT_MAX;

			// pick the shortest size bigger than the distance epsilon
			if ( dim.x > distanceEpsilon && dim.x < len ) 
				len = dim.x;
			if ( dim.y > distanceEpsilon && dim.y < len ) 
				len = dim.y;
			if ( dim.z > distanceEpsilon && dim.z < len ) 
				len = dim.z;

			// if the AABB is small in all dimensions, resize it
			if ( len == FLT_MAX )
			{
				dim = PxVec3(resizeValue);
			}
			// if one edge is small, set to 1/5th the shortest non-zero edge.
			else
			{
				if ( dim.x < distanceEpsilon )
					dim.x = len * 0.05f;
				else
					dim.x *= 0.5f;
				if ( dim.y < distanceEpsilon )
					dim.y = len * 0.05f;
				else
					dim.y *= 0.5f;
				if ( dim.z < distanceEpsilon ) 
					dim.z = len * 0.05f;
				else
					dim.z *= 0.5f;
			}

			// construct the AABB
			const PxVec3 extPos = center + dim;
			const PxVec3 extNeg = center - dim;

			if(fCheck)
				vcount = 0;

			vertices[vcount++] = extNeg;			
			vertices[vcount++] = PxVec3(extPos.x,extNeg.y,extNeg.z);
			vertices[vcount++] = PxVec3(extPos.x,extPos.y,extNeg.z);			
			vertices[vcount++] = PxVec3(extNeg.x,extPos.y,extNeg.z);			
			vertices[vcount++] = PxVec3(extNeg.x,extNeg.y,extPos.z);			
			vertices[vcount++] = PxVec3(extPos.x,extNeg.y,extPos.z);			
			vertices[vcount++] = extPos;			
			vertices[vcount++] = PxVec3(extNeg.x,extPos.y,extPos.z);			
			return true; // return cube
		}
		else
		{
			scale = dim;
		}
		return false;
	}