Bounds3 Bounds3::ToManaged(PxBounds3 bounds) { PxVec3 center = bounds.getCenter(); PxVec3 extents = bounds.getExtents(); return Bounds3(MathUtil::PxVec3ToVector3(center - extents), MathUtil::PxVec3ToVector3(center + extents)); }
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); }
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); }
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); }
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); }
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); }
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 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 }
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; } } }
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); } }
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)); } } }
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 }
static void outputMeshToStream( PxShape* meshShape, const PxRigidActor* actor, const PxTransform& meshPose, IntArray& geomStream, TriArray& worldTriangles, IntArray& triIndicesArray, const PxExtendedVec3& origin, const PxBounds3& tmpBounds, const CCTParams& params, Cm::RenderBuffer* renderBuffer, PxU16& nbTessellation) { PX_ASSERT(meshShape->getGeometryType() == PxGeometryType::eTRIANGLEMESH); // Do AABB-mesh query PxTriangleMeshGeometry triGeom; meshShape->getTriangleMeshGeometry(triGeom); const PxBoxGeometry boxGeom(tmpBounds.getExtents()); const PxTransform boxPose(tmpBounds.getCenter(), PxQuat(PxIdentity)); // Collide AABB against current mesh PxMeshOverlapUtil overlapUtil; const PxU32 nbTouchedTris = overlapUtil.findOverlap(boxGeom, boxPose, triGeom, meshPose); 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; touchedMesh->mTGUserData = meshShape; touchedMesh->mActor = actor; touchedMesh->mOffset = origin; touchedMesh->mNbTris = nbTouchedTris; touchedMesh->mIndexWorldTriangles = worldTriangles.size(); const PxU32* PX_RESTRICT indices = overlapUtil.getResults(); if(params.mSlopeLimit!=0.0f) { if(!params.mTessellation) { // 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(triGeom, meshPose, 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 { const PxBounds3 cullingBox = PxBounds3::centerExtents(boxPose.p + offset, boxGeom.halfExtents); // 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(triGeom, meshPose, triangleIndex, currentTriangle); currentTriangle.verts[0] += offset; currentTriangle.verts[1] += offset; currentTriangle.verts[2] += offset; PxU32 nbNewTris = createInvisibleWalls(params, currentTriangle, worldTriangles, triIndicesArray); nbCreatedTris += nbNewTris; if(!nbNewTris) { /* worldTriangles.pushBack(currentTriangle); triIndicesArray.pushBack(triangleIndex); nbCreatedTris++;*/ tessellateTriangle(nbNewTris, currentTriangle, triangleIndex, worldTriangles, triIndicesArray, cullingBox, params, nbTessellation); nbCreatedTris += nbNewTris; // printf("Tesselate: %d new tris\n", nbNewTris); } } touchedMesh->mNbTris = nbCreatedTris; } } else { if(!params.mTessellation) { // 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(triGeom, meshPose, triangleIndex, currentTriangle); currentTriangle.verts[0] += offset; currentTriangle.verts[1] += offset; currentTriangle.verts[2] += offset; triIndicesArray.pushBack(triangleIndex); } } else { const PxBounds3 cullingBox = PxBounds3::centerExtents(boxPose.p + offset, boxGeom.halfExtents); 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(triGeom, meshPose, triangleIndex, currentTriangle); currentTriangle.verts[0] += offset; currentTriangle.verts[1] += offset; currentTriangle.verts[2] += offset; PxU32 nbNewTris = 0; tessellateTriangle(nbNewTris, currentTriangle, triangleIndex, worldTriangles, triIndicesArray, cullingBox, params, nbTessellation); // printf("Tesselate: %d new tris\n", nbNewTris); nbCreatedTris += nbNewTris; } touchedMesh->mNbTris = nbCreatedTris; } } if(gVisualizeTouchedTris) visualizeTouchedTriangles(touchedMesh->mNbTris, touchedMesh->mIndexWorldTriangles, &worldTriangles[0], renderBuffer, offset, params.mUpDirection); }
static void outputConvexToStream(PxShape* convexShape, const PxRigidActor* actor, const PxTransform& absPose_, IntArray& geomStream, TriArray& worldTriangles, IntArray& triIndicesArray, const PxExtendedVec3& origin, const PxBounds3& tmpBounds, const CCTParams& params, Cm::RenderBuffer* renderBuffer, PxU16& nbTessellation) { PX_ASSERT(convexShape->getGeometryType() == PxGeometryType::eCONVEXMESH); PxConvexMeshGeometry cg; convexShape->getConvexMeshGeometry(cg); PX_ASSERT(cg.convexMesh); // Do AABB-mesh query PxU32* TF; // Collide AABB against current mesh // The overlap function doesn't exist for convexes so let's just dump all tris PxConvexMesh& cm = *cg.convexMesh; // PT: convex triangles are not exposed anymore so we need to access convex polygons & triangulate them // PT: TODO: this is copied from "DrawObjects", move this to a shared place. Actually a helper directly in PxConvexMesh would be useful. PxU32 Nb = 0; { const PxU32 nbPolys = cm.getNbPolygons(); const PxU8* polygons = cm.getIndexBuffer(); for(PxU32 i=0;i<nbPolys;i++) { PxHullPolygon data; cm.getPolygonData(i, data); Nb += data.mNbVerts - 2; } // PT: revisit this code. We don't use the polygon offset? TF = (PxU32*)PxAlloca(sizeof(PxU32)*Nb*3); PxU32* t = TF; for(PxU32 i=0;i<nbPolys;i++) { PxHullPolygon data; cm.getPolygonData(i, data); const PxU32 nbV = data.mNbVerts; const PxU32 nbTris = nbV - 2; const PxU8 vref0 = *polygons; for(PxU32 j=0;j<nbTris;j++) { const PxU32 vref1 = polygons[(j+1)%nbV]; const PxU32 vref2 = polygons[(j+2)%nbV]; *t++ = vref0; *t++ = vref1; *t++ = vref2; } polygons += nbV; } } // PT: you can't use PxTransform with a non-uniform scaling const PxMat33 rot = PxMat33(absPose_.q) * cg.scale.toMat33(); const PxMat44 absPose(rot, absPose_.p); const PxVec3 p = absPose.getPosition(); const PxVec3 MeshOffset(float(p.x - origin.x), float(p.y - origin.y), float(p.z - origin.z)); // LOSS OF ACCURACY 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; touchedMesh->mTGUserData = convexShape; touchedMesh->mActor = actor; touchedMesh->mOffset = origin; touchedMesh->mIndexWorldTriangles = worldTriangles.size(); const PxVec3* verts = cm.getVertices(); // Loop through touched triangles if(params.mTessellation) { const PxBoxGeometry boxGeom(tmpBounds.getExtents()); const PxBounds3 cullingBox = PxBounds3::centerExtents(tmpBounds.getCenter() + offset, boxGeom.halfExtents); PxU32 nbCreatedTris = 0; while(Nb--) { // Compute triangle in world space, add to array PxTriangle currentTriangle; const PxU32 vref0 = *TF++; const PxU32 vref1 = *TF++; const PxU32 vref2 = *TF++; currentTriangle.verts[0] = MeshOffset + absPose.rotate(verts[vref0]); currentTriangle.verts[1] = MeshOffset + absPose.rotate(verts[vref1]); currentTriangle.verts[2] = MeshOffset + absPose.rotate(verts[vref2]); PxU32 nbNewTris = 0; tessellateTriangle(nbNewTris, currentTriangle, PX_INVALID_U32, worldTriangles, triIndicesArray, cullingBox, params, nbTessellation); nbCreatedTris += nbNewTris; } touchedMesh->mNbTris = nbCreatedTris; } else { // Reserve memory for incoming triangles PxTriangle* TouchedTriangles = reserve(worldTriangles, Nb); touchedMesh->mNbTris = Nb; while(Nb--) { // Compute triangle in world space, add to array PxTriangle& currentTriangle = *TouchedTriangles++; const PxU32 vref0 = *TF++; const PxU32 vref1 = *TF++; const PxU32 vref2 = *TF++; currentTriangle.verts[0] = MeshOffset + absPose.rotate(verts[vref0]); currentTriangle.verts[1] = MeshOffset + absPose.rotate(verts[vref1]); currentTriangle.verts[2] = MeshOffset + absPose.rotate(verts[vref2]); triIndicesArray.pushBack(PX_INVALID_U32); } } if(gVisualizeTouchedTris) visualizeTouchedTriangles(touchedMesh->mNbTris, touchedMesh->mIndexWorldTriangles, &worldTriangles[0], renderBuffer, offset, params.mUpDirection); }
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); }
static void outputBoxToStream( PxShape* boxShape, const PxRigidActor* actor, const PxTransform& globalPose, IntArray& geomStream, TriArray& worldTriangles, IntArray& triIndicesArray, const PxExtendedVec3& origin, const PxBounds3& tmpBounds, const CCTParams& params, PxU16& nbTessellation) { PX_ASSERT(boxShape->getGeometryType() == PxGeometryType::eBOX); PxBoxGeometry bg; boxShape->getBoxGeometry(bg); //8 verts in local space. const PxF32 dx = bg.halfExtents.x; const PxF32 dy = bg.halfExtents.y; const PxF32 dz = bg.halfExtents.z; PxVec3 boxVerts[8]= { PxVec3(-dx,-dy,-dz), PxVec3(+dx,-dy,-dz), PxVec3(+dx,+dy,-dz), PxVec3(-dx,+dy,-dz), PxVec3(-dx,-dy,+dz), PxVec3(+dx,-dy,+dz), PxVec3(+dx,+dy,+dz), PxVec3(-dx,+dy,+dz) }; //Transform verts into world space. const PxVec3 pxOrigin = toVec3(origin); for(PxU32 i = 0; i < 8; i++) { boxVerts[i] = globalPose.transform(boxVerts[i]) - pxOrigin; } //Index of triangles. const PxU32 boxTris[12][3]= { {0,2,1}, {2,0,3}, //0,1,2,3 {3,6,2}, {6,3,7}, //3,2,6,7 {7,5,6}, {5,7,4}, //7,6,5,4 {4,1,5}, {1,4,0}, //4,5,1,0 {0,7,3}, {7,0,4}, //0,3,7,4 {2,5,1}, {5,2,6} //2,1,5,6 }; TouchedMesh* touchedMesh = (TouchedMesh*)reserve(geomStream, sizeof(TouchedMesh)/sizeof(PxU32)); touchedMesh->mType = TouchedGeomType::eMESH; touchedMesh->mTGUserData = boxShape; touchedMesh->mActor = actor; touchedMesh->mOffset = origin; touchedMesh->mIndexWorldTriangles = worldTriangles.size(); if(params.mTessellation) { const PxBoxGeometry boxGeom(tmpBounds.getExtents()); const PxVec3 offset(float(-origin.x), float(-origin.y), float(-origin.z)); const PxBounds3 cullingBox = PxBounds3::centerExtents(tmpBounds.getCenter() + offset, boxGeom.halfExtents); PxU32 nbCreatedTris = 0; for(PxU32 i=0; i<12; i++) { // Compute triangle in world space, add to array const PxTriangle currentTriangle(boxVerts[boxTris[i][0]], boxVerts[boxTris[i][1]], boxVerts[boxTris[i][2]]); PxU32 nbNewTris = 0; tessellateTriangle(nbNewTris, currentTriangle, PX_INVALID_U32, worldTriangles, triIndicesArray, cullingBox, params, nbTessellation); nbCreatedTris += nbNewTris; } touchedMesh->mNbTris = nbCreatedTris; } else { touchedMesh->mNbTris = 12; // Reserve memory for incoming triangles PxTriangle* TouchedTriangles = reserve(worldTriangles, 12); for(PxU32 i=0; i<12; i++) { PxTriangle& currentTriangle = TouchedTriangles[i]; currentTriangle.verts[0] = boxVerts[boxTris[i][0]]; currentTriangle.verts[1] = boxVerts[boxTris[i][1]]; currentTriangle.verts[2] = boxVerts[boxTris[i][2]]; triIndicesArray.pushBack(PX_INVALID_U32); } } }
void FDestructibleMeshEditorViewportClient::ProcessClick( class FSceneView& View, class HHitProxy* HitProxy, FKey Key, EInputEvent Event, uint32 HitX, uint32 HitY ) { #if WITH_APEX bool bKeepSelection = Viewport->KeyState(EKeys::LeftControl) || Viewport->KeyState(EKeys::RightControl); bool bSelectionChanged = false; if (Key == EKeys::LeftMouseButton && Event == EInputEvent::IE_Released) { UDestructibleComponent* Comp = PreviewDestructibleComp.Get(); NxDestructibleAsset* Asset = Comp->DestructibleMesh->ApexDestructibleAsset; const NxRenderMeshAsset* RenderMesh = Asset->getRenderMeshAsset(); FVector2D ScreenPos(HitX, HitY); FVector ClickOrigin, ViewDir; View.DeprojectFVector2D(ScreenPos, ClickOrigin, ViewDir); float NearestHitDistance = FLT_MAX; int32 ClickedChunk = -1; for (uint32 i=0; i < Asset->getChunkCount(); ++i) { int32 PartIdx = Asset->getPartIndex(i); int32 BoneIdx = i+1; if (!Comp->IsBoneHidden(BoneIdx)) { 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); FVector HitLoc, HitNorm; float HitTime; if (FMath::LineExtentBoxIntersection(Bounds, ClickOrigin, ClickOrigin + ViewDir * 1000.0f, FVector(0,0,0), HitLoc, HitNorm, HitTime)) { float dist = (HitLoc - ClickOrigin).SizeSquared(); if (dist < NearestHitDistance) { NearestHitDistance = dist; ClickedChunk = i; } } } } if (ClickedChunk >= 0) { int32 Idx = SelectedChunkIndices.Find(ClickedChunk); if (Idx < 0) { if (!bKeepSelection) { SelectedChunkIndices.Empty(); } SelectedChunkIndices.Add(ClickedChunk); bSelectionChanged = true; } else { SelectedChunkIndices.RemoveAt(Idx); bSelectionChanged = true; } } else if (!bKeepSelection) { SelectedChunkIndices.Empty(); bSelectionChanged = true; } } if (bSelectionChanged) { UpdateChunkSelection(SelectedChunkIndices); } #endif // WITH_APEX }
////////////////////////////////////////////////////////////////////////// // 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; }