void UDebugSkelMeshComponent::ToggleClothSectionsVisibility(bool bShowOnlyClothSections) { FSkeletalMeshResource* SkelMeshResource = GetSkeletalMeshResource(); if (SkelMeshResource) { PreEditChange(NULL); for (int32 LODIndex = 0; LODIndex < SkelMeshResource->LODModels.Num(); LODIndex++) { FStaticLODModel& LODModel = SkelMeshResource->LODModels[LODIndex]; for (int32 SecIdx = 0; SecIdx < LODModel.Sections.Num(); SecIdx++) { FSkelMeshSection& Section = LODModel.Sections[SecIdx]; // toggle visibility between cloth sections and non-cloth sections if (bShowOnlyClothSections) { // enables only cloth sections if (LODModel.Chunks[Section.ChunkIndex].HasApexClothData()) { Section.bDisabled = false; } else { Section.bDisabled = true; } } else { // disables cloth sections and also corresponding original sections if (LODModel.Chunks[Section.ChunkIndex].HasApexClothData()) { Section.bDisabled = true; LODModel.Sections[Section.CorrespondClothSectionIndex].bDisabled = true; } else { Section.bDisabled = false; } } } } PostEditChange(); } }
void UDebugSkelMeshComponent::RestoreClothSectionsVisibility() { // if this skeletal mesh doesn't have any clothing assets, just return if (!SkeletalMesh || SkeletalMesh->ClothingAssets.Num() == 0) { return; } FSkeletalMeshResource* SkelMeshResource = GetSkeletalMeshResource(); if (SkelMeshResource) { PreEditChange(NULL); for(int32 LODIndex = 0; LODIndex < SkelMeshResource->LODModels.Num(); LODIndex++) { FStaticLODModel& LODModel = SkelMeshResource->LODModels[LODIndex]; // enables all sections first for(int32 SecIdx = 0; SecIdx < LODModel.Sections.Num(); SecIdx++) { LODModel.Sections[SecIdx].bDisabled = false; } // disables corresponding original section to enable the cloth section instead for(int32 SecIdx = 0; SecIdx < LODModel.Sections.Num(); SecIdx++) { FSkelMeshSection& Section = LODModel.Sections[SecIdx]; if(LODModel.Chunks[Section.ChunkIndex].HasApexClothData()) { LODModel.Sections[Section.CorrespondClothSectionIndex].bDisabled = true; } } } PostEditChange(); } }
int32 UDebugSkelMeshComponent::FindCurrentSectionDisplayMode() { ESectionDisplayMode DisplayMode = ESectionDisplayMode::None; FSkeletalMeshResource* SkelMeshResource = GetSkeletalMeshResource(); // if this skeletal mesh doesn't have any clothing asset, returns "None" if (!SkelMeshResource || !SkeletalMesh || SkeletalMesh->ClothingAssets.Num() == 0) { return ESectionDisplayMode::None; } else { int32 LODIndex; int32 NumLODs = SkelMeshResource->LODModels.Num(); for (LODIndex = 0; LODIndex < NumLODs; LODIndex++) { // if find any LOD model which has cloth data, then break if (SkelMeshResource->LODModels[LODIndex].HasApexClothData()) { break; } } // couldn't find if (LODIndex == NumLODs) { return ESectionDisplayMode::None; } FStaticLODModel& LODModel = SkelMeshResource->LODModels[LODIndex]; // firstly, find cloth sections for (int32 SecIdx = 0; SecIdx < LODModel.Sections.Num(); SecIdx++) { FSkelMeshSection& Section = LODModel.Sections[SecIdx]; if (LODModel.Chunks[Section.ChunkIndex].HasApexClothData()) { // Normal state if the cloth section is visible and the corresponding section is disabled if (Section.bDisabled == false && LODModel.Sections[Section.CorrespondClothSectionIndex].bDisabled == true) { DisplayMode = ESectionDisplayMode::ShowOnlyClothSections; break; } } } // secondly, find non-cloth sections except cloth-corresponding sections bool bFoundNonClothSection = false; for (int32 SecIdx = 0; SecIdx < LODModel.Sections.Num(); SecIdx++) { FSkelMeshSection& Section = LODModel.Sections[SecIdx]; // not related to cloth sections if (!LODModel.Chunks[Section.ChunkIndex].HasApexClothData() && Section.CorrespondClothSectionIndex < 0) { bFoundNonClothSection = true; if (!Section.bDisabled) { if (DisplayMode == ESectionDisplayMode::ShowOnlyClothSections) { DisplayMode = ESectionDisplayMode::ShowAll; } else { DisplayMode = ESectionDisplayMode::HideOnlyClothSections; } } break; } } } return DisplayMode; }
void USkeletalMeshComponent::RecalcRequiredBones(int32 LODIndex) { if (!SkeletalMesh) { return; } FSkeletalMeshResource* SkelMeshResource = GetSkeletalMeshResource(); check(SkelMeshResource); // The list of bones we want is taken from the predicted LOD level. FStaticLODModel& LODModel = SkelMeshResource->LODModels[LODIndex]; RequiredBones = LODModel.RequiredBones; const UPhysicsAsset* const PhysicsAsset = GetPhysicsAsset(); // If we have a PhysicsAsset, we also need to make sure that all the bones used by it are always updated, as its used // by line checks etc. We might also want to kick in the physics, which means having valid bone transforms. if(PhysicsAsset) { TArray<FBoneIndexType> PhysAssetBones; for(int32 i=0; i<PhysicsAsset->BodySetup.Num(); i++ ) { int32 PhysBoneIndex = SkeletalMesh->RefSkeleton.FindBoneIndex( PhysicsAsset->BodySetup[i]->BoneName ); if(PhysBoneIndex != INDEX_NONE) { PhysAssetBones.Add(PhysBoneIndex); } } // Then sort array of required bones in hierarchy order PhysAssetBones.Sort(); // Make sure all of these are in RequiredBones. MergeInBoneIndexArrays(RequiredBones, PhysAssetBones); } // Make sure that bones with per-poly collision are also always updated. // TODO UE4 // Purge invisible bones and their children // this has to be done before mirror table check/phsysics body checks // mirror table/phys body ones has to be calculated if (ShouldUpdateBoneVisibility()) { check(BoneVisibilityStates.Num() == SpaceBases.Num()); int32 VisibleBoneWriteIndex = 0; for (int32 i = 0; i < RequiredBones.Num(); ++i) { FBoneIndexType CurBoneIndex = RequiredBones[i]; // Current bone visible? if (BoneVisibilityStates[CurBoneIndex] == BVS_Visible) { RequiredBones[VisibleBoneWriteIndex++] = CurBoneIndex; } } // Remove any trailing junk in the RequiredBones array const int32 NumBonesHidden = RequiredBones.Num() - VisibleBoneWriteIndex; if (NumBonesHidden > 0) { RequiredBones.RemoveAt(VisibleBoneWriteIndex, NumBonesHidden); } } // Add in any bones that may be required when mirroring. // JTODO: This is only required if there are mirroring nodes in the tree, but hard to know... if(SkeletalMesh->SkelMirrorTable.Num() > 0 && SkeletalMesh->SkelMirrorTable.Num() == LocalAtoms.Num()) { TArray<FBoneIndexType> MirroredDesiredBones; MirroredDesiredBones.AddUninitialized(RequiredBones.Num()); // Look up each bone in the mirroring table. for(int32 i=0; i<RequiredBones.Num(); i++) { MirroredDesiredBones[i] = SkeletalMesh->SkelMirrorTable[RequiredBones[i]].SourceIndex; } // Sort to ensure strictly increasing order. MirroredDesiredBones.Sort(); // Make sure all of these are in RequiredBones, and MergeInBoneIndexArrays(RequiredBones, MirroredDesiredBones); } // Ensure that we have a complete hierarchy down to those bones. FAnimationRuntime::EnsureParentsPresent(RequiredBones, SkeletalMesh); // make sure animation requiredBone to mark as dirty if (AnimScriptInstance) { AnimScriptInstance->RecalcRequiredBones(); } bRequiredBonesUpToDate = true; // Invalidate cached bones. CachedLocalAtoms.Empty(); CachedSpaceBases.Empty(); }