bool copyStaticProperties(PxRigidActor& to, const PxRigidActor& from,NxMirrorScene::MirrorFilter &mirrorFilter) { physx::shdfnd::InlineArray<PxShape*, 64> shapes; shapes.resize(from.getNbShapes()); PxU32 shapeCount = from.getNbShapes(); from.getShapes(shapes.begin(), shapeCount); physx::shdfnd::InlineArray<PxMaterial*, 64> materials; for(PxU32 i = 0; i < shapeCount; i++) { PxShape* s = shapes[i]; if ( mirrorFilter.shouldMirror(*s) ) { PxU32 materialCount = s->getNbMaterials(); materials.resize(materialCount); s->getMaterials(materials.begin(), materialCount); PxShape* shape = to.createShape(s->getGeometry().any(), materials.begin(), static_cast<physx::PxU16>(materialCount)); shape->setLocalPose( s->getLocalPose()); shape->setContactOffset(s->getContactOffset()); shape->setRestOffset(s->getRestOffset()); shape->setFlags(s->getFlags()); shape->setSimulationFilterData(s->getSimulationFilterData()); shape->setQueryFilterData(s->getQueryFilterData()); mirrorFilter.reviseMirrorShape(*shape); } } to.setActorFlags(from.getActorFlags()); to.setOwnerClient(from.getOwnerClient()); to.setDominanceGroup(from.getDominanceGroup()); if ( to.getNbShapes() ) { mirrorFilter.reviseMirrorActor(to); } return to.getNbShapes() != 0; }
bool CreateGeometryFromPhysxActor(PxActor *a, LevelGeometry::Mesh &mesh) { bool rv = false; if (!a) return rv; PxRigidActor *ra = a->isRigidActor(); if (!ra) return rv; GameObject* gameObj = NULL; PhysicsCallbackObject* userData = static_cast<PhysicsCallbackObject*>(ra->userData); if(userData) gameObj = userData->isGameObject(); r3dCSHolder block(g_pPhysicsWorld->GetConcurrencyGuard()); PxU32 nbShapes = ra->getNbShapes(); for (PxU32 i = 0; i < nbShapes; ++i) { PxShape *s = 0; ra->getShapes(&s, 1, i); PxGeometryType::Enum gt = s->getGeometryType(); switch(gt) { case PxGeometryType::eTRIANGLEMESH: { PxTriangleMeshGeometry g; s->getTriangleMeshGeometry(g); PxTransform t = s->getLocalPose().transform(ra->getGlobalPose()); rv = CreateGeometryFromPhysxGeometry(g, t, mesh); break; } default: r3dArtBug("buildNavigation: Unsupported physx mesh type %d, obj: %s\n", gt, gameObj ? gameObj->Name.c_str() : "<unknown>"); } } return rv; }
bool UWorld::ComponentSweepMulti(TArray<struct FHitResult>& OutHits, class UPrimitiveComponent* PrimComp, const FVector& Start, const FVector& End, const FQuat& Quat, const struct FComponentQueryParams& Params) const { if (GetPhysicsScene() == NULL) { return false; } if (PrimComp == NULL) { UE_LOG(LogCollision, Log, TEXT("ComponentSweepMulti : No PrimComp")); return false; } ECollisionChannel TraceChannel = PrimComp->GetCollisionObjectType(); // if extent is 0, do line trace if (PrimComp->IsZeroExtent()) { return RaycastMulti(this, OutHits, Start, End, TraceChannel, Params, FCollisionResponseParams(PrimComp->GetCollisionResponseToChannels())); } OutHits.Reset(); #if UE_WITH_PHYSICS const FBodyInstance* BodyInstance = PrimComp->GetBodyInstance(); if (!BodyInstance || !BodyInstance->IsValidBodyInstance()) { UE_LOG(LogCollision, Log, TEXT("ComponentSweepMulti : (%s) No physics data"), *PrimComp->GetReadableName()); return false; } #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) if(PrimComp->IsA(USkeletalMeshComponent::StaticClass())) { UE_LOG(LogCollision, Warning, TEXT("ComponentSweepMulti : SkeletalMeshComponent support only root body (%s) "), *PrimComp->GetReadableName()); } #endif #endif SCOPE_CYCLE_COUNTER(STAT_Collision_GeomSweepMultiple); bool bHaveBlockingHit = false; #if WITH_PHYSX ExecuteOnPxRigidActorReadOnly(BodyInstance, [&] (const PxRigidActor* PRigidActor) { // Get all the shapes from the actor FInlinePxShapeArray PShapes; const int32 NumShapes = FillInlinePxShapeArray(PShapes, *PRigidActor); // calculate the test global pose of the actor const PxQuat PGeomRot = U2PQuat(Quat); const PxTransform PGlobalStartPose = PxTransform(U2PVector(Start), PGeomRot); const PxTransform PGlobalEndPose = PxTransform(U2PVector(End), PGeomRot); // Iterate over each shape for(int32 ShapeIdx=0; ShapeIdx<NumShapes; ShapeIdx++) { PxShape* PShape = PShapes[ShapeIdx]; check(PShape); GET_GEOMETRY_FROM_SHAPE(PGeom, PShape); if (PGeom != NULL) { // Calc shape global pose const PxTransform PLocalShape = PShape->getLocalPose(); const PxTransform PShapeGlobalStartPose = PGlobalStartPose.transform(PLocalShape); const PxTransform PShapeGlobalEndPose = PGlobalEndPose.transform(PLocalShape); // consider localshape rotation for shape rotation const PxQuat PShapeRot = PGeomRot * PLocalShape.q; if (GeomSweepMulti_PhysX(this, *PGeom, PShapeRot, OutHits, P2UVector(PShapeGlobalStartPose.p), P2UVector(PShapeGlobalEndPose.p), TraceChannel, Params, FCollisionResponseParams(PrimComp->GetCollisionResponseToChannels()))) { bHaveBlockingHit = true; } } } }); #endif //WITH_PHYSX //@TODO: BOX2D: Implement UWorld::ComponentSweepMulti #if WITH_BOX2D // if (b2Body* BodyInstance = PrimComp->BodyInstance.BodyInstancePtr) // { // // } #endif return bHaveBlockingHit; }
osg::Node* createNodeForActor( PxRigidActor* actor ) { if ( !actor ) return NULL; std::vector<PxShape*> shapes( actor->getNbShapes() ); osg::ref_ptr<osg::MatrixTransform> transform = new osg::MatrixTransform; transform->setMatrix( toMatrix(PxMat44(actor->getGlobalPose())) ); osg::ref_ptr<osg::Geode> geode = new osg::Geode; transform->addChild( geode.get() ); PxU32 num = actor->getShapes( &(shapes[0]), actor->getNbShapes() ); for ( PxU32 i=0; i<num; ++i ) { PxShape* shape = shapes[i]; osg::Matrix localMatrix = toMatrix( PxMat44(actor->getGlobalPose()) ); osg::Vec3 localPos = toVec3( shape->getLocalPose().p ); osg::Quat localQuat(shape->getLocalPose().q.x, shape->getLocalPose().q.y, shape->getLocalPose().q.z, shape->getLocalPose().q.w); switch ( shape->getGeometryType() ) { case PxGeometryType::eSPHERE: { PxSphereGeometry sphere; shape->getSphereGeometry( sphere ); osg::Sphere* sphereShape = new osg::Sphere(localPos, sphere.radius); geode->addDrawable( new osg::ShapeDrawable(sphereShape) ); } break; case PxGeometryType::ePLANE: // TODO break; case PxGeometryType::eCAPSULE: { PxCapsuleGeometry capsule; shape->getCapsuleGeometry( capsule ); osg::Capsule* capsuleShape = new osg::Capsule( localPos, capsule.radius, capsule.halfHeight * 2.0f); capsuleShape->setRotation( localQuat ); geode->addDrawable( new osg::ShapeDrawable(capsuleShape) ); } break; case PxGeometryType::eBOX: { PxBoxGeometry box; shape->getBoxGeometry( box ); osg::Box* boxShape = new osg::Box(localPos, box.halfExtents[0] * 2.0f, box.halfExtents[1] * 2.0f, box.halfExtents[2] * 2.0f); boxShape->setRotation( localQuat ); geode->addDrawable( new osg::ShapeDrawable(boxShape) ); } break; case PxGeometryType::eCONVEXMESH: { PxConvexMeshGeometry convexMeshGeom; shape->getConvexMeshGeometry( convexMeshGeom ); // TODO: consider convexMeshGeom.scale PxConvexMesh* convexMesh = convexMeshGeom.convexMesh; if ( convexMesh ) { /*for ( unsigned int i=0; i<convexMesh->getNbPolygons(); ++i ) { }*/ // TODO } } break; case PxGeometryType::eTRIANGLEMESH: { PxTriangleMeshGeometry triangleMeshGeom; shape->getTriangleMeshGeometry( triangleMeshGeom ); // TODO: consider triangleMeshGeom.scale PxTriangleMesh* triangleMesh = triangleMeshGeom.triangleMesh; if ( triangleMesh ) { osg::ref_ptr<osg::Vec3Array> va = new osg::Vec3Array( triangleMesh->getNbVertices() ); for ( unsigned int i=0; i<va->size(); ++i ) (*va)[i] = toVec3( *(triangleMesh->getVertices() + i) ) * localMatrix; osg::ref_ptr<osg::DrawElements> de; if ( triangleMesh->getTriangleMeshFlags()&PxTriangleMeshFlag::eHAS_16BIT_TRIANGLE_INDICES ) { osg::DrawElementsUShort* de16 = new osg::DrawElementsUShort(GL_TRIANGLES); de = de16; const PxU16* indices = (const PxU16*)triangleMesh->getTriangles(); for ( unsigned int i=0; i<triangleMesh->getNbTriangles(); ++i ) { de16->push_back( indices[3 * i + 0] ); de16->push_back( indices[3 * i + 1] ); de16->push_back( indices[3 * i + 2] ); } } else { osg::DrawElementsUInt* de32 = new osg::DrawElementsUInt(GL_TRIANGLES); de = de32; const PxU32* indices = (const PxU32*)triangleMesh->getTriangles(); for ( unsigned int i=0; i<triangleMesh->getNbTriangles(); ++i ) { de32->push_back( indices[3 * i + 0] ); de32->push_back( indices[3 * i + 1] ); de32->push_back( indices[3 * i + 2] ); } } geode->addDrawable( createGeometry(va.get(), NULL, NULL, de.get()) ); } } break; case PxGeometryType::eHEIGHTFIELD: { PxHeightFieldGeometry hfGeom; shape->getHeightFieldGeometry( hfGeom ); // TODO: consider hfGeom.*scale PxHeightField* heightField = hfGeom.heightField; if ( heightField ) { // TODO } } break; } } return transform.release(); }
FDbool BuildingSystem::searchForHit(PhysicsSystem& physicsSystem, Ray r, PxGeometry& pixelFrustum, SearchContext& searchContext) { // Cast the ray into the scene. Quit if no intersection at all. PxQueryFilterData qFilterData; qFilterData.flags |= PxQueryFlag::ePREFILTER | PxQueryFlag::ePOSTFILTER; FDbool rayStatus = physicsSystem.scene->raycast( r.position, r.direction, 100, searchContext.hitBuffer, PxHitFlag::ePOSITION | PxHitFlag::eDISTANCE | PxHitFlag::eNORMAL, qFilterData, &CustomPhysicsQueryFilter()); /* Demo-ing to a friend showed that it can be confusing to try to connect * up an existing point that lies on the guide plane, since part of it will * be behind the guide plane, which the ray-cast will see as being closer. * To remedy this, I treat the GuidePlane as a "touching" rather than * "blocking hit" and give some priority to points. */ if (rayStatus && searchContext.hitBuffer.hasBlock) { // In this case, we know we hit something other than the guide plane. searchContext.hitActor = searchContext.hitBuffer.block.actor; searchContext.rayHit = &searchContext.hitBuffer.block; FDreal blockDistance = searchContext.rayHit->distance; searchContext.setHit(&searchContext.hitBuffer.block); // If the guide plane was also hit, see if it is closer. if (searchContext.hitBuffer.nbTouches > 0) { float guidePlaneDistance = searchContext.hitBuffer.getTouch(0). distance; // If the point intersects the plane, prefer it. if (searchContext.hitActor == pointActor) { FDUint i = (FDUint)searchContext.rayHit->shape->userData; Vector3 pointPos = *pointAuthor->getAttribute<Vector3>(i, 0); float pointRadius = 0.2; Vector3 guidePlaneNormal = searchContext.hitBuffer. getTouch(0).normal; Plane p = Plane(searchContext.hitBuffer.getTouch(0).position, guidePlaneNormal); // We know the point (modeled as a sphere) intersects the // plane if the point is within 1 sphere radius. float pointPlaneDistance = p.distance(pointPos); if (abs(pointPlaneDistance) <= pointRadius) { blockDistance = 0; } } if (guidePlaneDistance < blockDistance) { searchContext.hitActor = searchContext.hitBuffer.getTouch(0). actor; searchContext.setHit(&searchContext.hitBuffer.getTouch(0)); } } } else if (rayStatus) { // Only the guide plane was hit. searchContext.hitActor = searchContext.hitBuffer.getTouch(0).actor; searchContext.setHit(&searchContext.hitBuffer.getTouch(0)); } // Try overlap test for other geometry. Quaternion q = fdmath::getRotationBetween(Vector3(0, 0, 1), r.direction); Vector3 obo = q.rotate(Vector3(0, 0, 1)); PxTransform pose(r.position, q); PxQueryFilterData qPixelFilterData; qPixelFilterData.flags |= PxQueryFlag::ePREFILTER; physicsSystem.scene->overlap(pixelFrustum, pose, searchContext.overlapBuffer, qPixelFilterData, &PixelQueryFilter()); for (FDUint i = 0; i < searchContext.overlapBuffer.nbTouches; i++) { PxRigidStatic* thisActor = (PxRigidStatic*)searchContext.overlapBuffer. touches[i].actor; PxShape* thisShape = searchContext.overlapBuffer.touches[i].shape; // Get the closet point on the line to the ray. Transform lineTransform = thisActor->getGlobalPose() * thisShape->getLocalPose(); Vector3 lineAxisPoint = lineTransform.transform(Vector3(1, 0, 0)); Vector3 centerPos = lineTransform.p; Vector3 lineAxis = (lineAxisPoint - centerPos).getNormalized(); Vector3 uAxis = lineAxis.cross(r.direction); uAxis.normalize(); Plane p(centerPos, lineAxisPoint, centerPos + uAxis); Vector3 intersectionPoint; FDbool intersects = r.intersect(p, intersectionPoint); FD_ASSERT(intersects, "Ray did not intersect line's plane."); FDreal y = lineAxis.dot(intersectionPoint) - lineAxis.dot(centerPos); Vector3 closestPoint = centerPos + lineAxis * y; FDreal dist = (closestPoint - r.position).magnitude(); if (dist < searchContext.hitDist) { searchContext.setHit(&searchContext.overlapBuffer.touches[i], closestPoint, -r.direction, dist); searchContext.hitActor = thisActor; } } return searchContext.hitHappened; }
bool UWorld::ComponentSweepMulti(TArray<struct FHitResult>& OutHits, class UPrimitiveComponent* PrimComp, const FVector& Start, const FVector& End, const FRotator& Rot, const struct FComponentQueryParams& Params) const { if(GetPhysicsScene() == NULL) { return false; } if(PrimComp == NULL) { UE_LOG(LogCollision, Log, TEXT("ComponentSweepMulti : No PrimComp")); return false; } // if target is skeletalmeshcomponent and do not support singlebody physics if ( !PrimComp->ShouldTrackOverlaps() ) { UE_LOG(LogCollision, Log, TEXT("ComponentSweepMulti : (%s) Does not support skeletalmesh with Physics Asset and destructibles."), *PrimComp->GetPathName()); return false; } ECollisionChannel TraceChannel = PrimComp->GetCollisionObjectType(); #if WITH_PHYSX // if extent is 0, do line trace if (PrimComp->IsZeroExtent()) { return RaycastMulti(this, OutHits, Start, End, TraceChannel, Params, FCollisionResponseParams(PrimComp->GetCollisionResponseToChannels())); } PxRigidActor* PRigidActor = PrimComp->BodyInstance.GetPxRigidActor(); if(PRigidActor == NULL) { UE_LOG(LogCollision, Log, TEXT("ComponentSweepMulti : (%s) No physics data"), *PrimComp->GetPathName()); return false; } PxScene * const PScene = PRigidActor->getScene(); OutHits.Empty(); // Get all the shapes from the actor TArray<PxShape*, TInlineAllocator<8>> PShapes; { SCOPED_SCENE_READ_LOCK(PScene); PShapes.AddZeroed(PRigidActor->getNbShapes()); PRigidActor->getShapes(PShapes.GetData(), PShapes.Num()); } // calculate the test global pose of the actor PxTransform PGlobalStartPose = U2PTransform(FTransform(Start)); PxTransform PGlobalEndPose = U2PTransform(FTransform(End)); bool bHaveBlockingHit = false; PxQuat PGeomRot = U2PQuat(Rot.Quaternion()); // Iterate over each shape SCENE_LOCK_READ(PScene); for(int32 ShapeIdx=0; ShapeIdx<PShapes.Num(); ShapeIdx++) { PxShape* PShape = PShapes[ShapeIdx]; check(PShape); TArray<struct FHitResult> Hits; // Calc shape global pose PxTransform PLocalShape = PShape->getLocalPose(); PxTransform PShapeGlobalStartPose = PGlobalStartPose.transform(PLocalShape); PxTransform PShapeGlobalEndPose = PGlobalEndPose.transform(PLocalShape); // consider localshape rotation for shape rotation PxQuat PShapeRot = PGeomRot * PLocalShape.q; GET_GEOMETRY_FROM_SHAPE(PGeom, PShape); if(PGeom != NULL) { SCENE_UNLOCK_READ(PScene); if (GeomSweepMulti(this, *PGeom, PShapeRot, Hits, P2UVector(PShapeGlobalStartPose.p), P2UVector(PShapeGlobalEndPose.p), TraceChannel, Params, FCollisionResponseParams(PrimComp->GetCollisionResponseToChannels()))) { bHaveBlockingHit = true; } OutHits.Append(Hits); SCENE_LOCK_READ(PScene); } } SCENE_UNLOCK_READ(PScene); return bHaveBlockingHit; #endif //WITH_PHYSX return false; }
bool UWorld::ComponentSweepSingle(struct FHitResult& OutHit,class UPrimitiveComponent* PrimComp, const FVector& Start, const FVector& End, const FRotator& Rot, const struct FComponentQueryParams& Params) const { OutHit.TraceStart = Start; OutHit.TraceEnd = End; if(GetPhysicsScene() == NULL) { return false; } if(PrimComp == NULL) { UE_LOG(LogCollision, Log, TEXT("ComponentSweepSingle : No PrimComp")); return false; } // if target is skeletalmeshcomponent and do not support singlebody physics if ( !PrimComp->ShouldTrackOverlaps() ) { UE_LOG(LogCollision, Log, TEXT("ComponentSweepSingle : (%s) Does not support skeletalmesh with Physics Asset and destructibles."), *PrimComp->GetPathName()); return false; } ECollisionChannel TraceChannel = PrimComp->GetCollisionObjectType(); #if WITH_PHYSX // if extent is 0, do line trace if (PrimComp->IsZeroExtent()) { return RaycastSingle(this, OutHit, Start, End, TraceChannel, Params, FCollisionResponseParams(PrimComp->GetCollisionResponseToChannels())); } PxRigidActor* PRigidActor = PrimComp->BodyInstance.GetPxRigidActor(); if(PRigidActor == NULL) { UE_LOG(LogCollision, Log, TEXT("ComponentSweepMulti : (%s) No physics data"), *PrimComp->GetPathName()); return false; } // Get all the shapes from the actor TArray<PxShape*, TInlineAllocator<8>> PShapes; PShapes.AddZeroed(PRigidActor->getNbShapes()); int32 NumShapes = PRigidActor->getShapes(PShapes.GetData(), PShapes.Num()); // calculate the test global pose of the actor PxTransform PGlobalStartPose = U2PTransform(FTransform(Start)); PxTransform PGlobalEndPose = U2PTransform(FTransform(End)); bool bHaveBlockingHit = false; PxQuat PGeomRot = U2PQuat(Rot.Quaternion()); // Iterate over each shape for(int32 ShapeIdx=0; ShapeIdx<PShapes.Num(); ShapeIdx++) { PxShape* PShape = PShapes[ShapeIdx]; check(PShape); // Calc shape global pose PxTransform PLocalShape = PShape->getLocalPose(); PxTransform PShapeGlobalStartPose = PGlobalStartPose.transform(PLocalShape); PxTransform PShapeGlobalEndPose = PGlobalEndPose.transform(PLocalShape); // consider localshape rotation for shape rotation PxQuat PShapeRot = PGeomRot * PLocalShape.q; GET_GEOMETRY_FROM_SHAPE(PGeom, PShape); if(PGeom != NULL) { // @todo UE4, this might not be the best behavior. If we're looking for the most closest, this have to change to save the result, and find the closest one or // any other options, right now if anything hits first, it will return if (GeomSweepSingle(this, *PGeom, PShapeRot, OutHit, P2UVector(PShapeGlobalStartPose.p), P2UVector(PShapeGlobalEndPose.p), TraceChannel, Params, FCollisionResponseParams(PrimComp->GetCollisionResponseToChannels()))) { bHaveBlockingHit = true; break; } } } return bHaveBlockingHit; #endif //WITH_PHYSX return false; }
bool UWorld::ComponentOverlapTest(class UPrimitiveComponent* PrimComp, const FVector& Pos, const FRotator& Rot, const struct FComponentQueryParams& Params) const { if(GetPhysicsScene() == NULL) { return false; } if(PrimComp == NULL) { UE_LOG(LogCollision, Log, TEXT("ComponentOverlapMulti : No PrimComp")); return false; } // if target is skeletalmeshcomponent and do not support singlebody physics, we don't support this yet // talk to @JG, SP, LH if ( !PrimComp->ShouldTrackOverlaps() ) { UE_LOG(LogCollision, Log, TEXT("ComponentOverlapMulti : (%s) Does not support skeletalmesh with Physics Asset and destructibles."), *PrimComp->GetPathName()); return false; } #if WITH_PHYSX ECollisionChannel TraceChannel = PrimComp->GetCollisionObjectType(); PxRigidActor* PRigidActor = PrimComp->BodyInstance.GetPxRigidActor(); if(PRigidActor == NULL) { UE_LOG(LogCollision, Log, TEXT("ComponentOverlapMulti : (%s) No physics data"), *PrimComp->GetPathName()); return false; } // calculate the test global pose of the actor PxTransform PTestGlobalPose = U2PTransform(FTransform(Rot, Pos)); // Get all the shapes from the actor TArray<PxShape*, TInlineAllocator<8>> PShapes; PShapes.AddZeroed(PRigidActor->getNbShapes()); int32 NumShapes = PRigidActor->getShapes(PShapes.GetData(), PShapes.Num()); // Iterate over each shape for(int32 ShapeIdx=0; ShapeIdx<PShapes.Num(); ShapeIdx++) { PxShape* PShape = PShapes[ShapeIdx]; check(PShape); // Calc shape global pose PxTransform PLocalPose = PShape->getLocalPose(); PxTransform PShapeGlobalPose = PTestGlobalPose.transform(PLocalPose); GET_GEOMETRY_FROM_SHAPE(PGeom, PShape); if(PGeom != NULL) { if( GeomOverlapTest(this, *PGeom, PShapeGlobalPose, TraceChannel, Params, FCollisionResponseParams(PrimComp->GetCollisionResponseToChannels()))) { // in this test, it only matters true or false. // if we found first true, we don't care next test anymore. return true; } } } #endif //WITH_PHYSX return false; }