void PhysX3::ApplyActionAtPoint(PintObjectHandle handle, PintActionType action_type, const Point& action, const Point& pos) { PxRigidActor* RigidActor = GetActorFromHandle(handle); if(!RigidActor) { PxShape* Shape = GetShapeFromHandle(handle); ASSERT(Shape); #ifdef SUPPORT_SHARED_SHAPES RigidActor = Shape->getActor(); #else RigidActor = &Shape->getActor(); #endif } if(RigidActor->getConcreteType()==PxConcreteType::eRIGID_DYNAMIC) { PxRigidDynamic* RigidDynamic = static_cast<PxRigidDynamic*>(RigidActor); if(!(RigidDynamic->getRigidBodyFlags() & PxRigidBodyFlag::eKINEMATIC)) { PxForceMode::Enum mode; if(action_type==PINT_ACTION_FORCE) mode = PxForceMode::eFORCE; else if(action_type==PINT_ACTION_IMPULSE) mode = PxForceMode::eIMPULSE; else ASSERT(0); PxRigidBodyExt::addForceAtPos(*RigidDynamic, ToPxVec3(action), ToPxVec3(pos), mode); } } }
void PxScaleRigidActor(PxRigidActor& actor, PxReal scale, bool scaleMassProps) { PX_CHECK_AND_RETURN(scale > 0, "PxScaleRigidActor requires that the scale parameter is greater than zero"); Ps::InlineArray<PxShape*, 64> shapes; shapes.resize(actor.getNbShapes()); actor.getShapes(shapes.begin(), shapes.size()); for(PxU32 i=0;i<shapes.size();i++) { shapes[i]->setLocalPose(scalePosition(shapes[i]->getLocalPose(), scale)); PxGeometryHolder h = shapes[i]->getGeometry(); switch(h.getType()) { case PxGeometryType::eSPHERE: h.sphere().radius *= scale; break; case PxGeometryType::ePLANE: break; case PxGeometryType::eCAPSULE: h.capsule().halfHeight *= scale; h.capsule().radius *= scale; break; case PxGeometryType::eBOX: h.box().halfExtents *= scale; break; case PxGeometryType::eCONVEXMESH: h.convexMesh().scale.scale *= scale; break; case PxGeometryType::eTRIANGLEMESH: h.triangleMesh().scale.scale *= scale; break; case PxGeometryType::eHEIGHTFIELD: h.heightField().heightScale *= scale; h.heightField().rowScale *= scale; h.heightField().columnScale *= scale; break; case PxGeometryType::eINVALID: case PxGeometryType::eGEOMETRY_COUNT: default: PX_ASSERT(0); } shapes[i]->setGeometry(h.any()); } if(!scaleMassProps) return; PxRigidDynamic* dynamic = (&actor)->is<PxRigidDynamic>(); if(!dynamic) return; PxReal scale3 = scale*scale*scale; dynamic->setMass(dynamic->getMass()*scale3); dynamic->setMassSpaceInertiaTensor(dynamic->getMassSpaceInertiaTensor()*scale3*scale*scale); dynamic->setCMassLocalPose(scalePosition(dynamic->getCMassLocalPose(), scale)); }
void PhysXInterface::setMatrix( int id, const osg::Matrix& matrix ) { PxReal d[16]; for ( int i=0; i<16; ++i ) d[i] = *(matrix.ptr() + i); PxRigidActor* actor = _actors[id]; if ( actor ) actor->setGlobalPose( PxTransform(PxMat44(d)) ); }
int RayCastManagerImpl::CastSweep(const XMFLOAT3& p_origin, XMFLOAT3& p_direction, float p_width, const float& p_range, int& o_flag) { if(p_range <= 0.0f) { cout << "Physcs. Raytracer. Sweep. Range of sweep was zero or below" << endl; return -1; } // Cast directx things to physx PxVec3 origin = PxVec3(p_origin.x, p_origin.y, p_origin.z); PxVec3 direction = PxVec3(p_direction.x, p_direction.y, p_direction.z); direction.normalize(); PxSweepBuffer hit; // Used to save the hit /// Paramters for the sweep // PxGeometry* geometry bool status = m_utils.m_worldScene->sweep(PxSphereGeometry(p_width), PxTransform(origin), direction, p_range, hit, PxHitFlag::eMESH_BOTH_SIDES); // hit.block.position; if(!status && !hit.hasBlock) { // No hit detected, return -1 TODOKO Maybee i should return something better? return -1; } // Start with checking static and dynamic rigid bodies unordered_map<PxRigidActor*, int> idsByRigidBody = m_utils.m_rigidBodyManager->GetIDsByBodies(); if(idsByRigidBody.find(hit.block.actor) != idsByRigidBody.end()) { PxRigidActor* actorAsRigic = (PxRigidActor*)hit.block.actor; if(actorAsRigic->isRigidDynamic()) { PxRigidDynamic* actorsAsDynamic = (PxRigidDynamic*)hit.block.actor; if(actorsAsDynamic->getRigidBodyFlags() & PxRigidBodyFlag::eKINEMATIC) { o_flag = 0; } } else if(actorAsRigic->isRigidStatic()) { o_flag = 3; } return idsByRigidBody.find(hit.block.actor)->second; } else { // Nothing } // Now comes the difficult task of checking vs character controllers unordered_map<PxController*, int> idsByCharacterController = m_utils.m_characterControlManager->GetIdsByControllers(); for(auto pairs : idsByCharacterController) // Loop through every pair in the list { if(pairs.first->getActor() == hit.block.actor) // The first part contains the actor pointer { o_flag = 1; return pairs.second; // If this is true we found a hit vs character controller, second contains ID } } return -1; }
void physx::PxSetGroupsMask(const PxRigidActor& actor, const PxGroupsMask& mask) { PxFilterData tmp; PxFilterData fd = convert(mask); if (actor.getNbShapes() == 1) { PxShape* shape = NULL; actor.getShapes(&shape, 1); // retrieve current group tmp = shape->getSimulationFilterData(); fd.word0 = tmp.word0; // set new filter data shape->setSimulationFilterData(fd); } else { PxShape* shape; PxU32 numShapes = actor.getNbShapes(); shdfnd::InlineArray<PxShape*, 64> shapes; if(numShapes > 64) { shapes.resize(64); } else { shapes.resize(numShapes); } PxU32 iter = 1 + numShapes/64; for(PxU32 i=0; i < iter; i++) { PxU32 offset = i * 64; PxU32 size = numShapes - offset; if(size > 64) size = 64; actor.getShapes(shapes.begin(), size, offset); for(PxU32 j = size; j--;) { // retrieve current group mask shape = shapes[j]; // retrieve current group tmp = shape->getSimulationFilterData(); fd.word0 = tmp.word0; // set new filter data shape->setSimulationFilterData(fd); } } } }
void physx::PxSetGroup(const PxRigidActor& actor, const PxU16 collisionGroup) { PX_CHECK_AND_RETURN(collisionGroup < 32,"Collision group must be less than 32"); PxFilterData fd; if (actor.getNbShapes() == 1) { PxShape* shape = NULL; actor.getShapes(&shape, 1); // retrieve current group mask fd = shape->getSimulationFilterData(); fd.word0 = collisionGroup; // set new filter data shape->setSimulationFilterData(fd); } else { PxShape* shape; PxU32 numShapes = actor.getNbShapes(); shdfnd::InlineArray<PxShape*, 64> shapes; if(numShapes > 64) { shapes.resize(64); } else { shapes.resize(numShapes); } PxU32 iter = 1 + numShapes/64; for(PxU32 i=0; i < iter; i++) { PxU32 offset = i * 64; PxU32 size = numShapes - offset; if(size > 64) size = 64; actor.getShapes(shapes.begin(), size, offset); for(PxU32 j = size; j--;) { // retrieve current group mask shape = shapes[j]; fd = shape->getSimulationFilterData(); fd.word0 = collisionGroup; // set new filter data shape->setSimulationFilterData(fd); } } } }
void PhysXRigidManager::move(std::string scene, float * transform) { if (rigidBodies.find(scene) != rigidBodies.end()) { PxRigidActor * actor = rigidBodies[scene].info.actor->is<PxRigidActor>(); if (actor) { rigidBodies[scene].info.extInfo.transform = transform; actor->setGlobalPose(PxTransform(PxMat44(transform))); } } }
PxGroupsMask physx::PxGetGroupsMask(const PxRigidActor& actor) { PX_CHECK_AND_RETURN_VAL(actor.getNbShapes() >= 1,"At least one shape must be in actor",PxGroupsMask()); PxShape* shape = NULL; actor.getShapes(&shape, 1); PxFilterData fd = shape->getSimulationFilterData(); return convert(fd); }
PxU16 physx::PxGetGroup(const PxRigidActor& actor) { PX_CHECK_AND_RETURN_NULL(actor.getNbShapes() >= 1,"There must be a shape in actor"); PxShape* shape = NULL; actor.getShapes(&shape, 1); PxFilterData fd = shape->getSimulationFilterData(); return (PxU16)fd.word0; }
PxExtendedVec3 SampleNorthPoleCameraController::computeCameraTarget() { PxRigidActor* characterActor = mCCT.getActor(); PxShape* shape; characterActor->getShapes(&shape,1); PxCapsuleGeometry geom; shape->getCapsuleGeometry(geom); const PxExtendedVec3 headPos = PxExtendedVec3(0,geom.halfHeight+geom.radius,0); return mCCT.getPosition() + headPos; }
osg::Matrix PhysXInterface::getMatrix( int id ) { PxRigidActor* actor = _actors[id]; if ( actor ) { float m[16]; PxMat44 pxMat( actor->getGlobalPose() ); for ( int i=0; i<16; ++i ) m[i] = *(pxMat.front() + i); return osg::Matrix(&m[0]); } return osg::Matrix(); }
void PhysXHeightfield::InitHeightfield(PxPhysics* physics, PxScene* scene, const char* filename) { float xScale = 0.0025f; float yScale = 0.0025f; float zScale = 10.00f; // NOTE: Assuming that heightfield texture has B8G8R8A8 format. if(LoadHeightfield(filename)) { PxU16 nbColumns = PxU16(mHeightfield.width); PxU16 nbRows = PxU16(mHeightfield.height); PxHeightFieldDesc heightFieldDesc; heightFieldDesc.format = PxHeightFieldFormat::eS16_TM; heightFieldDesc.nbColumns = nbColumns; heightFieldDesc.nbRows = nbRows; heightFieldDesc.samples.data = mHeightfield.data; heightFieldDesc.samples.stride = sizeof(PxHeightFieldSample); //heightFieldDesc.convexEdgeThreshold = 0; PxHeightField* heightField = physics->createHeightField(heightFieldDesc); // create shape for heightfield PxTransform pose(PxVec3(-((PxReal)nbRows*yScale) / 2.0f, 0.0f, -((PxReal)nbColumns*xScale) / 2.0f), PxQuat::createIdentity()); // PxTransform pose = PxTransform::createIdentity(); pose.p = PxVec3(-((nbColumns/2)*xScale),0.0,-((nbColumns/2)*xScale)); PxRigidActor* hf = physics->createRigidStatic(pose); if(!hf) return; const PxMaterial* mMat = physics->createMaterial(0.9f, 0.9f, 0.001f); //PxShape* shape = hf->createShape((PxHeightFieldGeometry(heightField, PxMeshGeometryFlags(), yScale, xScale, xScale)), *mMat); //PxHeightFieldGeometry hfGeom(heightField, PxMeshGeometryFlags(), heightScale, rowScale, colScale); //PxShape* aHeightFieldShape = aHeightFieldActor->createShape(hfGeom, aMaterialArray, nbMaterials); PxHeightFieldGeometry hfGeom(heightField, PxMeshGeometryFlags(), yScale, xScale, xScale); PxShape* hfShape = hf->createShape(hfGeom, *mMat); if(!hfShape) return; //shape->setFlag(PxShapeFlag::ePARTICLE_DRAIN, false); //shape->setFlag(PxShapeFlag::eSIMULATION_SHAPE, true); //shape->setFlag(PxShapeFlag::eUSE_SWEPT_BOUNDS, true); // add actor to the scene scene->addActor(*hf); } }
bool Picking::pick(int x, int y) { PxScene& scene = mFrame.getActiveScene(); PxVec3 rayOrig, rayDir, pickOrig; computeCameraRay(rayOrig, rayDir, pickOrig, x, y); // raycast rigid bodies in scene PxRaycastHit hit; hit.shape = NULL; PxRaycastBuffer hit1; scene.raycast(rayOrig, rayDir, PX_MAX_F32, hit1, PxHitFlag::ePOSITION); hit = hit1.block; if(hit.shape) { const char* shapeName = hit.shape->getName(); if(shapeName) printf("Picked shape name: %s\n", shapeName); PxRigidActor* actor = hit.actor; PX_ASSERT(actor); mSelectedActor = static_cast<PxRigidActor*>(actor->is<PxRigidDynamic>()); if(!mSelectedActor) mSelectedActor = static_cast<PxRigidActor*>(actor->is<PxArticulationLink>()); //ML::this is very useful to debug some collision problem PxTransform t = actor->getGlobalPose(); // printf("id = %i\n PxTransform transform(PxVec3(%f, %f, %f), PxQuat(%f, %f, %f, %f))\n", (int)actor->userData, t.p.x, t.p.y, t.p.z, t.q.x, t.q.y, t.q.z, t.q.w); } else { mSelectedActor = 0; } if(mSelectedActor) { printf("Actor '%s' picked! (userData: %p)\n", mSelectedActor->getName(), mSelectedActor->userData); //if its a dynamic rigid body, joint it for dragging purposes: grabActor(hit.position, rayOrig); } #ifdef VISUALIZE_PICKING_RAYS Ray ray; ray.origin = rayOrig; ray.dir = rayDir; mRays.push_back(ray); #endif return true; }
void Picking::grabActor(const PxVec3& worldImpact, const PxVec3& rayOrigin) { if(!mSelectedActor || (mSelectedActor->getType() != PxActorType::eRIGID_DYNAMIC && mSelectedActor->getType() != PxActorType::eARTICULATION_LINK)) return; PxScene& scene = mFrame.getActiveScene(); PxPhysics& physics = scene.getPhysics(); //create a shape less actor for the mouse { mMouseActor = physics.createRigidDynamic(PxTransform(worldImpact, PxQuat::createIdentity())); mMouseActor->setRigidDynamicFlag(PxRigidDynamicFlag::eKINEMATIC, true); mMouseActor->setMass(1.0f); mMouseActor->setMassSpaceInertiaTensor(PxVec3(1.0f, 1.0f, 1.0f)); scene.addActor(*mMouseActor); mFrame.addPhysicsActors(mMouseActor); } PxRigidActor* pickedActor = static_cast<PxRigidActor*>(mSelectedActor); #if USE_D6_JOINT_FOR_MOUSE mMouseJoint = PxD6JointCreate( physics, mMouseActor, PxTransform::createIdentity(), pickedActor, PxTransform(pickedActor->getGlobalPose().transformInv(worldImpact))); #elif USE_SPHERICAL_JOINT_FOR_MOUSE mMouseJoint = PxSphericalJointCreate(physics, mMouseActor, PxTransform::createIdentity(), pickedActor, PxTransform(pickedActor->getGlobalPose().transformInv(worldImpact))); #else mMouseJoint = PxDistanceJointCreate(physics, mMouseActor, PxTransform::createIdentity(), pickedActor, PxTransform(pickedActor->getGlobalPose().transformInv(worldImpact))); mMouseJoint->setMaxDistance(0.0f); mMouseJoint->setMinDistance(0.0f); mMouseJoint->setDistanceJointFlags(PxDistanceJointFlag::eMAX_DISTANCE_ENABLED); #endif mDistanceToPicked = (worldImpact - rayOrigin).magnitude(); }
void PhysX::AddWorldImpulseAtWorldPos(PintObjectHandle handle, const Point& world_impulse, const Point& world_pos) { PxRigidActor* RigidActor = GetActorFromHandle(handle); if(!RigidActor) { PxShape* Shape = GetShapeFromHandle(handle); ASSERT(Shape); RigidActor = &Shape->getActor(); } if(RigidActor->getConcreteType()==PxConcreteType::eRIGID_DYNAMIC) { PxRigidDynamic* RigidDynamic = static_cast<PxRigidDynamic*>(RigidActor); PxRigidBodyExt::addForceAtPos(*RigidDynamic, ToPxVec3(world_impulse), ToPxVec3(world_pos), PxForceMode::eIMPULSE); } }
void PhysX::AddLocalTorque(PintObjectHandle handle, const Point& local_torque) { PxRigidActor* RigidActor = GetActorFromHandle(handle); if(!RigidActor) { PxShape* Shape = GetShapeFromHandle(handle); ASSERT(Shape); RigidActor = &Shape->getActor(); } if(RigidActor->getConcreteType()==PxConcreteType::eRIGID_DYNAMIC) { PxRigidDynamic* RigidDynamic = static_cast<PxRigidDynamic*>(RigidActor); const PxVec3 GlobalTorque = RigidDynamic->getGlobalPose().rotate(ToPxVec3(local_torque)); RigidDynamic->addTorque(GlobalTorque, PxForceMode::eACCELERATION, true); } }
void TCompCharacterController::SetFilterData(PxFilterData& filter) { PxRigidActor *ra = m_pActor->getActor()->isRigidActor(); m_filter = filter; if (ra) { const PxU32 numShapes = ra->getNbShapes(); PxShape **ptr; ptr = new PxShape*[numShapes]; ra->getShapes(ptr, numShapes); for (PxU32 i = 0; i < numShapes; i++) { PxShape* shape = ptr[i]; shape->setSimulationFilterData(m_filter); shape->setQueryFilterData(m_filter); } } }
PxBounds3 NpShapeManager::getWorldBounds(const PxRigidActor& actor) const { PxBounds3 bounds(PxBounds3::empty()); const PxU32 nbShapes = getNbShapes(); PxTransform actorPose = actor.getGlobalPose(); NpShape*const* PX_RESTRICT shapes = getShapes(); for(PxU32 i=0;i<nbShapes;i++) bounds.include(Gu::computeBounds(shapes[i]->getScbShape().getGeometry(), actorPose * shapes[i]->getLocalPoseFast(), !physx::gUnifiedHeightfieldCollision)); return bounds; }
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; }
PR PhysX3::GetWorldTransform(PintObjectHandle handle) { PxTransform Pose; PxRigidActor* RigidActor = GetActorFromHandle(handle); if(RigidActor) { Pose = RigidActor->getGlobalPose(); } else { PxShape* Shape = GetShapeFromHandle(handle); ASSERT(Shape); #ifdef SUPPORT_SHARED_SHAPES ASSERT(Shape->getActor()); Pose = PxShapeExt::getGlobalPose(*Shape, *Shape->getActor()); #else Pose = PxShapeExt::getGlobalPose(*Shape); #endif } return PR(ToPoint(Pose.p), ToQuat(Pose.q)); }
void TCompCharacterController::SetCollisions(bool new_collisions) { PxRigidActor *ra = m_pActor->getActor()->isRigidActor(); if (ra) { const PxU32 numShapes = ra->getNbShapes(); PxShape **ptr; ptr = new PxShape*[numShapes]; ra->getShapes(ptr, numShapes); for (PxU32 i = 0; i < numShapes; i++) { PxShape* shape = ptr[i]; if (!new_collisions) { m_filter.word1 &= ~ItLightensFilter::eCOLLISION; m_filter.word1 &= ~ItLightensFilter::eCAN_TRIGGER; //for test only } else { m_filter.word1 |= ItLightensFilter::eCOLLISION; m_filter.word1 |= ItLightensFilter::eCAN_TRIGGER; //for test only } shape->setSimulationFilterData(m_filter); shape->setQueryFilterData(m_filter); } } }
void NpShapeManager::setupAllSceneQuery(NpScene* scene, const PxRigidActor& actor, bool hasPrunerStructure, const PxBounds3* bounds) { PX_ASSERT(scene); // shouldn't get here unless we're in a scene SceneQueryManager& sqManager = scene->getSceneQueryManagerFast(); const PxU32 nbShapes = getNbShapes(); NpShape*const *shapes = getShapes(); const PxType actorType = actor.getConcreteType(); const bool isDynamic = actorType == PxConcreteType::eRIGID_DYNAMIC || actorType == PxConcreteType::eARTICULATION_LINK; for(PxU32 i=0;i<nbShapes;i++) { if(isSceneQuery(*shapes[i])) setPrunerData(i, sqManager.addPrunerShape(*shapes[i], actor, isDynamic, bounds ? bounds + i : NULL, hasPrunerStructure)); } }
void NpShapeManager::visualize(Cm::RenderOutput& out, NpScene* scene, const PxRigidActor& actor) { const PxU32 nbShapes = getNbShapes(); NpShape*const* PX_RESTRICT shapes = getShapes(); PxTransform actorPose = actor.getGlobalPose(); const bool visualizeCompounds = (nbShapes>1) && scene->getVisualizationParameter(PxVisualizationParameter::eCOLLISION_COMPOUNDS)!=0.0f; PxBounds3 compoundBounds(PxBounds3::empty()); for(PxU32 i=0;i<nbShapes;i++) { Scb::Shape& shape = shapes[i]->getScbShape(); if(shape.getFlags() & PxShapeFlag::eVISUALIZATION) { shapes[i]->visualize(out, actor); if(visualizeCompounds) compoundBounds.include(Gu::computeBounds(shape.getGeometry(), actorPose*shapes[i]->getLocalPose(), !physx::gUnifiedHeightfieldCollision)); } } if(visualizeCompounds && !compoundBounds.isEmpty()) out << PxU32(PxDebugColor::eARGB_MAGENTA) << PxMat44(PxIdentity) << Cm::DebugBox(compoundBounds); }
void USkeletalMeshComponent::UpdateKinematicBonesToAnim(const TArray<FTransform>& InSpaceBases, ETeleportType Teleport, bool bNeedsSkinning, EAllowKinematicDeferral DeferralAllowed) { SCOPE_CYCLE_COUNTER(STAT_UpdateRBBones); // This below code produces some interesting result here // - below codes update physics data, so if you don't update pose, the physics won't have the right result // - but if we just update physics bone without update current pose, it will have stale data // If desired, pass the animation data to the physics joints so they can be used by motors. // See if we are going to need to update kinematics const bool bUpdateKinematics = (KinematicBonesUpdateType != EKinematicBonesUpdateToPhysics::SkipAllBones); const bool bTeleport = Teleport == ETeleportType::TeleportPhysics; // If desired, update physics bodies associated with skeletal mesh component to match. if(!bUpdateKinematics && !(bTeleport && IsAnySimulatingPhysics())) { // nothing to do return; } // Get the scene, and do nothing if we can't get one. FPhysScene* PhysScene = nullptr; if (GetWorld() != nullptr) { PhysScene = GetWorld()->GetPhysicsScene(); } if(PhysScene == nullptr) { return; } const FTransform& CurrentLocalToWorld = ComponentToWorld; // Gracefully handle NaN if(CurrentLocalToWorld.ContainsNaN()) { return; } // If we are only using bodies for physics, don't need to move them right away, can defer until simulation (unless told not to) if(BodyInstance.GetCollisionEnabled() == ECollisionEnabled::PhysicsOnly && DeferralAllowed == EAllowKinematicDeferral::AllowDeferral) { PhysScene->MarkForPreSimKinematicUpdate(this, Teleport, bNeedsSkinning); return; } #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) // If desired, draw the skeleton at the point where we pass it to the physics. if (bShowPrePhysBones && SkeletalMesh && InSpaceBases.Num() == SkeletalMesh->RefSkeleton.GetNum()) { for (int32 i = 1; i<InSpaceBases.Num(); i++) { FVector ThisPos = CurrentLocalToWorld.TransformPosition(InSpaceBases[i].GetLocation()); int32 ParentIndex = SkeletalMesh->RefSkeleton.GetParentIndex(i); FVector ParentPos = CurrentLocalToWorld.TransformPosition(InSpaceBases[ParentIndex].GetLocation()); GetWorld()->LineBatcher->DrawLine(ThisPos, ParentPos, AnimSkelDrawColor, SDPG_Foreground); } } #endif // warn if it has non-uniform scale const FVector& MeshScale3D = CurrentLocalToWorld.GetScale3D(); #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) if( !MeshScale3D.IsUniform() ) { UE_LOG(LogPhysics, Log, TEXT("USkeletalMeshComponent::UpdateKinematicBonesToAnim : Non-uniform scale factor (%s) can cause physics to mismatch for %s SkelMesh: %s"), *MeshScale3D.ToString(), *GetFullName(), SkeletalMesh ? *SkeletalMesh->GetFullName() : TEXT("NULL")); } #endif if (bEnablePerPolyCollision == false) { const UPhysicsAsset* const PhysicsAsset = GetPhysicsAsset(); if (PhysicsAsset && SkeletalMesh && Bodies.Num() > 0) { #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) if (!ensure(PhysicsAsset->BodySetup.Num() == Bodies.Num())) { // related to TTP 280315 UE_LOG(LogPhysics, Warning, TEXT("Mesh (%s) has PhysicsAsset(%s), and BodySetup(%d) and Bodies(%d) don't match"), *SkeletalMesh->GetName(), *PhysicsAsset->GetName(), PhysicsAsset->BodySetup.Num(), Bodies.Num()); return; } #endif #if WITH_PHYSX // Lock the scenes we need (flags set in InitArticulated) if(bHasBodiesInSyncScene) { SCENE_LOCK_WRITE(PhysScene->GetPhysXScene(PST_Sync)) } if (bHasBodiesInAsyncScene) { SCENE_LOCK_WRITE(PhysScene->GetPhysXScene(PST_Async)) } #endif // Iterate over each body for (int32 i = 0; i < Bodies.Num(); i++) { // If we have a physics body, and its kinematic... FBodyInstance* BodyInst = Bodies[i]; check(BodyInst); if (BodyInst->IsValidBodyInstance() && (bTeleport || !BodyInst->IsInstanceSimulatingPhysics())) { const int32 BoneIndex = BodyInst->InstanceBoneIndex; // If we could not find it - warn. if (BoneIndex == INDEX_NONE || BoneIndex >= GetNumSpaceBases()) { const FName BodyName = PhysicsAsset->BodySetup[i]->BoneName; UE_LOG(LogPhysics, Log, TEXT("UpdateRBBones: WARNING: Failed to find bone '%s' need by PhysicsAsset '%s' in SkeletalMesh '%s'."), *BodyName.ToString(), *PhysicsAsset->GetName(), *SkeletalMesh->GetName()); } else { #if WITH_PHYSX // update bone transform to world const FTransform BoneTransform = InSpaceBases[BoneIndex] * CurrentLocalToWorld; if(!BoneTransform.IsValid()) { const FName BodyName = PhysicsAsset->BodySetup[i]->BoneName; UE_LOG(LogPhysics, Warning, TEXT("UpdateKinematicBonesToAnim: Trying to set transform with bad data %s on PhysicsAsset '%s' in SkeletalMesh '%s' for bone '%s'"), *BoneTransform.ToHumanReadableString(), *PhysicsAsset->GetName(), *SkeletalMesh->GetName(), *BodyName.ToString()); BoneTransform.DiagnosticCheck_IsValid(); //In special nan mode we want to actually ensure continue; } // If kinematic and not teleporting, set kinematic target if (!BodyInst->IsInstanceSimulatingPhysics() && !bTeleport) { PhysScene->SetKinematicTarget_AssumesLocked(BodyInst, BoneTransform, true); } // Otherwise, set global pose else { const PxTransform PNewPose = U2PTransform(BoneTransform); ensure(PNewPose.isValid()); PxRigidActor* RigidActor = BodyInst->GetPxRigidActor_AssumesLocked(); // This should never fail because IsValidBodyInstance() passed above RigidActor->setGlobalPose(PNewPose); } #endif // now update scale // if uniform, we'll use BoneTranform if (MeshScale3D.IsUniform()) { // @todo UE4 should we update scale when it's simulated? BodyInst->UpdateBodyScale(BoneTransform.GetScale3D()); } else { // @note When you have non-uniform scale on mesh base, // hierarchical bone transform can update scale too often causing performance issue // So we just use mesh scale for all bodies when non-uniform // This means physics representation won't be accurate, but // it is performance friendly by preventing too frequent physics update BodyInst->UpdateBodyScale(MeshScale3D); } } } else { //make sure you have physics weight or blendphysics on, otherwise, you'll have inconsistent representation of bodies // @todo make this to be kismet log? But can be too intrusive if (!bBlendPhysics && BodyInst->PhysicsBlendWeight <= 0.f && BodyInst->BodySetup.IsValid()) { //It's not clear whether this should be a warning. There are certainly cases where you interpolate the blend weight towards 0. The blend feature needs some work which will probably change this in the future. //Making it Verbose for now UE_LOG(LogPhysics, Verbose, TEXT("%s(Mesh %s, PhysicsAsset %s, Bone %s) is simulating, but no blending. "), *GetName(), *GetNameSafe(SkeletalMesh), *GetNameSafe(PhysicsAsset), *BodyInst->BodySetup.Get()->BoneName.ToString()); } } } #if WITH_PHYSX // Unlock the scenes if (bHasBodiesInSyncScene) { SCENE_UNLOCK_WRITE(PhysScene->GetPhysXScene(PST_Sync)) } if (bHasBodiesInAsyncScene) { SCENE_UNLOCK_WRITE(PhysScene->GetPhysXScene(PST_Async)) } #endif } } else { //per poly update requires us to update all vertex positions if (MeshObject)
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 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; }
PxRigidActor* SampleSubmarine::loadTerrain(const char* name, const PxReal heightScale, const PxReal rowScale, const PxReal columnScale) { PxRigidActor* heightFieldActor = NULL; BmpLoader loader; if(loader.loadBmp(getSampleMediaFilename(name))) { PxU16 nbColumns = PxU16(loader.mWidth), nbRows = PxU16(loader.mHeight); PxHeightFieldDesc heightFieldDesc; heightFieldDesc.nbColumns = nbColumns; heightFieldDesc.nbRows = nbRows; PxU32* samplesData = (PxU32*)SAMPLE_ALLOC(sizeof(PxU32)*nbColumns * nbRows); heightFieldDesc.samples.data = samplesData; heightFieldDesc.samples.stride = sizeof(PxU32); PxU8* currentByte = (PxU8*)heightFieldDesc.samples.data; PxU8* loader_ptr = loader.mRGB; PxVec3Alloc* vertexesA = SAMPLE_NEW(PxVec3Alloc)[nbRows * nbColumns]; PxF32* uvs = (PxF32*)SAMPLE_ALLOC(sizeof(PxF32) * nbRows * nbColumns * 2); PxVec3* vertexes = vertexesA; for (PxU32 row = 0; row < nbRows; row++) { for (PxU32 column = 0; column < nbColumns; column++) { PxHeightFieldSample* currentSample = (PxHeightFieldSample*)currentByte; currentSample->height = *loader_ptr; vertexes[row * nbColumns + column] = PxVec3(PxReal(row)*rowScale, PxReal(currentSample->height * heightScale), PxReal(column)*columnScale); uvs[(row * nbColumns + column)*2 + 0] = (float)column/7.0f; uvs[(row * nbColumns + column)*2 + 1] = (float)row/7.0f; currentSample->materialIndex0 = 0; currentSample->materialIndex1 = 0; currentSample->clearTessFlag(); currentByte += heightFieldDesc.samples.stride; loader_ptr += 3 * sizeof(PxU8); } } PxHeightField* heightField = getPhysics().createHeightField(heightFieldDesc); if(!heightField) fatalError("createHeightField failed!"); // create shape for heightfield PxTransform pose(PxVec3(-((PxReal)nbRows*rowScale) / 2.0f, 0.0f, -((PxReal)nbColumns*columnScale) / 2.0f), PxQuat::createIdentity()); heightFieldActor = getPhysics().createRigidStatic(pose); if(!heightFieldActor) fatalError("createRigidStatic failed!"); PxShape* shape = heightFieldActor->createShape(PxHeightFieldGeometry(heightField, PxMeshGeometryFlags(), heightScale, rowScale, columnScale), getDefaultMaterial()); if(!shape) fatalError("createShape failed!"); // add actor to the scene getActiveScene().addActor(*heightFieldActor); // create indices PxU32* indices = (PxU32*)SAMPLE_ALLOC(sizeof(PxU32)*((nbColumns - 1) * (nbRows - 1) * 3 * 2)); for(int i = 0; i < (nbColumns - 1); ++i) { for(int j = 0; j < (nbRows - 1); ++j) { // first triangle indices[6 * (i * (nbRows - 1) + j) + 0] = (i + 1) * nbRows + j; indices[6 * (i * (nbRows - 1) + j) + 1] = i * nbRows + j; indices[6 * (i * (nbRows - 1) + j) + 2] = i * nbRows + j + 1; // second triangle indices[6 * (i * (nbRows - 1) + j) + 3] = (i + 1) * nbRows + j + 1; indices[6 * (i * (nbRows - 1) + j) + 4] = (i + 1) * nbRows + j; indices[6 * (i * (nbRows - 1) + j) + 5] = i * nbRows + j + 1; } } // add mesh to renderer RAWMesh data; data.mName = name; data.mTransform = PxTransform::createIdentity(); data.mNbVerts = nbColumns * nbRows; data.mVerts = vertexes; data.mVertexNormals = NULL; data.mUVs = uvs; data.mMaterialID = MATERIAL_TERRAIN_MUD; data.mNbFaces = (nbColumns - 1) * (nbRows - 1) * 2; data.mIndices = indices; RenderMeshActor* hf_mesh = createRenderMeshFromRawMesh(data); if(!hf_mesh) fatalError("createRenderMeshFromRawMesh failed!"); hf_mesh->setPhysicsShape(shape); shape->setFlag(PxShapeFlag::eVISUALIZATION, false); SAMPLE_FREE(indices); SAMPLE_FREE(uvs); DELETEARRAY(vertexesA); SAMPLE_FREE(samplesData); } return heightFieldActor; }
// Creates an physics entity from an entity info structure and a starting transform void PhysicsEngine::createEntity(PhysicsEntity* entity, PhysicsEntityInfo* info, PxTransform transform) { transform.p.y += info->yPosOffset; // Set static/dynamic info for actor depending on its type PxRigidActor* actor; if (info->type == PhysicsType::DYNAMIC) { DynamicInfo* dInfo = info->dynamicInfo; PxRigidDynamic* dynamicActor = physics->createRigidDynamic(transform); dynamicActor->setLinearDamping(dInfo->linearDamping); dynamicActor->setAngularDamping(dInfo->angularDamping); dynamicActor->setMaxAngularVelocity(dInfo->maxAngularVelocity); actor = dynamicActor; } else if (info->type == PhysicsType::STATIC) { PxRigidStatic* staticActor = physics->createRigidStatic(transform); actor = staticActor; } // All shapes in actor for (auto sInfo : info->shapeInfo) { // Create material and geometry for shape and add it to actor PxGeometry* geometry; PxMaterial* material; if (sInfo->geometry == Geometry::SPHERE) { SphereInfo* sphInfo = (SphereInfo*)sInfo; geometry = new PxSphereGeometry(sphInfo->radius); } else if (sInfo->geometry == Geometry::BOX) { BoxInfo* boxInfo = (BoxInfo*)sInfo; geometry = new PxBoxGeometry(boxInfo->halfX, boxInfo->halfY, boxInfo->halfZ); } else if (sInfo->geometry == Geometry::CAPSULE) { CapsuleInfo* capInfo = (CapsuleInfo*)sInfo; geometry = new PxCapsuleGeometry(capInfo->radius, capInfo->halfHeight); } else if (sInfo->geometry == Geometry::CONVEX_MESH) { ConvexMeshInfo* cmInfo = (ConvexMeshInfo*)sInfo; PxConvexMesh* mesh = helper->createConvexMesh(cmInfo->verts.data(), cmInfo->verts.size()); geometry = new PxConvexMeshGeometry(mesh); } // Not working until index drawing is set up else if (sInfo->geometry == Geometry::TRIANGLE_MESH) { TriangleMeshInfo* tmInfo = (TriangleMeshInfo*)sInfo; PxTriangleMesh* mesh = helper->createTriangleMesh(tmInfo->verts.data(), tmInfo->verts.size(), tmInfo->faces.data(), tmInfo->faces.size()/3); geometry = new PxTriangleMeshGeometry(mesh); } material = (sInfo->isDrivable) ? drivingSurfaces[0] : physics->createMaterial(sInfo->dynamicFriction, sInfo->staticFriction, sInfo->restitution); PxShape* shape = actor->createShape(*geometry, *material); // TODO support shape flags shape->setLocalPose(sInfo->transform); material->release(); delete geometry; // Set up querry filter data for shape PxFilterData qryFilterData; qryFilterData.word3 = (sInfo->isDrivable) ? (PxU32)Surface::DRIVABLE : (PxU32)Surface::UNDRIVABLE; shape->setQueryFilterData(qryFilterData); // Set up simulation filter data for shape PxFilterData simFilterData; simFilterData.word0 = (PxU32)sInfo->filterFlag0; simFilterData.word1 = (PxU32)sInfo->filterFlag1; simFilterData.word2 = (PxU32)sInfo->filterFlag2; simFilterData.word3 = (PxU32)sInfo->filterFlag3; shape->setSimulationFilterData(simFilterData); if (info->type == PhysicsType::DYNAMIC) { DynamicInfo* dInfo = info->dynamicInfo; PxRigidBodyExt::updateMassAndInertia(*(PxRigidBody*)actor, dInfo->density, &dInfo->cmOffset); PxRigidBody* body = (PxRigidBody*)actor; } } // Add actor to scene, set actor for entity, and set user data for actor. Creates one to one between entities and phyX scene->addActor(*actor); entity->setActor(actor); actor->userData = entity; }
void SampleParticles::loadTerrain(const char* path, PxReal xScale, PxReal yScale, PxReal zScale) { SampleFramework::SampleAsset* asset = getAsset(terrain_hf, SampleFramework::SampleAsset::ASSET_TEXTURE); mManagedAssets.push_back(asset); PX_ASSERT(asset->getType() == SampleFramework::SampleAsset::ASSET_TEXTURE); SampleFramework::SampleTextureAsset* texAsset = static_cast<SampleFramework::SampleTextureAsset*>(asset); SampleRenderer::RendererTexture2D* heightfieldTexture = texAsset->getTexture(); // NOTE: Assuming that heightfield texture has B8G8R8A8 format. if(heightfieldTexture) { PxU16 nbColumns = PxU16(heightfieldTexture->getWidth()); PxU16 nbRows = PxU16(heightfieldTexture->getHeight()); PxHeightFieldDesc heightFieldDesc; heightFieldDesc.nbColumns = nbColumns; heightFieldDesc.nbRows = nbRows; PxU32* samplesData = (PxU32*)SAMPLE_ALLOC(sizeof(PxU32) * nbColumns * nbRows); heightFieldDesc.samples.data = samplesData; heightFieldDesc.samples.stride = sizeof(PxU32); heightFieldDesc.convexEdgeThreshold = 0; PxU8* currentByte = (PxU8*)heightFieldDesc.samples.data; PxU32 texturePitch = 0; PxU8* loaderPtr = static_cast<PxU8*>(heightfieldTexture->lockLevel(0, texturePitch)); PxVec3Alloc* verticesA = SAMPLE_NEW(PxVec3Alloc)[nbRows * nbColumns]; PxVec3* vertices = verticesA; PxReal* UVs = (PxReal*)SAMPLE_ALLOC(sizeof(PxReal) * nbRows * nbColumns * 2); for (PxU32 row = 0; row < nbRows; row++) { for (PxU32 column = 0; column < nbColumns; column++) { PxHeightFieldSample* currentSample = (PxHeightFieldSample*)currentByte; currentSample->height = *loaderPtr; vertices[row * nbColumns + column] = PxVec3(PxReal(row) * xScale, PxReal(currentSample->height * zScale), PxReal(column) * yScale); UVs[2 * (row * nbColumns + column)] = (PxReal(row) / PxReal(nbRows)) * 7.0f; UVs[2 * (row * nbColumns + column) + 1] = (PxReal(column) / PxReal(nbColumns)) * 7.0f; currentSample->materialIndex0 = 0; currentSample->materialIndex1 = 0; currentSample->clearTessFlag(); currentByte += heightFieldDesc.samples.stride; loaderPtr += 4 * sizeof(PxU8); } } PxHeightField* heightField = getPhysics().createHeightField(heightFieldDesc); // free allocated memory for heightfield samples description SAMPLE_FREE(samplesData); // create shape for heightfield PxTransform pose(PxVec3(-((PxReal)nbRows*yScale) / 2.0f, 0.0f, -((PxReal)nbColumns*xScale) / 2.0f), PxQuat::createIdentity()); PxRigidActor* hf = getPhysics().createRigidStatic(pose); runtimeAssert(hf, "PxPhysics::createRigidStatic returned NULL\n"); PxShape* shape = hf->createShape(PxHeightFieldGeometry(heightField, PxMeshGeometryFlags(), zScale, xScale, yScale), getDefaultMaterial()); runtimeAssert(shape, "PxRigidActor::createShape returned NULL\n"); shape->setFlag(PxShapeFlag::ePARTICLE_DRAIN, false); shape->setFlag(PxShapeFlag::eSIMULATION_SHAPE, true); // add actor to the scene getActiveScene().addActor(*hf); mPhysicsActors.push_back(hf); // create indices and UVs PxU32* indices = (PxU32*)SAMPLE_ALLOC(sizeof(PxU32) * (nbColumns - 1) * (nbRows - 1) * 3 * 2); for(int i = 0; i < (nbColumns - 1); ++i) { for(int j = 0; j < (nbRows - 1); ++j) { // first triangle indices[6 * (i * (nbRows - 1) + j) + 0] = (i + 1) * nbRows + j; indices[6 * (i * (nbRows - 1) + j) + 1] = i * nbRows + j; indices[6 * (i * (nbRows - 1) + j) + 2] = i * nbRows + j + 1; // second triangle indices[6 * (i * (nbRows - 1) + j) + 3] = (i + 1) * nbRows + j + 1; indices[6 * (i * (nbRows - 1) + j) + 4] = (i + 1) * nbRows + j; indices[6 * (i * (nbRows - 1) + j) + 5] = i * nbRows + j + 1; } } // add mesh to renderer RAWMesh data; data.mName = "terrain"; data.mTransform = PxTransform::createIdentity(); data.mNbVerts = nbColumns * nbRows; data.mVerts = (PxVec3*)vertices; data.mVertexNormals = NULL; data.mUVs = UVs; data.mMaterialID = MATERIAL_HEIGHTFIELD; data.mNbFaces = (nbColumns - 1) * (nbRows - 1) * 2; data.mIndices = indices; RenderMeshActor* hf_mesh = createRenderMeshFromRawMesh(data); hf_mesh->setPhysicsShape(shape); SAMPLE_FREE(indices); SAMPLE_FREE(UVs); DELETEARRAY(verticesA); } else { char errMsg[256]; physx::string::sprintf_s(errMsg, 256, "Couldn't load %s\n", path); fatalError(errMsg); } }
void SampleCustomGravityCameraController::update(Camera& camera, PxReal dtime) { const PxExtendedVec3& currentPos = mCCT.getPosition(); const PxVec3 curPos = toVec3(currentPos); // Compute up vector for current CCT position PxVec3 upVector; mBase.mPlanet.getUpVector(upVector, curPos); PX_ASSERT(upVector.isFinite()); // Update CCT if(!mBase.isPaused()) { if(1) { bool recordPos = true; const PxU32 currentSize = mNbRecords; if(currentSize) { const PxVec3 lastPos = mHistory[currentSize-1]; // const float limit = 0.1f; const float limit = 0.5f; if((curPos - lastPos).magnitude()<limit) recordPos = false; } if(recordPos) { if(mNbRecords==POS_HISTORY_LIMIT) { for(PxU32 i=1;i<mNbRecords;i++) mHistory[i-1] = mHistory[i]; mNbRecords--; } mHistory[mNbRecords++] = curPos; } } // Subtract off the 'up' component of the view direction to get our forward motion vector. PxVec3 viewDir = camera.getViewDir(); PxVec3 forward = (viewDir - upVector * upVector.dot(viewDir)).getNormalized(); // PxVec3 forward = mForward; // Compute "right" vector PxVec3 right = forward.cross(upVector); right.normalize(); // PxVec3 right = mRightV; PxVec3 targetKeyDisplacement(0); if(mFwd) targetKeyDisplacement += forward; if(mBwd) targetKeyDisplacement -= forward; if(mRight) targetKeyDisplacement += right; if(mLeft) targetKeyDisplacement -= right; targetKeyDisplacement *= mKeyShiftDown ? mRunningSpeed : mWalkingSpeed; // targetKeyDisplacement += PxVec3(0,-9.81,0); targetKeyDisplacement *= dtime; PxVec3 targetPadDisplacement(0); targetPadDisplacement += forward * mGamepadForwardInc * mRunningSpeed; targetPadDisplacement += right * mGamepadLateralInc * mRunningSpeed; // targetPadDisplacement += PxVec3(0,-9.81,0); targetPadDisplacement *= dtime; const PxF32 heightDelta = gJump.getHeight(dtime); // printf("%f\n", heightDelta); PxVec3 upDisp = upVector; if(heightDelta!=0.0f) upDisp *= heightDelta; else upDisp *= -9.81f * dtime; const PxVec3 disp = targetKeyDisplacement + targetPadDisplacement + upDisp; //upDisp.normalize(); //printf("%f | %f | %f\n", upDisp.x, upDisp.y, upDisp.z); // printf("%f | %f | %f\n", targetKeyDisplacement.x, targetKeyDisplacement.y, targetKeyDisplacement.z); // printf("%f | %f | %f\n\n", targetPadDisplacement.x, targetPadDisplacement.y, targetPadDisplacement.z); mCCT.setUpDirection(upVector); const PxU32 flags = mCCT.move(disp, 0.001f, dtime, PxControllerFilters()); if(flags & PxControllerFlag::eCOLLISION_DOWN) { gJump.stopJump(); // printf("Stop jump\n"); } } // Update camera if(1) { mTargetYaw += mGamepadYawInc * dtime; mTargetPitch += mGamepadPitchInc * dtime; // Clamp pitch // if(mTargetPitch<mPitchMin) mTargetPitch = mPitchMin; // if(mTargetPitch>mPitchMax) mTargetPitch = mPitchMax; } if(1) { PxVec3 up = upVector; PxQuat localPitchQ(mTargetPitch, PxVec3(1.0f, 0.0f, 0.0f)); PX_ASSERT(localPitchQ.isSane()); PxMat33 localPitchM(localPitchQ); const PxVec3 upRef(0.0f, 1.0f, 0.0f); PxQuat localYawQ(mTargetYaw, upRef); PX_ASSERT(localYawQ.isSane()); PxMat33 localYawM(localYawQ); bool res; PxQuat localToWorldQ = rotationArc(upRef, up, res); static PxQuat memory(0,0,0,1); if(!res) { localToWorldQ = memory; } else { memory = localToWorldQ; } PX_ASSERT(localToWorldQ.isSane()); PxMat33 localToWorld(localToWorldQ); static PxVec3 previousUp(0.0f, 1.0f, 0.0f); static PxQuat incLocalToWorldQ(0.0f, 0.0f, 0.0f, 1.0f); PxQuat incQ = rotationArc(previousUp, up, res); PX_ASSERT(incQ.isSane()); // incLocalToWorldQ = incLocalToWorldQ * incQ; incLocalToWorldQ = incQ * incLocalToWorldQ; PX_ASSERT(incLocalToWorldQ.isSane()); incLocalToWorldQ.normalize(); PxMat33 incLocalToWorldM(incLocalToWorldQ); localToWorld = incLocalToWorldM; previousUp = up; mTest = localToWorld; //mTest = localToWorld * localYawM; // PxMat33 rot = localYawM * localToWorld; PxMat33 rot = localToWorld * localYawM * localPitchM; // PxMat33 rot = localToWorld * localYawM; PX_ASSERT(rot.column0.isFinite()); PX_ASSERT(rot.column1.isFinite()); PX_ASSERT(rot.column2.isFinite()); //// PxMat44 view(rot.column0, rot.column1, rot.column2, PxVec3(0)); mForward = -rot.column2; mRightV = rot.column0; camera.setView(PxTransform(view)); PxVec3 viewDir = camera.getViewDir(); PX_ASSERT(viewDir.isFinite()); //// PxRigidActor* characterActor = mCCT.getActor(); PxShape* shape; characterActor->getShapes(&shape,1); PxCapsuleGeometry geom; shape->getCapsuleGeometry(geom); up *= geom.halfHeight+geom.radius; const PxVec3 headPos = curPos + up; const float distanceToTarget = 10.0f; // const float distanceToTarget = 20.0f; // const float distanceToTarget = 5.0f; // const PxVec3 camPos = headPos - viewDir*distanceToTarget; const PxVec3 camPos = headPos - mForward*distanceToTarget;// + up * 20.0f; // view.t = camPos; view.column3 = PxVec4(camPos,0); // camera.setView(view); camera.setView(PxTransform(view)); mTarget = headPos; } if(0) { PxControllerState cctState; mCCT.getState(cctState); printf("\nCCT state:\n"); printf("delta: %.02f | %.02f | %.02f\n", cctState.deltaXP.x, cctState.deltaXP.y, cctState.deltaXP.z); printf("touchedShape: %p\n", cctState.touchedShape); printf("touchedObstacle: %p\n", cctState.touchedObstacle); printf("standOnAnotherCCT: %d\n", cctState.standOnAnotherCCT); printf("standOnObstacle: %d\n", cctState.standOnObstacle); printf("isMovingUp: %d\n", cctState.isMovingUp); printf("collisionFlags: %d\n", cctState.collisionFlags); } }