void UPoseableMeshComponent::SetBoneTransformByName(FName BoneName, const FTransform& InTransform, EBoneSpaces::Type BoneSpace) { if( !SkeletalMesh || !RequiredBones.IsValid() ) { return; } int32 BoneIndex = GetBoneIndex(BoneName); if(BoneIndex >=0 && BoneIndex < LocalAtoms.Num()) { LocalAtoms[BoneIndex] = InTransform; // If we haven't requested local space we need to transform the position passed in //if(BoneSpace != EBoneSpaces::LocalSpace) { if(BoneSpace == EBoneSpaces::WorldSpace) { LocalAtoms[BoneIndex].SetToRelativeTransform(GetComponentToWorld()); } int32 ParentIndex = RequiredBones.GetParentBoneIndex(BoneIndex); if(ParentIndex >=0) { FA2CSPose CSPose; CSPose.AllocateLocalPoses(RequiredBones, LocalAtoms); LocalAtoms[BoneIndex].SetToRelativeTransform(CSPose.GetComponentSpaceTransform(ParentIndex)); } // Need to send new state to render thread MarkRenderDynamicDataDirty(); } } }
void MorphByBone::fnRemoveBone(INode *node) { int boneIndex = GetBoneIndex(node); this->DeleteBone(boneIndex); UpdateLocalUI(); BuildTreeList(); }
FTransform UPoseableMeshComponent::GetBoneTransformByName(FName BoneName, EBoneSpaces::Type BoneSpace) { if( !SkeletalMesh || !RequiredBones.IsValid() ) { return FTransform(); } int32 BoneIndex = GetBoneIndex(BoneName); if( BoneIndex == INDEX_NONE) { FString Message = FString::Printf(TEXT("Invalid Bone Name '%s'"), *BoneName.ToString()); FFrame::KismetExecutionMessage(*Message, ELogVerbosity::Warning); return FTransform(); } /*if(BoneSpace == EBoneSpaces::LocalSpace) { return LocalAtoms[i]; }*/ FA2CSPose CSPose; CSPose.AllocateLocalPoses(RequiredBones, LocalAtoms); if(BoneSpace == EBoneSpaces::ComponentSpace) { return CSPose.GetComponentSpaceTransform(BoneIndex); } else { return CSPose.GetComponentSpaceTransform(BoneIndex) * ComponentToWorld; } }
void mCSkin::LimitNumInfluencingBonesPerVert( MIUInt const a_uMax ) { mTArray< MIUInt > arrVertexIndices( m_arrVertexIndices.GetCount() ); mTArray< MIUInt > arrBoneIndices( m_arrBoneIndices.GetCount() ); mTArray< MIFloat > arrWeights( m_arrWeights.GetCount() ); mTArray< MIUInt > arrVertWeightIndices( 0, 100 ); MIUInt * pVertWeightIndices = arrVertWeightIndices.AccessBuffer(); for ( MIUInt u = 0, ue = GetNumVerts(); u != ue; ++u ) { MIUInt uWeightCount = GetNumInfluencingBones( u ); MIFloat fWeightSum = 0.0f; s_pWeights = &m_arrWeights[ m_arrFirstWeightIndexPerVertex[ u ] ]; for ( MIUInt v = uWeightCount; v--; pVertWeightIndices[ v ] = v ); qsort( pVertWeightIndices, uWeightCount, sizeof( *pVertWeightIndices ), &CompareVretWeightIndices ); uWeightCount = g_min( uWeightCount, a_uMax ); for ( MIUInt v = 0; v != uWeightCount; ++v ) { arrVertexIndices.Add( u ); arrBoneIndices.Add( GetBoneIndex( u, pVertWeightIndices[ v ] ) ); arrWeights.Add( s_pWeights[ pVertWeightIndices[ v ] ] ); fWeightSum += s_pWeights[ pVertWeightIndices[ v ] ]; } for ( MIFloat * pWeights = &arrWeights.Back(), * pEnd = pWeights - uWeightCount; pWeights != pEnd; *pWeights-- /= fWeightSum ); } arrVertexIndices.UnReserve(); arrBoneIndices.UnReserve(); arrWeights.UnReserve(); mCSkin skinResult; skinResult.InitSwapping( GetNumVerts(), m_arrBoneIDs, arrVertexIndices, arrBoneIndices, arrWeights ); Swap( skinResult ); }
void UDestructibleComponent::WakeRigidBody(FName BoneName /* = NAME_None */) { #if WITH_APEX ExecuteOnPhysicsReadWrite([&] { const int32 ChunkIdx = BoneIdxToChunkIdx(GetBoneIndex(BoneName)); ApexDestructibleActor->setChunkPhysXActorAwakeState(ChunkIdx, true); }); #endif }
void MorphByBone::fnSelectBone(INode *node,const TCHAR* morphName) { int boneIndex = GetBoneIndex(node); int morphIndex = GetMorphIndex(node,morphName); this->currentBone = boneIndex; this->currentMorph = morphIndex; UpdateLocalUI(); BuildTreeList(); NotifyDependents(FOREVER, PART_ALL, REFMSG_CHANGE); GetCOREInterface()->RedrawViews(GetCOREInterface()->GetTime()); }
void UDestructibleComponent::AddForce( FVector Force, FName BoneName /*= NAME_None*/, bool bAccelChange /* = false */ ) { #if WITH_APEX ExecuteOnPhysicsReadWrite([&] { const int32 ChunkIdx = BoneIdxToChunkIdx(GetBoneIndex(BoneName)); if (PxRigidDynamic* Actor = ApexDestructibleActor->getChunkPhysXActor(ChunkIdx)) { Actor->addForce(U2PVector(Force), bAccelChange ? PxForceMode::eACCELERATION : PxForceMode::eFORCE); } }); #endif }
void UDestructibleComponent::AddForceAtLocation( FVector Force, FVector Location, FName BoneName /*= NAME_None*/ ) { #if WITH_APEX ExecuteOnPhysicsReadWrite([&] { int32 ChunkIdx = BoneIdxToChunkIdx(GetBoneIndex(BoneName)); if (PxRigidDynamic* Actor = ApexDestructibleActor->getChunkPhysXActor(ChunkIdx)) { PxRigidBodyExt::addForceAtPos(*Actor, U2PVector(Force), U2PVector(Location), PxForceMode::eFORCE); } }); #endif }
void UDestructibleComponent::AddForce( FVector Force, FName BoneName /*= NAME_None*/, bool bAccelChange /* = false */ ) { #if WITH_APEX int32 ChunkIdx = NxModuleDestructibleConst::INVALID_CHUNK_INDEX; if (BoneName != NAME_None) { ChunkIdx = BoneIdxToChunkIdx(GetBoneIndex(BoneName)); } PxRigidDynamic* Actor = ApexDestructibleActor->getChunkPhysXActor(ChunkIdx); Actor->addForce(U2PVector(Force), bAccelChange ? PxForceMode::eACCELERATION : PxForceMode::eFORCE); #endif }
void UDestructibleComponent::AddImpulse( FVector Impulse, FName BoneName /*= NAME_None*/, bool bVelChange /*= false*/ ) { #if WITH_APEX ExecuteOnPhysicsReadWrite([&] { const int32 ChunkIdx = BoneIdxToChunkIdx(GetBoneIndex(BoneName)); if(PxRigidDynamic* Actor = ApexDestructibleActor->getChunkPhysXActor(ChunkIdx)) { Actor->addForce(U2PVector(Impulse), bVelChange ? PxForceMode::eVELOCITY_CHANGE : PxForceMode::eIMPULSE); } }); #endif }
FBodyInstance* UDestructibleComponent::GetBodyInstance( FName BoneName /*= NAME_None*/, bool) const { #if WITH_APEX if (ApexDestructibleActor != NULL) { int32 BoneIdx = GetBoneIndex(BoneName); PxRigidDynamic* PActor = ApexDestructibleActor->getChunkPhysXActor(BoneIdxToChunkIdx(BoneIdx)); const_cast<UDestructibleComponent*>(this)->SetupFakeBodyInstance(PActor, BoneIdx); } #endif // WITH_APEX return (FBodyInstance*)&BodyInstance; }
void UDestructibleComponent::AddImpulse( FVector Impulse, FName BoneName /*= NAME_None*/, bool bVelChange /*= false*/ ) { #if WITH_APEX int32 ChunkIdx = BoneIdxToChunkIdx(GetBoneIndex(BoneName)); PxRigidDynamic* PActor = ApexDestructibleActor->getChunkPhysXActor(ChunkIdx); if (PActor != NULL) { SCOPED_SCENE_WRITE_LOCK(PActor->getScene()); PActor->addForce(U2PVector(Impulse), bVelChange ? PxForceMode::eVELOCITY_CHANGE : PxForceMode::eIMPULSE); } #endif }
FTransform UDestructibleComponent::GetSocketTransform(FName InSocketName, ERelativeTransformSpace TransformSpace) const { FTransform ST = Super::GetSocketTransform(InSocketName, TransformSpace); int32 BoneIdx = GetBoneIndex(InSocketName); // As bones in a destructible might be scaled to 0 when hidden, we force a scale of 1 if we want the socket transform if (BoneIdx > 0 && IsBoneHidden(BoneIdx)) { ST.SetScale3D(FVector(1.0f, 1.0f, 1.0f)); } return ST; }
void UDestructibleComponent::AddForceAtLocation( FVector Force, FVector Location, FName BoneName /*= NAME_None*/ ) { #if WITH_APEX if (ApexDestructibleActor) { int32 ChunkIdx = NxModuleDestructibleConst::INVALID_CHUNK_INDEX; if (BoneName != NAME_None) { ChunkIdx = BoneIdxToChunkIdx(GetBoneIndex(BoneName)); } PxRigidDynamic* Actor = ApexDestructibleActor->getChunkPhysXActor(ChunkIdx); Actor->addForce(U2PVector(Force), PxForceMode::eFORCE); } #endif }
void UPoseableMeshComponent::ResetBoneTransformByName(FName BoneName) { if( !SkeletalMesh ) { return; } const int32 BoneIndex = GetBoneIndex(BoneName); if( BoneIndex != INDEX_NONE ) { LocalAtoms[BoneIndex] = SkeletalMesh->RefSkeleton.GetRefBonePose()[BoneIndex]; } else { FString Message = FString::Printf(TEXT("Invalid Bone Name '%s'"), *BoneName.ToString()); FFrame::KismetExecutionMessage(*Message, ELogVerbosity::Warning); } }
void UDestructibleComponent::AddForce( FVector Force, FName BoneName /*= NAME_None*/ ) { #if WITH_APEX int32 ChunkIdx = NxModuleDestructibleConst::INVALID_CHUNK_INDEX; if (BoneName != NAME_None) { ChunkIdx = BoneIdxToChunkIdx(GetBoneIndex(BoneName)); } //ApexDestructibleActor->applyDamage(1.0f, Impulse.Size(), U2PVector(Position), U2PVector(Impulse.SafeNormal()), ChunkIdx); for (int32 i=0; i < ChunkInfos.Num(); ++i) { if (ChunkInfos[i].ChunkIndex == ChunkIdx && ChunkInfos[i].Actor) { ChunkInfos[i].Actor->addForce(U2PVector(Force), PxForceMode::eFORCE); } } #endif }
// --[ Method ]--------------------------------------------------------------- // // - Class : CStravaganzaMaxTools // // - prototype : int BuildPhysiqueData(INode* pMaxNode, // CObject* pObject, // std::vector<std::string> &vecBoneNames, // std::vector<CBlendedVertex> &vecBlendedVertices) // // - Purpose : Builds the bone data for a given node. Returns the number // of bones processed (0 = failure). // // ----------------------------------------------------------------------------- int CStravaganzaMaxTools::BuildPhysiqueData(INode* pMaxNode, CObject* pObject, std::vector<std::string> &vecBoneNames, std::vector<CBlendedVertex> &vecBlendedVertices) { int nCount = 0; int nBoneCount = 0; Modifier *pPhyModifier = NULL; // Physique modifier IPhysiqueExport *pPhyExport = NULL; // Physique export interface IPhyContextExport *pPhyObjExport = NULL; // Physique object export interface vecBoneNames.clear(); vecBlendedVertices.clear(); // Build bone list std::vector<INode*> vecMaxBones; if(!AddNodeBones(vecMaxBones, pMaxNode)) { LOG.Write("\nWARNING - Error building node %s bone list", pMaxNode->GetName()); return 0; } // Build bones name list for(nBoneCount = 0; nBoneCount < vecMaxBones.size(); nBoneCount++) { vecBoneNames.push_back(vecMaxBones[nBoneCount]->GetName()); } // Get Physique modifier if(pPhyModifier = GetPhysiqueModifier(pMaxNode)) { pPhyExport = (IPhysiqueExport *)pPhyModifier->GetInterface(I_PHYINTERFACE); if(pPhyExport == NULL) { LOG.Write("\nWARNING - Couldn't get Physique export interface.\nFailed with node %s.", pMaxNode->GetName()); return 0; } } // Get physique object export interface pPhyObjExport = pPhyExport->GetContextInterface(pMaxNode); if(pPhyObjExport == NULL) { pPhyModifier->ReleaseInterface(I_PHYINTERFACE, pPhyExport); LOG.Write("\nWARNING - Unable to get physique context export.\nFailed with node %s.", pMaxNode->GetName()); return 0; } // Convert to rigid for time independent vertex assignment // Allow blending to export multi-link assignments pPhyObjExport->ConvertToRigid(true); pPhyObjExport->AllowBlending(true); // Build deformable vertex list bool bOK = true; int nBlendedCount = 0, nBlendedRigidCount = 0, nFloatingCount = 0; for(nCount = 0; nCount < pPhyObjExport->GetNumberVertices(); nCount++) { IPhyVertexExport *pPhyVertExport; IPhyBlendedRigidVertex *pPhyBRVertexExport; IPhyRigidVertex *pPhyRigidVertexExport; IPhyFloatingVertex *pPhyFloatingVertex; pPhyVertExport = pPhyObjExport->GetVertexInterface(nCount); CBlendedVertex blendedVertex; float fTotalWeight = 0.0f; bool bFloatingBones = false; // Floating Vertex pPhyFloatingVertex = pPhyObjExport->GetFloatingVertexInterface(nCount); if(pPhyFloatingVertex) { bFloatingBones = true; CVector3 v3OffsetVector; float fWeight; // More than one bone int nNumVtxBones = pPhyFloatingVertex->GetNumberNodes(); // LOG.Write("\n%u - Floating, with %u bones", nCount, nNumVtxBones); for(nBoneCount = 0; nBoneCount < nNumVtxBones; nBoneCount++) { int nIndex = GetBoneIndex(vecMaxBones, pPhyFloatingVertex->GetNode(nBoneCount)); if(nIndex == -1) { LOG.Write("\nWARNING - Unable to get bone index (%s)", pPhyFloatingVertex->GetNode(nBoneCount)->GetName()); bOK = false; break; } float fTotal; v3OffsetVector = Point3ToVector3(pPhyFloatingVertex->GetOffsetVector(nBoneCount)); fWeight = pPhyFloatingVertex->GetWeight(nBoneCount, fTotal); fTotalWeight += fWeight;//fTotal; //fWeight = fTotal; // LOG.Write("\n Weight = %f (%s)", fWeight, pPhyFloatingVertex->GetNode(nBoneCount)->GetName()); blendedVertex.AddLink(v3OffsetVector, nIndex, fWeight); } // LOG.Write("\n Total = %f", fTotalWeight); if(!ARE_EQUAL(fTotalWeight, 1.0f)) { LOG.Write("\n WARNING - Vertex %u has total weights %f", nCount, fTotalWeight); } nFloatingCount++; pPhyObjExport->ReleaseVertexInterface(pPhyFloatingVertex); } if(pPhyVertExport) { if(pPhyVertExport->GetVertexType() & BLENDED_TYPE) { CVector3 v3OffsetVector; float fWeight; // More than one bone pPhyBRVertexExport = (IPhyBlendedRigidVertex *)pPhyVertExport; int nNumVtxBones = pPhyBRVertexExport->GetNumberNodes(); // LOG.Write("\n%u - Blended, with %u bones", nCount, nNumVtxBones); for(nBoneCount = 0; nBoneCount < nNumVtxBones; nBoneCount++) { int nIndex = GetBoneIndex(vecMaxBones, pPhyBRVertexExport->GetNode(nBoneCount)); if(nIndex == -1) { LOG.Write("\nWARNING - Unable to get bone index (%s)", pPhyBRVertexExport->GetNode(nBoneCount)->GetName()); bOK = false; break; } v3OffsetVector = Point3ToVector3(pPhyBRVertexExport->GetOffsetVector(nBoneCount)); fWeight = pPhyBRVertexExport->GetWeight(nBoneCount); fTotalWeight += fWeight; // LOG.Write("\n Weight = %f (%s)", fWeight, pPhyBRVertexExport->GetNode(nBoneCount)->GetName()); blendedVertex.AddLink(v3OffsetVector, nIndex, fWeight); } // LOG.Write("\n Total = %f", fTotalWeight); if(!ARE_EQUAL(fTotalWeight, 1.0f)) { LOG.Write("\n WARNING - Vertex %u has total weights %f", nCount, fTotalWeight); } nBlendedCount++; } else { CVector3 v3OffsetVector; float fWeight; // Single bone pPhyRigidVertexExport = (IPhyRigidVertex *)pPhyVertExport; int nIndex = GetBoneIndex(vecMaxBones, pPhyRigidVertexExport->GetNode()); if(nIndex == -1) { LOG.Write("\nWARNING - Unable to get bone index (%s)", pPhyRigidVertexExport->GetNode()->GetName()); bOK = false; break; } v3OffsetVector = Point3ToVector3(pPhyRigidVertexExport->GetOffsetVector()); fWeight = 1.0f; fTotalWeight = 1.0f; // LOG.Write("\n%u - Rigid (%s)", nCount, pPhyRigidVertexExport->GetNode()->GetName()); blendedVertex.AddLink(v3OffsetVector, nIndex, fWeight); nBlendedRigidCount++; } pPhyObjExport->ReleaseVertexInterface(pPhyVertExport); } for(int i = 0; i < blendedVertex.GetNumLinks(); i++) { // Normalize blendedVertex.SetWeight(i, blendedVertex.GetWeight(i) / fTotalWeight); } vecBlendedVertices.push_back(blendedVertex); } pPhyExport->ReleaseContextInterface(pPhyObjExport); pPhyModifier->ReleaseInterface(I_PHYINTERFACE, pPhyExport); if(!bOK) { vecMaxBones.clear(); vecBoneNames.clear(); vecBlendedVertices.clear(); } else { LOG.Write("\nPhysique: %u bones, %u vertices (%u rigid, %u rigidblended, %u floating)", vecBoneNames.size(), vecBlendedVertices.size(), nBlendedRigidCount, nBlendedCount, nFloatingCount); } return vecMaxBones.size(); }
void UPhATEdSkeletalMeshComponent::RenderAssetTools(const FSceneView* View, class FPrimitiveDrawInterface* PDI, bool bHitTest) { check(SharedData); UPhysicsAsset* const PhysicsAsset = GetPhysicsAsset(); check(PhysicsAsset); bool bHitTestAndBodyMode = bHitTest && SharedData->EditingMode == FPhATSharedData::PEM_BodyEdit; bool bHitTestAndConstraintMode = bHitTest && SharedData->EditingMode == FPhATSharedData::PEM_ConstraintEdit; FPhATSharedData::EPhATRenderMode CollisionViewMode = SharedData->GetCurrentCollisionViewMode(); #if DEBUG_CLICK_VIEWPORT PDI->DrawLine(SharedData->LastClickOrigin, SharedData->LastClickOrigin + SharedData->LastClickDirection * 5000.0f, FLinearColor(1, 1, 0, 1), SDPG_Foreground); PDI->DrawPoint(SharedData->LastClickOrigin, FLinearColor(1, 0, 0), 5, SDPG_Foreground); #endif // Draw bodies for (int32 i = 0; i <PhysicsAsset->BodySetup.Num(); ++i) { int32 BoneIndex = GetBoneIndex(PhysicsAsset->BodySetup[i]->BoneName); // If we found a bone for it, draw the collision. // The logic is as follows; always render in the ViewMode requested when not in hit mode - but if we are in hit mode and the right editing mode, render as solid if (BoneIndex != INDEX_NONE) { FTransform BoneTM = GetBoneTransform(BoneIndex); float Scale = BoneTM.GetScale3D().GetAbsMax(); FVector VectorScale(Scale); BoneTM.RemoveScaling(); FKAggregateGeom* AggGeom = &PhysicsAsset->BodySetup[i]->AggGeom; for (int32 j = 0; j <AggGeom->SphereElems.Num(); ++j) { if (bHitTest) { PDI->SetHitProxy(new HPhATEdBoneProxy(i, KPT_Sphere, j)); } FTransform ElemTM = GetPrimitiveTransform(BoneTM, i, KPT_Sphere, j, Scale); //solids are drawn if it's the ViewMode and we're not doing a hit, or if it's hitAndBodyMode if( (CollisionViewMode == FPhATSharedData::PRM_Solid && !bHitTest) || bHitTestAndBodyMode) { UMaterialInterface* PrimMaterial = GetPrimitiveMaterial(i, KPT_Sphere, j, bHitTestAndBodyMode); AggGeom->SphereElems[j].DrawElemSolid(PDI, ElemTM, VectorScale, PrimMaterial->GetRenderProxy(0)); } //wires are never used during hit if(!bHitTest) { if (CollisionViewMode == FPhATSharedData::PRM_Solid || CollisionViewMode == FPhATSharedData::PRM_Wireframe) { AggGeom->SphereElems[j].DrawElemWire(PDI, ElemTM, VectorScale, GetPrimitiveColor(i, KPT_Sphere, j)); } } if (bHitTest) { PDI->SetHitProxy(NULL); } } for (int32 j = 0; j <AggGeom->BoxElems.Num(); ++j) { if (bHitTest) { PDI->SetHitProxy(new HPhATEdBoneProxy(i, KPT_Box, j)); } FTransform ElemTM = GetPrimitiveTransform(BoneTM, i, KPT_Box, j, Scale); if ( (CollisionViewMode == FPhATSharedData::PRM_Solid && !bHitTest) || bHitTestAndBodyMode) { UMaterialInterface* PrimMaterial = GetPrimitiveMaterial(i, KPT_Box, j, bHitTestAndBodyMode); AggGeom->BoxElems[j].DrawElemSolid(PDI, ElemTM, VectorScale, PrimMaterial->GetRenderProxy(0)); } if(!bHitTest) { if (CollisionViewMode == FPhATSharedData::PRM_Solid || CollisionViewMode == FPhATSharedData::PRM_Wireframe) { AggGeom->BoxElems[j].DrawElemWire(PDI, ElemTM, VectorScale, GetPrimitiveColor(i, KPT_Box, j)); } } if (bHitTest) { PDI->SetHitProxy(NULL); } } for (int32 j = 0; j <AggGeom->SphylElems.Num(); ++j) { if (bHitTest) { PDI->SetHitProxy(new HPhATEdBoneProxy(i, KPT_Sphyl, j)); } FTransform ElemTM = GetPrimitiveTransform(BoneTM, i, KPT_Sphyl, j, Scale); if ( (CollisionViewMode == FPhATSharedData::PRM_Solid && !bHitTest) || bHitTestAndBodyMode) { UMaterialInterface* PrimMaterial = GetPrimitiveMaterial(i, KPT_Sphyl, j, bHitTestAndBodyMode); AggGeom->SphylElems[j].DrawElemSolid(PDI, ElemTM, VectorScale, PrimMaterial->GetRenderProxy(0)); } if(!bHitTest) { if (CollisionViewMode == FPhATSharedData::PRM_Solid || CollisionViewMode == FPhATSharedData::PRM_Wireframe) { AggGeom->SphylElems[j].DrawElemWire(PDI, ElemTM, VectorScale, GetPrimitiveColor(i, KPT_Sphyl, j)); } } if (bHitTest) { PDI->SetHitProxy(NULL); } } for (int32 j = 0; j <AggGeom->ConvexElems.Num(); ++j) { if (bHitTest) { PDI->SetHitProxy(new HPhATEdBoneProxy(i, KPT_Convex, j)); } FTransform ElemTM = GetPrimitiveTransform(BoneTM, i, KPT_Convex, j, Scale); //convex doesn't have solid draw so render lines if we're in hitTestAndBodyMode if(!bHitTest || bHitTestAndBodyMode) { if (CollisionViewMode == FPhATSharedData::PRM_Solid || CollisionViewMode == FPhATSharedData::PRM_Wireframe) { AggGeom->ConvexElems[j].DrawElemWire(PDI, ElemTM, Scale, GetPrimitiveColor(i, KPT_Convex, j)); } } if (bHitTest) { PDI->SetHitProxy(NULL); } } if (!bHitTest && SharedData->bShowCOM && Bodies.IsValidIndex(i)) { Bodies[i]->DrawCOMPosition(PDI, COMRenderSize, SharedData->COMRenderColor); } } } // Draw Constraints FPhATSharedData::EPhATConstraintViewMode ConstraintViewMode = SharedData->GetCurrentConstraintViewMode(); if (ConstraintViewMode != FPhATSharedData::PCV_None) { for (int32 i = 0; i <PhysicsAsset->ConstraintSetup.Num(); ++i) { int32 BoneIndex1 = GetBoneIndex(PhysicsAsset->ConstraintSetup[i]->DefaultInstance.ConstraintBone1); int32 BoneIndex2 = GetBoneIndex(PhysicsAsset->ConstraintSetup[i]->DefaultInstance.ConstraintBone2); // if bone doesn't exist, do not draw it. It crashes in random points when we try to manipulate. if (BoneIndex1 != INDEX_NONE && BoneIndex2 != INDEX_NONE) { if (bHitTest) { PDI->SetHitProxy(new HPhATEdConstraintProxy(i)); } if(bHitTestAndConstraintMode || !bHitTest) { DrawConstraint(i, View, PDI, SharedData->EditorSimOptions->bShowConstraintsAsPoints); } if (bHitTest) { PDI->SetHitProxy(NULL); } } } } if (!bHitTest && SharedData->EditingMode == FPhATSharedData::PEM_BodyEdit && SharedData->bShowInfluences) { DrawCurrentInfluences(PDI); } // If desired, draw bone hierarchy. if (!bHitTest && SharedData->bShowHierarchy) { DrawHierarchy(PDI, false); } // If desired, draw animation skeleton. if (!bHitTest && SharedData->bShowAnimSkel) { DrawHierarchy(PDI, SharedData->bRunningSimulation); } }
bool GetBlendData(OutModel& model, aiMesh* mesh, PODVector<unsigned>& boneMappings, Vector<PODVector<unsigned char> >& blendIndices, Vector<PODVector<float> >& blendWeights, String& errorMessage, unsigned maxBones) { blendIndices.Resize(mesh->mNumVertices); blendWeights.Resize(mesh->mNumVertices); boneMappings.Clear(); // If model has more bones than can fit vertex shader parameters, write the per-geometry mappings if (model.bones_.Size() > maxBones) { if (mesh->mNumBones > maxBones) { errorMessage = "Geometry (submesh) has over " + String(maxBones) + " bone influences. Try splitting to more submeshes\n" "that each stay at " + String(maxBones) + " bones or below."; return false; } boneMappings.Resize(mesh->mNumBones); for (unsigned i = 0; i < mesh->mNumBones; ++i) { aiBone* bone = mesh->mBones[i]; String boneName = FromAIString(bone->mName); unsigned globalIndex = GetBoneIndex(model, boneName); if (globalIndex == M_MAX_UNSIGNED) { errorMessage = "Bone " + boneName + " not found"; return false; } boneMappings[i] = globalIndex; for (unsigned j = 0; j < bone->mNumWeights; ++j) { unsigned vertex = bone->mWeights[j].mVertexId; blendIndices[vertex].Push(i); blendWeights[vertex].Push(bone->mWeights[j].mWeight); } } } else { for (unsigned i = 0; i < mesh->mNumBones; ++i) { aiBone* bone = mesh->mBones[i]; String boneName = FromAIString(bone->mName); unsigned globalIndex = GetBoneIndex(model, boneName); if (globalIndex == M_MAX_UNSIGNED) { errorMessage = "Bone " + boneName + " not found"; return false; } for (unsigned j = 0; j < bone->mNumWeights; ++j) { unsigned vertex = bone->mWeights[j].mVertexId; blendIndices[vertex].Push(globalIndex); blendWeights[vertex].Push(bone->mWeights[j].mWeight); } } } // Normalize weights now if necessary, also remove too many influences for (unsigned i = 0; i < blendWeights.Size(); ++i) { if (blendWeights[i].Size() > 4) { PrintLine("Warning: more than 4 bone influences in vertex " + String(i)); while (blendWeights[i].Size() > 4) { unsigned lowestIndex = 0; float lowest = M_INFINITY; for (unsigned j = 0; j < blendWeights[i].Size(); ++j) { if (blendWeights[i][j] < lowest) { lowest = blendWeights[i][j]; lowestIndex = j; } } blendWeights[i].Erase(lowestIndex); blendIndices[i].Erase(lowestIndex); } } float sum = 0.0f; for (unsigned j = 0; j < blendWeights[i].Size(); ++j) sum += blendWeights[i][j]; if (sum != 1.0f && sum != 0.0f) { for (unsigned j = 0; j < blendWeights[i].Size(); ++j) blendWeights[i][j] /= sum; } } return true; }