void Apex::LoadDynamicTriangleMesh(int numVerts, PxVec3* verts, ObjectInfo info) { PxRigidDynamic* meshActor = mPhysics->createRigidDynamic(PxTransform::createIdentity()); PxShape* meshShape, *convexShape; if(meshActor) { //meshActor->setRigidDynamicFlag(PxRigidDynamicFlag::eKINEMATIC, true); PxTriangleMeshDesc meshDesc; meshDesc.points.count = numVerts; meshDesc.points.stride = sizeof(PxVec3); meshDesc.points.data = verts; //meshDesc.triangles.count = numInds/3.; //meshDesc.triangles.stride = 3*sizeof(int); //meshDesc.triangles.data = inds; PxToolkit::MemoryOutputStream writeBuffer; bool status = mCooking->cookTriangleMesh(meshDesc, writeBuffer); if(!status) return; PxToolkit::MemoryInputData readBuffer(writeBuffer.getData(), writeBuffer.getSize()); PxTriangleMeshGeometry triGeom; triGeom.triangleMesh = mPhysics->createTriangleMesh(readBuffer); //triGeom.scale = PxMeshScale(PxVec3(info.sx,info.sy,info.sz),physx::PxQuat::createIdentity()); meshShape = meshActor->createShape(triGeom, *defaultMaterial); //meshShape->setLocalPose(PxTransform(PxVec3(info.x,info.y,info.z))); meshShape->setFlag(PxShapeFlag::eUSE_SWEPT_BOUNDS, true); PxConvexMeshDesc convexDesc; convexDesc.points.count = numVerts; convexDesc.points.stride = sizeof(PxVec3); convexDesc.points.data = verts; convexDesc.flags = PxConvexFlag::eCOMPUTE_CONVEX; if(!convexDesc.isValid()) return; PxToolkit::MemoryOutputStream buf; if(!mCooking->cookConvexMesh(convexDesc, buf)) return; PxToolkit::MemoryInputData input(buf.getData(), buf.getSize()); PxConvexMesh* convexMesh = mPhysics->createConvexMesh(input); PxConvexMeshGeometry convexGeom = PxConvexMeshGeometry(convexMesh); convexShape = meshActor->createShape(convexGeom, *defaultMaterial); //convexShape->setLocalPose(PxTransform(PxVec3(info.x,info.y,info.z))); //convexShape->setFlag(PxShapeFlag::eSIMULATION_SHAPE, false); convexShape->setFlag(PxShapeFlag::eSIMULATION_SHAPE, true); meshShape->setFlag(PxShapeFlag::eSIMULATION_SHAPE, false); meshActor->setRigidDynamicFlag(PxRigidDynamicFlag::eKINEMATIC, false); meshActor->setGlobalPose(PxTransform(PxVec3(info.x,info.y,info.z), PxQuat(info.ry, PxVec3(0.0f,1.0f,0.0f)))); mScene[mCurrentScene]->addActor(*meshActor); dynamicActors.push_back(meshActor); } }
void Spacetime::restoreState(void) { for (int i = 0; i < dynamic_actors.size(); i++) { PxRigidDynamic *current = dynamic_actors[i]; current->setLinearVelocity(linearVelocityVector[i]); current->setAngularVelocity(angularVelocityVector[i]); current->setGlobalPose(globalPoseVector[i]); } }
void UDestructibleComponent::OnUpdateTransform(bool bSkipPhysicsMove) { // We are handling the physics move below, so don't handle it at higher levels Super::OnUpdateTransform(true); if (SkeletalMesh == NULL) { return; } if (!bPhysicsStateCreated || bSkipPhysicsMove) { return; } const FTransform& CurrentLocalToWorld = ComponentToWorld; if(CurrentLocalToWorld.ContainsNaN()) { return; } // 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("UDestructibleComponent::SendPhysicsTransform : Non-uniform scale factor (%s) can cause physics to mismatch for %s SkelMesh: %s"), *MeshScale3D.ToString(), *GetFullName(), SkeletalMesh ? *SkeletalMesh->GetFullName() : TEXT("NULL")); } #endif #if WITH_APEX if (ApexDestructibleActor) { PxRigidDynamic* PRootActor = ApexDestructibleActor->getChunkPhysXActor(0); PxMat44 GlobalPose(PxMat33(U2PQuat(CurrentLocalToWorld.GetRotation())), U2PVector(CurrentLocalToWorld.GetTranslation())); if(!PRootActor || PRootActor->getScene()) //either root chunk is null meaning fractured (so there's a scene), or the root has a scene { ApexDestructibleActor->setGlobalPose(GlobalPose); }else { PRootActor->setGlobalPose(PxTransform(GlobalPose)); //we're not in a scene yet, so place the root actor in this new position } } #endif // #if WITH_APEX }
void PhysicsEngine::createVehicle(Vehicle* vehicle, PxTransform transform) { VehicleTuning* tuning = &vehicle->tuning; tuningFromUserTuning(vehicle); PxVehicleDrive4W* physVehicle = vehCreator->createVehicle4W(vehicle); //PxTransform startTransform(PxVec3(0, (tuning->chassisDims.y*0.5f + tuning->wheelRadius + 1.0f), 0), PxQuat(PxIdentity)); PxRigidDynamic* actor = physVehicle->getRigidDynamicActor(); actor->setGlobalPose(transform); scene->addActor(*actor); physVehicle->setToRestState(); physVehicle->mDriveDynData.forceGearChange(PxVehicleGearsData::eFIRST); physVehicle->mDriveDynData.setUseAutoGears(true); vehicle->setActor(actor); vehicle->setPhysicsVehicle(physVehicle); actor->userData = vehicle; vehicles.push_back(physVehicle); }
void Spacetime::setState(matrix<double> stateVector) { std::vector<PxQuat> theta; for (int i = 0; i < joints.size(); i++) { PxQuat q = PxQuat::createIdentity(); if (i == 0) { if (DOF > X) { q *= PxQuat(stateVector((i)*DOF+X,0), PxVec3(1,0,0)); } if (DOF > Y) { q *= PxQuat(stateVector((i)*DOF+Y,0), PxVec3(0,1,0)); } if (DOF > Z) { q *= PxQuat(stateVector((i)*DOF+Z,0), PxVec3(0,0,1)); } } else { if (DOF > X) { q *= PxQuat(stateVector((i)*DOF+X,0), PxVec3(1,0,0)) * theta[(i-1)*DOF+X]; } if (DOF > Y) { q *= PxQuat(stateVector((i)*DOF+Y,0), PxVec3(0,1,0)) * theta[(i-1)*DOF+Y]; } if (DOF > Z) { q *= PxQuat(stateVector((i)*DOF+Z,0), PxVec3(0,0,1)) * theta[(i-1)*DOF+Z]; } } theta.push_back(q); } dynamic_actors[0]->setGlobalPose(PxTransform(root, PxQuat::createIdentity())); PxVec3 lastJointPos = dynamic_actors[0]->getGlobalPose().p + PxVec3(0,0.5,0); PxQuat lastJointRot = dynamic_actors[0]->getGlobalPose().q; for (int i = 0; i < joints.size(); i++) { PxRigidDynamic *current = dynamic_actors[i+1]; PxVec3 t = theta[i].rotate(-joint_local_positions[i]); PxVec3 gPos = lastJointPos + t; current->setGlobalPose(PxTransform(gPos, theta[i])); lastJointPos = lastJointPos + 2*t; } for (int i = 0; i < joints.size(); i++) { PxRigidDynamic *current = dynamic_actors[i+1]; PxVec3 angularVelocity; if (DOF > X) { angularVelocity[X] = stateVector(joints.size()*DOF + i*DOF+X,0); } else { angularVelocity[X] = 0.0; } if (DOF > Y) { angularVelocity[Y] = stateVector(joints.size()*DOF + i*DOF+Y,0); } else { angularVelocity[Y] = 0.0; } if (DOF > Z) { angularVelocity[Z] = stateVector(joints.size()*DOF + i*DOF+Z,0); } else { angularVelocity[Z] = 0.0; } current->setAngularVelocity(angularVelocity); current->setLinearVelocity(PxVec3(0,0,0)); } }
bool CTank::CreateTankActor( CPhysX * pPhysX ) { if( !LoadData( "InitShader.lua" ) ) return false; // CParamTank* pParamTank = new CParamTank; // // if( !CLua::LoadParamTank( "", &pParamTank ) ) // { // // } if( GameObject * pBody = GetDetail( BODY ) ) { if ( pBody->CreateTriangleMesh( pPhysX ) ) { pBody->Update( 0.f ); PxTriangleMesh* triangleMesh = pBody->GetTriangleMesh(); D3DXVECTOR3 Position = pBody->GetPosition(); //D3DXComputeBoundingBox(Vertices, g_pMesh->GetNumVertices(), FVFVertexSize, &pMin, &pMax); //PxRigidDynamic* pRigDynAct = pPhysX->GetPhysics()->createRigidDynamic( PxTransform( physx::PxVec3( Position.x, Position.y, Position.z ) ) ); // PxRigidDynamic* pRigDynAct = PxCreateDynamic( *pPhysX->GetPhysics(), PxTransform( physx::PxVec3( Position.x, Position.y, Position.z ) ), PxBoxGeometry( 14.f, 4.6f, 6.f ), *pMaterial, 1.f ); // // if( pRigDynAct && pMaterial && triangleMesh ) // { // //pRigDynAct->createShape( PxTriangleMeshGeometry( triangleMesh ), *pMaterial ); // // pRigDynAct->setRigidDynamicFlag(PxRigidDynamicFlag::eKINEMATIC, false); // pRigDynAct->setActorFlag( PxActorFlag::eVISUALIZATION, true ); // pRigDynAct->setAngularDamping( 0.5f ); // //pRigDynAct->setMass( 10000.f ); // PxRigidBodyExt::updateMassAndInertia( *pRigDynAct, 10.f ); // // if( pMaterial ) // pPhysX->PushMaterial( pMaterial ); // // pPhysX->AddActorScene( pRigDynAct ); // m_pActor = pRigDynAct; // // return true; // } const int nWheels = 12; PxF32 chassisMass = 1500.f; const PxF32 wheelMass = 50.f; PxF32 fShift = -0.85f; PxVec3 wheelCentreOffsets[ nWheels ]; for( int i = 0; i < nWheels/2; ++i ) { wheelCentreOffsets[ i*2 ] = PxVec3( -1.2f, -0.5f, 2.1f + i * fShift ); wheelCentreOffsets[ i*2+1 ] = PxVec3( 1.2f, -0.5f, 2.1f + i * fShift ); } // размеры корпуса const PxVec3 chassisDims( 2.4f, 1.f, 6.f );// = computeChassisAABBDimensions(chassisConvexMesh); // Начало координат находится в центре шасси сетки // Установить центр масс будет ниже этой точки const PxVec3 chassisCMOffset = PxVec3( 0.f, -chassisDims.y * 0.5f - 0.65f, 0.f ); PxVehicleWheelsSimData* wheelsSimData = PxVehicleWheelsSimData::allocate( nWheels ); PxVehicleWheelsSimData& wheelsData = *wheelsSimData; PxVehicleDriveSimData4W driveData; PxVec3 chassisMOI( (chassisDims.y*chassisDims.y + chassisDims.z * chassisDims.z) * chassisMass / 12.f, (chassisDims.x*chassisDims.x + chassisDims.z * chassisDims.z) * chassisMass / 12.f, (chassisDims.x*chassisDims.x + chassisDims.y * chassisDims.y) * chassisMass / 12.f); // структура шасси PxVehicleChassisData chassisData; chassisData.mMass = chassisMass; // Масса транспортного средства жесткой актер тела chassisData.mMOI = chassisMOI; // Момент инерции автомобиля жесткая актер тела. chassisData.mCMOffset = chassisCMOffset; // Центр масс смещение автомобиля жесткая актер тела. // Немного настройки здесь.Автомобиль будет иметь более отзывчивым поворот, если мы сведем // у-компоненты шасси момента инерции. chassisMOI.y *= 0.8f; const PxF32 massRear = 0.5f * chassisMass * ( chassisDims.z - 3 * chassisCMOffset.z ) / chassisDims.z; const PxF32 massFront = massRear; //Extract the wheel radius and width from the wheel convex meshes PxF32 wheelWidths[ nWheels ] = {0.f}; PxF32 wheelRadii[ nWheels ] = {0.f}; for( PxU32 i = 0; i < nWheels; ++i ) { wheelWidths[ i ] = 0.5f; wheelRadii [ i ] = 0.32f; } // Теперь вычислим колеса массы и инерции компонентов вокруг оси оси PxF32 wheelMOIs[ nWheels ]; for( PxU32 i = 0; i < nWheels; ++i ) { wheelMOIs[ i ] = 0.5f * wheelMass * wheelRadii[ i ] * wheelRadii[ i ]; } // Давайте создадим структуру данных колеса теперь с радиусом, массы и МВД PxVehicleWheelData wheels[ nWheels ]; for(PxU32 i = 0; i < nWheels; ++i ) { wheels[ i ].mRadius = wheelRadii[ i ]; // Радиус блок, который включает в себя колеса металл плюс резиновые шины wheels[ i ].mMass = wheelMass; // Масса колеса плюс шины wheels[ i ].mMOI = wheelMOIs[ i ]; // Момент инерции колеса wheels[ i ].mWidth = wheelWidths[ i ]; // Максимальная ширина блок, который включает в себя колеса плюс шин //wheels[ i ].mMaxHandBrakeTorque = 0.f; // Отключение стояночного тормоза от передних колес и позволяют для задних колес //wheels[ i ].mMaxSteer = 0.f; // Включить рулевого управления для передних колес и отключить для передних колес //wheels[ i ].mDampingRate = 1.f; // Скорость затухания описывает скорость, с которой свободно вращающееся колесо теряет скорость вращения } //Let's set up the tire data structures now. //Put slicks on the front tires and wets on the rear tires. PxVehicleTireData tires[ nWheels ]; for(PxU32 i = 0; i < nWheels; ++i ) { tires[ i ].mType = 1; // тип сцепления шин с поверхностью } // Структура данных подвески PxVehicleSuspensionData susps[ nWheels ]; for( PxU32 i = 0; i < nWheels; i++ ) { susps[ i ].mMaxCompression = 0.03f; // Максимальное сжатие пружинной подвески susps[ i ].mMaxDroop = 0.03f; // Максимальное удлинение пружинной подвески susps[ i ].mSpringStrength = 20000.f; // пружинная сила подвески блока susps[ i ].mSpringDamperRate = 500.f; susps[ i ].mSprungMass = chassisMass / nWheels; // Масса транспортного средства, которая поддерживается пружинная подвеска, указанных в кг. } PxVec3 suspTravelDirections[ nWheels ]; PxVec3 wheelCentreCMOffsets[ nWheels ]; PxVec3 suspForceAppCMOffsets[ nWheels ]; PxVec3 tireForceAppCMOffsets[ nWheels ]; for( PxU32 i = 0 ; i < nWheels; ++i ) { wheelCentreCMOffsets [ i ] = wheelCentreOffsets[ i ] - chassisCMOffset; suspForceAppCMOffsets[ i ] = PxVec3( wheelCentreCMOffsets[ i ].x, -0.3f, wheelCentreCMOffsets[ i ].z ); tireForceAppCMOffsets[ i ] = PxVec3( wheelCentreCMOffsets[ i ].x, -0.3f, wheelCentreCMOffsets[ i ].z ); suspTravelDirections [ i ] = PxVec3( 0, -1, 0 ); // направление подвески } // Теперь добавьте колеса, шины и подвеска данных for( PxU32 i = 0; i < nWheels; ++i ) { wheelsData.setWheelData( i, wheels[ i ] ); // установить данные колеса wheelsData.setTireData( i, tires[ i ] ); // Установите шину данных колеса wheelsData.setSuspensionData( i, susps[ i ] ); // Установите подвеску данные колеса wheelsData.setSuspTravelDirection( i, suspTravelDirections[ i ] ); // Установить направление движения подвески колес wheelsData.setWheelCentreOffset( i, wheelCentreCMOffsets[ i ] ); // Установить смещение от центра жесткой тело массой в центре колеса wheelsData.setSuspForceAppPointOffset( i, suspForceAppCMOffsets[ i ] ); // Установить приложение точкой подвески силу подвески колес wheelsData.setTireForceAppPointOffset( i, tireForceAppCMOffsets[ i ] ); // Установить приложение точку шин силу шинах колес } //Diff PxVehicleDifferential4WData diff; diff.mType = PxVehicleDifferential4WData::eDIFF_TYPE_LS_4WD; driveData.setDiffData( diff ); //Engine PxVehicleEngineData engine; engine.mPeakTorque = 300.f; // максимальная скорость вращения двигателя engine.mMaxOmega = 400.f; // Максимальный крутящий момент доступен обратиться к двигателю engine.mDampingRateFullThrottle = 0.15f; // скорость затухания двигатель при полностью открытой дроссельной заслонке engine.mDampingRateZeroThrottleClutchEngaged = 8.f; // скорость затухания двигатель при нулевой газ при включении сцепления engine.mDampingRateZeroThrottleClutchDisengaged = 0.35f; // Краткие скорость затухания двигатель при нулевой газ при выключенном сцеплении (на нейтральной передаче) driveData.setEngineData( engine ); //Gears PxVehicleGearsData gears; gears.mSwitchTime = 0.5f; driveData.setGearsData( gears ); // Прочность сцепления PxVehicleClutchData clutch; clutch.mStrength = PxVehicleGearsData::eMAX_NUM_GEAR_RATIOS; driveData.setClutchData( clutch ); //Ackermann steer accuracy PxVehicleAckermannGeometryData ackermann; ackermann.mAccuracy = 0.1f; ackermann.mAxleSeparation = wheelCentreOffsets[ 0 ].z - wheelCentreOffsets[ nWheels - 1 ].z; // Расстояние между центром передней оси и центром задней оси ackermann.mFrontWidth = wheelCentreOffsets[ 0 ].x - wheelCentreOffsets[ 1 ].x; // Расстояние между центральной точке два передних колеса ackermann.mRearWidth = wheelCentreOffsets[ nWheels - 2 ].x - wheelCentreOffsets[ nWheels - 1 ].x; // Расстояние между центральной точке два задних колеса driveData.setAckermannGeometryData(ackermann); PxTriangleMesh * pTriangleMesh = 0; D3DXVECTOR3 vPosition; if( GameObject * pRoller = GetDetail( WHEEL_LEFT_1ST ) ) { if( pRoller->CreateTriangleMesh( pPhysX ) ) { pRoller->Update( 0.f ); pTriangleMesh = pRoller->GetTriangleMesh(); Position = pRoller->GetPosition(); } } // Нам нужно добавить колеса столкновения форм, их местный позы, материал для колес, и моделирование фильтра для колес PxTriangleMeshGeometry WheelGeom( pTriangleMesh ); PxGeometry* wheelGeometries[ nWheels ] = {0}; PxTransform wheelLocalPoses[ nWheels ]; for( PxU32 i = 0; i < nWheels; ++i ) { wheelGeometries[ i ] = &WheelGeom; wheelLocalPoses[ i ] = PxTransform::createIdentity(); } PxMaterial* pMaterial = pPhysX->GetPhysics()->createMaterial( 0.5f, 0.5f, 0.1f ); //коэффициенты трения скольжения и покоя(Dynamic friction,Static friction), коэффициент упругости const PxMaterial& wheelMaterial = *pMaterial; PxFilterData wheelCollFilterData; wheelCollFilterData.word0 = COLLISION_FLAG_WHEEL; wheelCollFilterData.word1 = COLLISION_FLAG_WHEEL_AGAINST; // Нам нужно добавить шасси столкновения форм, их местный позы, материала для шасси и моделирования фильтр для шасси. //PxBoxGeometry chassisConvexGeom( 1.5f, 0.3f, 4.f ); PxBoxGeometry chassisConvexGeom( chassisDims.x/2, chassisDims.y/2, chassisDims.z/2 ); const PxGeometry* chassisGeoms = &chassisConvexGeom; const PxTransform chassisLocalPoses = PxTransform::createIdentity(); const PxMaterial& chassisMaterial = *pMaterial; PxFilterData chassisCollFilterData; chassisCollFilterData.word0 = COLLISION_FLAG_CHASSIS; chassisCollFilterData.word1 = COLLISION_FLAG_CHASSIS_AGAINST; // Создание фильтра запроса данных для автомобилей, чтобы машины не пытайтесь ездить на себя. PxFilterData vehQryFilterData; SampleVehicleSetupVehicleShapeQueryFilterData( &vehQryFilterData ); PxRigidDynamic* vehActor = pPhysX->GetPhysics()->createRigidDynamic( PxTransform::createIdentity() ); //Add all the wheel shapes to the actor. for( PxU32 i = 0; i < nWheels; ++i ) { PxShape* wheelShape=vehActor->createShape( *wheelGeometries[ i ], wheelMaterial ); wheelShape->setQueryFilterData( vehQryFilterData ); wheelShape->setSimulationFilterData( wheelCollFilterData ); wheelShape->setLocalPose( wheelLocalPoses[ i ] ); wheelShape->setFlag( PxShapeFlag::eSIMULATION_SHAPE, true ); } //Add the chassis shapes to the actor PxShape* chassisShape = vehActor->createShape( *chassisGeoms, chassisMaterial ); chassisShape->setQueryFilterData( vehQryFilterData ); chassisShape->setSimulationFilterData( chassisCollFilterData ); chassisShape->setLocalPose( PxTransform( physx::PxVec3( 0, 0, 0 ) ) ); vehActor->setMass( chassisData.mMass ); vehActor->setMassSpaceInertiaTensor( chassisData.mMOI ); vehActor->setCMassLocalPose( PxTransform( chassisData.mCMOffset, PxQuat::createIdentity() ) ); vehActor->setGlobalPose( PxTransform( physx::PxVec3( 0, 8, 0 ), PxQuat::createIdentity() ) ); PxVehicleDriveTank* pTank = PxVehicleDriveTank::allocate( nWheels ); pTank->setup( pPhysX->GetPhysics(), vehActor, *wheelsSimData, driveData, nWheels ); pPhysX->AddActorScene( vehActor ); m_pActor = vehActor; pPhysX->AddTank( pTank ); //Free the sim data because we don't need that any more. wheelsSimData->free(); //pTank->setDriveModel( PxVehicleDriveTank::eDRIVE_MODEL_SPECIAL ); pTank->setToRestState(); pTank->mDriveDynData.setUseAutoGears( true ); return true; } } return false; }
void USkeletalMeshComponent::UpdateKinematicBonesToAnim(const TArray<FTransform>& InSpaceBases, ETeleportType Teleport, bool bNeedsSkinning) { 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 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); } } // 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 (bTeleport || (BodyInst->IsValidBodyInstance() && !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.ContainsNaN()) { 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()); continue; } // If kinematic and not teleporting, set kinematic target PxRigidDynamic* PRigidDynamic = BodyInst->GetPxRigidDynamic_AssumesLocked(); if (!IsRigidBodyNonKinematic_AssumesLocked(PRigidDynamic) && !bTeleport) { PhysScene->SetKinematicTarget_AssumesLocked(BodyInst, BoneTransform, true); } // Otherwise, set global pose else { const PxTransform PNewPose = U2PTransform(BoneTransform); ensure(PNewPose.isValid()); PRigidDynamic->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()) { UE_LOG(LogPhysics, Warning, 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 doRaycastCCD(PxShape* shape, PxTransform& newPose, PxVec3& newShapeCenter, const PxVec3& ccdWitness, const PxVec3& ccdWitnessOffset) { PxRigidDynamic* dyna = canDoCCD(shape); if(!dyna) return true; bool updateCCDWitness = true; const PxVec3 offset = newPose.p - newShapeCenter; //printf("CCD0: %f | %f | %f\n", newShapeCenter.x, newShapeCenter.y, newShapeCenter.z); const PxVec3& origin = ccdWitness; // const PxVec3& dest = newPose.p; const PxVec3& dest = newShapeCenter; PxVec3 dir = dest - origin; const PxReal length = dir.magnitude(); if(length!=0.0f) { dir /= length; // Compute internal radius // PxVec3 localCenter; const PxReal internalRadius = computeInternalRadius(shape, dir, /*localCenter,*/ ccdWitnessOffset); // Compute distance to impact PxRaycastHit hit; // if(internalRadius!=0.0f && CCDRaycast(shape->getActor().getActiveScene(), origin + localCenter, dir, length, hit)) if(internalRadius!=0.0f && CCDRaycast(shape->getActor().getScene(), origin, dir, length, hit)) { #ifdef RAYCAST_CCD_PRINT_DEBUG static int count=0; printf("CCD hit %d\n", count++); #endif updateCCDWitness = false; const PxReal radiusLimit = internalRadius * 0.75f; if(hit.distance>radiusLimit) { // newPose.p = origin + dir * (hit.distance - radiusLimit); newShapeCenter = origin + dir * (hit.distance - radiusLimit); #ifdef RAYCAST_CCD_PRINT_DEBUG printf(" Path0: %f | %f\n", hit.distance, radiusLimit); #endif } else { // newPose.p = origin; newShapeCenter = origin; // newShapeCenter = origin + hit.normal * (radiusLimit - hit.distance); #ifdef RAYCAST_CCD_PRINT_DEBUG printf(" Path1: %f\n", hit.distance); #endif } { newPose.p = offset + newShapeCenter; //newPose.p.y += 10.0f; //printf("%f | %f | %f\n", newPose.p.x, newPose.p.y, newPose.p.z); // dyna->setGlobalPose(newPose); // newPose = actorGlobalPose * shapeLocalPose // newPose * inverse(shapeLocalPose) = actorGlobalPose const PxTransform shapeLocalPose = shape->getLocalPose(); const PxTransform inverseShapeLocalPose = shapeLocalPose.getInverse(); PxTransform newGlobalPose = newPose * inverseShapeLocalPose; dyna->setGlobalPose(newGlobalPose); //dyna->setGlobalPose(newPose); //printf("%f | %f | %f\n", newGlobalPose.p.x, newGlobalPose.p.y, newGlobalPose.p.z); //printf("%f | %f | %f\n", shapeLocalPose.p.x, shapeLocalPose.p.y, shapeLocalPose.p.z); /*PX_INLINE PxTransform PxShapeExt::getGlobalPose(const PxShape& shape) { PxRigidActor& ra = shape.getActor(); return ra.getGlobalPose() * shape.getLocalPose(); }*/ const PxVec3 testShapeCenter = getShapeCenter(shape, ccdWitnessOffset); float d = (testShapeCenter - newShapeCenter).magnitude(); //printf("%f\n", d); //printf("CCD1: %f | %f | %f\n", testShapeCenter.x, testShapeCenter.y, testShapeCenter.z); //dyna->clearForce(PxForceMode::eFORCE); //dyna->clearForce(PxForceMode::eIMPULSE); //dyna->setLinearVelocity(PxVec3(0)); // PT: this helps the CCT but stops small objects dead, which doesn't look great } } } return updateCCDWitness; }