UMaterialInterface* FParticleBeam2EmitterInstance::GetCurrentMaterial() { UMaterialInterface* RenderMaterial = CurrentMaterial; if ((RenderMaterial == NULL) || (RenderMaterial->CheckMaterialUsage_Concurrent(MATUSAGE_BeamTrails) == false)) { RenderMaterial = UMaterial::GetDefaultMaterial(MD_Surface); } return RenderMaterial; }
void SLandscapeAssetThumbnail::OnMaterialCompilationFinished(UMaterialInterface* MaterialInterface) { UMaterialInterface* MaterialAsset = Cast<UMaterialInterface>(AssetThumbnail->GetAsset()); if (MaterialAsset) { if (MaterialAsset->IsDependent(MaterialInterface)) { // Refresh thumbnail AssetThumbnail->SetAsset(AssetThumbnail->GetAsset()); } } }
void SMaterialEditorViewport::OnSetPreviewMeshFromSelection() { bool bFoundPreviewMesh = false; FEditorDelegates::LoadSelectedAssetsIfNeeded.Broadcast(); UMaterialInterface* MaterialInterface = MaterialEditorPtr.Pin()->GetMaterialInterface(); // Look for a selected asset that can be converted to a mesh component for (FSelectionIterator SelectionIt(*GEditor->GetSelectedObjects()); SelectionIt && !bFoundPreviewMesh; ++SelectionIt) { UObject* TestAsset = *SelectionIt; if (TestAsset->IsAsset()) { if (TSubclassOf<UActorComponent> ComponentClass = FComponentAssetBrokerage::GetPrimaryComponentForAsset(TestAsset->GetClass())) { if (ComponentClass->IsChildOf(UMeshComponent::StaticClass())) { if (USkeletalMesh* SkeletalMesh = Cast<USkeletalMesh>(TestAsset)) { // Special case handling for skeletal meshes, sets the material to be usable with them if (MaterialInterface->GetMaterial()) { bool bNeedsRecompile = false; MaterialInterface->GetMaterial()->SetMaterialUsage(bNeedsRecompile, MATUSAGE_SkeletalMesh); } } SetPreviewAsset(TestAsset); MaterialInterface->PreviewMesh = TestAsset->GetPathName(); bFoundPreviewMesh = true; } } } } if (bFoundPreviewMesh) { FMaterialEditor::UpdateThumbnailInfoPreviewMesh(MaterialInterface); MaterialInterface->MarkPackageDirty(); RefreshViewport(); } else { FSuppressableWarningDialog::FSetupInfo Info(NSLOCTEXT("UnrealEd", "Warning_NoPreviewMeshFound_Message", "You need to select a mesh-based asset in the content browser to preview it."), NSLOCTEXT("UnrealEd", "Warning_NoPreviewMeshFound", "Warning: No Preview Mesh Found"), "Warning_NoPreviewMeshFound"); Info.ConfirmText = NSLOCTEXT("UnrealEd", "Warning_NoPreviewMeshFound_Confirm", "Continue"); FSuppressableWarningDialog NoPreviewMeshWarning( Info ); NoPreviewMeshWarning.ShowModal(); } }
bool UParticleModuleCollisionGPU::IsValidForLODLevel(UParticleLODLevel* LODLevel, FString& OutErrorString) { UMaterialInterface* Material = NULL; if (LODLevel && LODLevel->RequiredModule) { Material = LODLevel->RequiredModule->Material; } if (Material == NULL) { Material = UMaterial::GetDefaultMaterial(MD_Surface); } check(Material); EBlendMode BlendMode = BLEND_Opaque; const FMaterialResource* MaterialResource = Material->GetMaterialResource(GetWorld() ? GetWorld()->FeatureLevel : GMaxRHIFeatureLevel); if(MaterialResource) { BlendMode = MaterialResource->GetBlendMode(); } if (CollisionMode == EParticleCollisionMode::SceneDepth && (BlendMode == BLEND_Opaque || BlendMode == BLEND_Masked)) { OutErrorString = NSLOCTEXT("UnrealEd", "CollisionOnOpaqueEmitter", "Scene depth collision cannot be used on emitters with an opaque material.").ToString(); return false; } if (CollisionMode == EParticleCollisionMode::DistanceField) { static const auto CVar = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.GenerateMeshDistanceFields")); if (CVar->GetValueOnGameThread() == 0) { OutErrorString = NSLOCTEXT("UnrealEd", "CollisionWithoutDistanceField", "Distance Field collision requires the 'Generate Mesh Distance Fields' Renderer project setting to be enabled.").ToString(); return false; } } if (LODLevel->TypeDataModule && LODLevel->TypeDataModule->IsA(UParticleModuleTypeDataGpu::StaticClass())) { if(!IsDistributionAllowedOnGPU(ResilienceScaleOverLife.Distribution)) { OutErrorString = GetDistributionNotAllowedOnGPUText(StaticClass()->GetName(), "ResilienceScaleOverLife" ).ToString(); return false; } } return true; }
FLinearColor FMaterialEditorViewportClient::GetBackgroundColor() const { FLinearColor BackgroundColor = FLinearColor::Black; UMaterialInterface* MaterialInterface = MaterialEditorPtr.Pin()->GetMaterialInterface(); if (MaterialInterface) { const EBlendMode PreviewBlendMode = (EBlendMode)MaterialInterface->GetBlendMode(); if (PreviewBlendMode == BLEND_Modulate) { BackgroundColor = FLinearColor::White; } else if (PreviewBlendMode == BLEND_Translucent) { BackgroundColor = FColor(64, 64, 64); } } return BackgroundColor; }
bool ADebugCameraHUD::DisplayMaterials( float X, float& Y, float DY, UMeshComponent* MeshComp ) { bool bDisplayedMaterial = false; if ( MeshComp != NULL ) { FFontRenderInfo FontRenderInfo = Canvas->CreateFontRenderInfo(false, true); UFont* Font = GEngine->GetSmallFont(); for ( int32 MaterialIndex = 0; MaterialIndex < MeshComp->GetNumMaterials(); ++MaterialIndex ) { UMaterialInterface* Material = MeshComp->GetMaterial(MaterialIndex); if ( Material != NULL ) { Y += DY; Canvas->DrawText(Font, FString::Printf(TEXT("Material: '%s'"), *Material->GetFName().ToString()), X + DY, Y, 1.f, 1.f, FontRenderInfo ); bDisplayedMaterial = true; } } } return bDisplayedMaterial; }
bool UParticleModuleCollisionGPU::IsValidForLODLevel(UParticleLODLevel* LODLevel, FString& OutErrorString) { UMaterialInterface* Material = NULL; if (LODLevel && LODLevel->RequiredModule) { Material = LODLevel->RequiredModule->Material; } if (Material == NULL) { Material = UMaterial::GetDefaultMaterial(MD_Surface); } check(Material); EBlendMode BlendMode = BLEND_Opaque; const FMaterialResource* MaterialResource = Material->GetMaterialResource(GetWorld() ? GetWorld()->FeatureLevel : GMaxRHIFeatureLevel); if(MaterialResource) { BlendMode = MaterialResource->GetBlendMode(); } if (BlendMode == BLEND_Opaque || BlendMode == BLEND_Masked) { OutErrorString = NSLOCTEXT("UnrealEd", "CollisionOnOpaqueEmitter", "Scene depth collision cannot be used on emitters with an opaque material.").ToString(); return false; } if (LODLevel->TypeDataModule && LODLevel->TypeDataModule->IsA(UParticleModuleTypeDataGpu::StaticClass())) { if(!IsDistributionAllowedOnGPU(ResilienceScaleOverLife.Distribution)) { OutErrorString = GetDistributionNotAllowedOnGPUText(StaticClass()->GetName(), "ResilienceScaleOverLife" ).ToString(); return false; } } return true; }
void FTextRenderSceneProxy::GetDynamicMeshElements(const TArray<const FSceneView*>& Views, const FSceneViewFamily& ViewFamily, uint32 VisibilityMap, FMeshElementCollector& Collector) const { QUICK_SCOPE_CYCLE_COUNTER( STAT_TextRenderSceneProxy_GetDynamicMeshElements ); // Vertex factory will not been initialized when the text string is empty or font is invalid. if(VertexFactory.IsInitialized()) { for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++) { if (VisibilityMap & (1 << ViewIndex)) { const FSceneView* View = Views[ViewIndex]; // Draw the mesh. FMeshBatch& Mesh = Collector.AllocateMesh(); FMeshBatchElement& BatchElement = Mesh.Elements[0]; BatchElement.IndexBuffer = &IndexBuffer; Mesh.VertexFactory = &VertexFactory; BatchElement.PrimitiveUniformBufferResource = &GetUniformBuffer(); BatchElement.FirstIndex = 0; BatchElement.NumPrimitives = IndexBuffer.Indices.Num() / 3; BatchElement.MinVertexIndex = 0; BatchElement.MaxVertexIndex = VertexBuffer.Vertices.Num() - 1; Mesh.ReverseCulling = IsLocalToWorldDeterminantNegative(); Mesh.bDisableBackfaceCulling = false; Mesh.Type = PT_TriangleList; Mesh.DepthPriorityGroup = SDPG_World; const bool bUseSelectedMaterial = GIsEditor && (View->Family->EngineShowFlags.Selection) ? IsSelected() : false; Mesh.MaterialRenderProxy = TextMaterial->GetRenderProxy(bUseSelectedMaterial); Mesh.bCanApplyViewModeOverrides = !bAlwaysRenderAsText; Collector.AddMesh(ViewIndex, Mesh); #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) RenderBounds(Collector.GetPDI(ViewIndex), View->Family->EngineShowFlags, GetBounds(), IsSelected()); #endif } } } }
void FTextRenderSceneProxy::DrawStaticElements(FStaticPrimitiveDrawInterface* PDI) { // Vertex factory will not been initialized when the font is invalid or the text string is empty. if(VertexFactory.IsInitialized()) { // Draw the mesh. FMeshBatch Mesh; FMeshBatchElement& BatchElement = Mesh.Elements[0]; BatchElement.IndexBuffer = &IndexBuffer; Mesh.VertexFactory = &VertexFactory; Mesh.MaterialRenderProxy = TextMaterial->GetRenderProxy(false); BatchElement.PrimitiveUniformBufferResource = &GetUniformBuffer(); BatchElement.FirstIndex = 0; BatchElement.NumPrimitives = IndexBuffer.Indices.Num() / 3; BatchElement.MinVertexIndex = 0; BatchElement.MaxVertexIndex = VertexBuffer.Vertices.Num() - 1; Mesh.ReverseCulling = IsLocalToWorldDeterminantNegative(); Mesh.bDisableBackfaceCulling = false; Mesh.Type = PT_TriangleList; Mesh.DepthPriorityGroup = SDPG_World; PDI->DrawMesh(Mesh, 1.0f); } }
void USkeletalMeshComponent::TickAnimation(float DeltaTime) { SCOPE_CYCLE_COUNTER(STAT_AnimTickTime); if (SkeletalMesh != NULL) { if (AnimScriptInstance != NULL) { // Tick the animation AnimScriptInstance->UpdateAnimation(DeltaTime * GlobalAnimRateScale); // TODO @LinaH - I've hit access violations due to AnimScriptInstance being NULL after this, probably due to // AnimNotifies? Please take a look and fix as we discussed. Temporary fix: if (AnimScriptInstance != NULL) { // now all tick/trigger/kismet is done // add MorphTarget Curves from Kismet driven or any other source // and overwrite if it exists // Tick always should maintain this list, not Evaluate for( auto Iter = MorphTargetCurves.CreateConstIterator(); Iter; ++Iter ) { float *CurveValPtr = AnimScriptInstance->MorphTargetCurves.Find(Iter.Key()); if ( CurveValPtr ) { // override the value if Kismet request was made *CurveValPtr = Iter.Value(); } else { AnimScriptInstance->MorphTargetCurves.Add(Iter.Key(), Iter.Value()); } } //Update material parameters if(AnimScriptInstance->MaterialParameterCurves.Num() > 0) { for( auto Iter = AnimScriptInstance->MaterialParameterCurves.CreateConstIterator(); Iter; ++Iter ) { FName ParameterName = Iter.Key(); float ParameterValue = Iter.Value(); for(int32 MaterialIndex = 0; MaterialIndex < GetNumMaterials(); ++MaterialIndex) { UMaterialInterface* MaterialInterface = GetMaterial(MaterialIndex); if (MaterialInterface) { float TestValue; //not used but needed for GetScalarParameterValue call if(MaterialInterface->GetScalarParameterValue(ParameterName,TestValue)) { UMaterialInstanceDynamic* DynamicMaterial = Cast<UMaterialInstanceDynamic>(MaterialInterface); if(!DynamicMaterial) //Is it already a UMaterialInstanceDynamic (ie we used it last tick) { DynamicMaterial = CreateAndSetMaterialInstanceDynamic(MaterialIndex); } DynamicMaterial->SetScalarParameterValue(ParameterName, ParameterValue); //Assume that we only set the parameter on one of the materials, remove this break //if that is no longer desired break; } } } } } } } } }
void UJanusExporterTool::Export() { TArray<UObject*> ObjectsToExport; FString Root = FString(ExportPath); // copy so we dont mess with the original reference FString Index = "<html>\n\t<head>\n\t\t<title>Unreal Export</title>\n\t</head>\n\t<body>\n\t\t<FireBoxRoom>\n\t\t\t<Assets>"; TArray<AActor*> ActorsExported; TArray<UStaticMesh*> StaticMeshesExp; TArray<FString> TexturesExp; TArray<FString> MaterialsExported; for (TObjectIterator<AActor> Itr; Itr; ++Itr) { AActor *Actor = *Itr; FString Name = Actor->GetName(); /*if (!Name.StartsWith("SM_Floor_R")) { continue; }*/ if (Actor->IsHiddenEd()) { continue; } ActorsExported.Add(Actor); TArray<UStaticMeshComponent*> StaticMeshes; Actor->GetComponents<UStaticMeshComponent>(StaticMeshes); for (int32 i = 0; i < StaticMeshes.Num(); i++) { UStaticMeshComponent* Component = StaticMeshes[i]; UStaticMesh *Mesh = Component->StaticMesh; if (!Mesh) { continue; } if (Component->LODData.Num() > 0) //if (false) { FStaticMeshComponentLODInfo* LODInfo = &Component->LODData[0]; FLightMap* LightMap = LODInfo->LightMap; FShadowMap* ShadowMap = LODInfo->ShadowMap; if (LightMap != NULL) { FLightMap2D* LightMap2D = LightMap->GetLightMap2D(); UTexture2D* Texture = LightMap2D->GetTexture(0); // 0 = HQ LightMap FString TexName = Texture->GetName(); if (TexturesExp.Contains(TexName)) { continue; } TexturesExp.Add(TexName); ExportPNG(Texture, Root); } if (ShadowMap != NULL) { FShadowMap2D* ShadowMap2D = ShadowMap->GetShadowMap2D(); UShadowMapTexture2D* ShadowTex = ShadowMap2D->GetTexture(); FString TexName = ShadowTex->GetName(); if (TexturesExp.Contains(TexName)) { continue; } TexturesExp.Add(TexName); ExportPNG(ShadowTex, Root); } } if (!StaticMeshesExp.Contains(Mesh)) { StaticMeshesExp.Add(Mesh); ExportFBX(Mesh, Root); } TArray<UMaterialInterface*> Materials = Component->GetMaterials(); for (int32 j = 0; j < Materials.Num(); j++) { UMaterialInterface* Material = Materials[j]; if (!Material) { continue; } FString MatName = Material->GetName(); if (MaterialsExported.Contains(MatName)) { continue; } MaterialsExported.Add(MatName); ExportMaterial(Root, Material, &TexturesExp); } } } // Models before textures so we can start showing the scene faster (textures take too long to load) for (int32 i = 0; i < StaticMeshesExp.Num(); i++) { UStaticMesh *mesh = StaticMeshesExp[i]; Index.Append("\n\t\t\t\t<AssetObject id=\"" + mesh->GetName() + "\" src=\"" + mesh->GetName() + ".fbx\" />"); } for (int32 i = 0; i < TexturesExp.Num(); i++) { FString Path = TexturesExp[i]; Index.Append("\n\t\t\t\t<AssetImage id=\"" + Path + "\" src=\"" + Path + ".png\" />"); } Index.Append("\n\t\t\t</Assets>\n\t\t\t<Room>"); for (int32 i = 0; i < ActorsExported.Num(); i++) { AActor *Actor = ActorsExported[i]; TArray<UStaticMeshComponent*> StaticMeshes; Actor->GetComponents<UStaticMeshComponent>(StaticMeshes); for (int32 i = 0; i < StaticMeshes.Num(); i++) { UStaticMeshComponent* Component = StaticMeshes[i]; UStaticMesh *Mesh = Component->StaticMesh; if (!Mesh) { continue; } FString ImageID = ""; TArray<UMaterialInterface*> Materials = Component->GetMaterials(); for (int32 j = 0; j < Materials.Num(); j++) { UMaterialInterface* Material = Materials[j]; if (!Material) { continue; } ImageID = Material->GetName() + "_BaseColor"; break; } if (ImageID == "") { Index.Append("\n\t\t\t\t<Object collision_id=\"" + Mesh->GetName() + "\" id=\"" + Mesh->GetName() + "\" lighting=\"true\" pos=\""); } else { Index.Append("\n\t\t\t\t<Object collision_id=\"" + Mesh->GetName() + "\" id=\"" + Mesh->GetName() + "\" image_id=\"" + ImageID + "\" lighting=\"true\" pos=\""); } FRotator Rot = Actor->GetActorRotation(); FVector XDir = Rot.RotateVector(FVector::RightVector); FVector YDir = Rot.RotateVector(FVector::UpVector); FVector ZDir = Rot.RotateVector(FVector::ForwardVector); FVector Pos = Actor->GetActorLocation() * UniformScale; FVector Sca = Actor->GetActorScale(); Pos = ChangeSpace(Pos); Sca = ChangeSpaceScalar(Sca) * UniformScale; XDir = ChangeSpace(XDir); YDir = ChangeSpace(YDir); ZDir = ChangeSpace(ZDir); FVector Sign = GetSignVector(Sca); Index.Append(FString::SanitizeFloat(Pos.X) + " " + FString::SanitizeFloat(Pos.Y) + " " + FString::SanitizeFloat(Pos.Z)); if (Sca.X < 0 || Sca.Y < 0 || Sca.Z < 0) { Index.Append("\" cull_face=\"front"); } Index.Append("\" scale=\""); Index.Append(FString::SanitizeFloat(Sca.X) + " " + FString::SanitizeFloat(Sca.Y) + " " + FString::SanitizeFloat(Sca.Z)); Index.Append("\" xdir=\""); Index.Append(FString::SanitizeFloat(XDir.X) + " " + FString::SanitizeFloat(XDir.Y) + " " + FString::SanitizeFloat(XDir.Z)); Index.Append("\" ydir=\""); Index.Append(FString::SanitizeFloat(YDir.X) + " " + FString::SanitizeFloat(YDir.Y) + " " + FString::SanitizeFloat(YDir.Z)); Index.Append("\" zdir=\""); Index.Append(FString::SanitizeFloat(ZDir.X) + " " + FString::SanitizeFloat(ZDir.Y) + " " + FString::SanitizeFloat(ZDir.Z)); Index.Append("\" />"); } } Index.Append("\n\t\t\t</Room>\n\t\t</FireBoxRoom>\n\t</body>\n</html>"); FString IndexPath = FString(ExportPath).Append("index.html"); FFileHelper::SaveStringToFile(Index, *IndexPath); }
bool SetApexDestructibleAsset(UDestructibleMesh& DestructibleMesh, NxDestructibleAsset& ApexDestructibleAsset, FSkeletalMeshImportData* OutData, EImportOptions::Type Options) { DestructibleMesh.PreEditChange(NULL); #if WITH_EDITORONLY_DATA // Handle the StaticMesh import case, where we have the materials only stored in the fracture settings if (DestructibleMesh.Materials.Num() == 0 && DestructibleMesh.FractureSettings != NULL && DestructibleMesh.FractureSettings->Materials.Num() > 0) { for (int32 i=0; i < DestructibleMesh.FractureSettings->Materials.Num(); ++i) { FSkeletalMaterial Mat; Mat.MaterialInterface = DestructibleMesh.FractureSettings->Materials[i]; Mat.bEnableShadowCasting = true; DestructibleMesh.Materials.Add(Mat); } } #endif ExistingDestMeshData* ExistDestMeshDataPtr = NULL; ExistDestMeshDataPtr = SaveExistingDestMeshData(&DestructibleMesh); // The asset is going away, which will destroy any actors created from it. We must destroy the physics state of any destructible mesh components before we release the asset. for(TObjectIterator<UDestructibleComponent> It; It; ++It) { UDestructibleComponent* DestructibleComponent = *It; if(DestructibleComponent->SkeletalMesh == &DestructibleMesh && DestructibleComponent->GetScene()) { DestructibleComponent->DestroyPhysicsState(); } } // Release old NxDestructibleAsset if it exists if (DestructibleMesh.ApexDestructibleAsset != NULL && DestructibleMesh.ApexDestructibleAsset != &ApexDestructibleAsset) { GPhysCommandHandler->DeferredRelease(DestructibleMesh.ApexDestructibleAsset); } // BRGTODO - need to remove the render data from the ApexDestructibleAsset, no longer need it // Removing const cast ... we'll have to make it non-const anyway when we modify it DestructibleMesh.ApexDestructibleAsset = &ApexDestructibleAsset; if ( !(Options&EImportOptions::PreserveSettings) ) { // Resize the depth parameters array to the appropriate size DestructibleMesh.DefaultDestructibleParameters.DepthParameters.Init(FDestructibleDepthParameters(), ApexDestructibleAsset.getDepthCount()); // Resize the fracture effects array to the appropriate size DestructibleMesh.FractureEffects.AddZeroed(ApexDestructibleAsset.getDepthCount()); // Load the UnrealEd-editable parameters from the destructible asset DestructibleMesh.LoadDefaultDestructibleParametersFromApexAsset(); } // Create body setup for the destructible mesh DestructibleMesh.CreateBodySetup(); #if 0 // BRGTODO // warning for missing smoothing group info CheckSmoothingInfo(FbxMesh); #endif FSkeletalMeshImportData TempData; // Fill with data from buffer FSkeletalMeshImportData* SkelMeshImportDataPtr = &TempData; if( OutData ) { SkelMeshImportDataPtr = OutData; } // Import animation hierarchy, although this is trivial for an Apex Destructible Asset CreateBones(*SkelMeshImportDataPtr, ApexDestructibleAsset); if (!(Options & EImportOptions::PreserveSettings)) { // Get all material names here ImportMaterialsForSkelMesh(*SkelMeshImportDataPtr, ApexDestructibleAsset); } else { SkelMeshImportDataPtr->Materials.Empty(DestructibleMesh.Materials.Num()); for (int32 i=0; i < DestructibleMesh.Materials.Num(); ++i) { UMaterialInterface* MI = DestructibleMesh.Materials[i].MaterialInterface; VMaterial NewMat; NewMat.MaterialName = MI != NULL ? MI->GetName() : TEXT(""); SkelMeshImportDataPtr->Materials.Add(NewMat); } } // Import graphics data bool bHaveNormals, bHaveTangents; if (!FillSkelMeshImporterFromApexDestructibleAsset(*SkelMeshImportDataPtr, ApexDestructibleAsset, bHaveNormals, bHaveTangents)) { return false; } #if 0 // BRGTODO - what is this? if( SkelMeshImportDataPtr->Materials.Num() == FbxMatList.Num() ) { // reorder material according to "SKinXX" in material name SetMaterialSkinXXOrder(*SkelMeshImportDataPtr, FbxMatList ); } #endif #if 0 // BRGTODO - what is this? if( ImportOptions->bSplitNonMatchingTriangles ) { DoUnSmoothVerts(*SkelMeshImportDataPtr); } #endif if ( !(Options&EImportOptions::PreserveSettings) ) { // process materials from import data ProcessImportMeshMaterials( DestructibleMesh.Materials,*SkelMeshImportDataPtr ); } // process reference skeleton from import data int32 SkeletalDepth=0; if(!ProcessImportMeshSkeleton(DestructibleMesh.RefSkeleton, SkeletalDepth, *SkelMeshImportDataPtr)) { return false; } UE_LOG(LogApexDestructibleAssetImport, Warning, TEXT("Bones digested - %i Depth of hierarchy - %i"), DestructibleMesh.RefSkeleton.GetNum(), SkeletalDepth); // process bone influences from import data ProcessImportMeshInfluences(*SkelMeshImportDataPtr); FSkeletalMeshResource& DestructibleMeshResource = *DestructibleMesh.GetImportedResource(); check(DestructibleMeshResource.LODModels.Num() == 0); DestructibleMeshResource.LODModels.Empty(); new(DestructibleMeshResource.LODModels)FStaticLODModel(); DestructibleMesh.LODInfo.Empty(); DestructibleMesh.LODInfo.AddZeroed(); DestructibleMesh.LODInfo[0].LODHysteresis = 0.02f; // Create initial bounding box based on expanded version of reference pose for meshes without physics assets. Can be overridden by artist. FBox BoundingBox( SkelMeshImportDataPtr->Points.GetTypedData(), SkelMeshImportDataPtr->Points.Num() ); FBox Temp = BoundingBox; FVector MidMesh = 0.5f*(Temp.Min + Temp.Max); BoundingBox.Min = Temp.Min + 1.0f*(Temp.Min - MidMesh); BoundingBox.Max = Temp.Max + 1.0f*(Temp.Max - MidMesh); // BRGTODO : what is this? // Tuck up the bottom as this rarely extends lower than a reference pose's (e.g. having its feet on the floor). // Maya has Y in the vertical, other packages have Z. //BEN const int32 CoordToTuck = bAssumeMayaCoordinates ? 1 : 2; //BEN BoundingBox.Min[CoordToTuck] = Temp.Min[CoordToTuck] + 0.1f*(Temp.Min[CoordToTuck] - MidMesh[CoordToTuck]); BoundingBox.Min[2] = Temp.Min[2] + 0.1f*(Temp.Min[2] - MidMesh[2]); DestructibleMesh.Bounds= FBoxSphereBounds(BoundingBox); // Store whether or not this mesh has vertex colors DestructibleMesh.bHasVertexColors = SkelMeshImportDataPtr->bHasVertexColors; FStaticLODModel& LODModel = DestructibleMeshResource.LODModels[0]; // Pass the number of texture coordinate sets to the LODModel. Ensure there is at least one UV coord LODModel.NumTexCoords = FMath::Max<uint32>(1,SkelMeshImportDataPtr->NumTexCoords); // if( bCreateRenderData ) // We always create render data { // copy vertex data needed to generate skinning streams for LOD TArray<FVector> LODPoints; TArray<FMeshWedge> LODWedges; TArray<FMeshFace> LODFaces; TArray<FVertInfluence> LODInfluences; TArray<int32> LODPointToRawMap; SkelMeshImportDataPtr->CopyLODImportData(LODPoints,LODWedges,LODFaces,LODInfluences,LODPointToRawMap); #include "Developer/MeshUtilities/Public/MeshUtilities.h" IMeshUtilities& MeshUtilities = FModuleManager::Get().LoadModuleChecked<IMeshUtilities>("MeshUtilities"); // Create actual rendering data. if (!MeshUtilities.BuildSkeletalMesh(DestructibleMeshResource.LODModels[0], DestructibleMesh.RefSkeleton, LODInfluences,LODWedges,LODFaces,LODPoints,LODPointToRawMap,false,!bHaveNormals,!bHaveTangents)) { DestructibleMesh.MarkPendingKill(); return false; } // Presize the per-section shadow casting array with the number of sections in the imported LOD. const int32 NumSections = LODModel.Sections.Num(); for ( int32 SectionIndex = 0 ; SectionIndex < NumSections ; ++SectionIndex ) { DestructibleMesh.LODInfo[0].TriangleSortSettings.AddZeroed(); } if (ExistDestMeshDataPtr) { RestoreExistingDestMeshData(ExistDestMeshDataPtr, &DestructibleMesh); delete ExistDestMeshDataPtr; ExistDestMeshDataPtr = NULL; } DestructibleMesh.CalculateInvRefMatrices(); DestructibleMesh.PostEditChange(); DestructibleMesh.MarkPackageDirty(); #if 0 // BRGTODO : Check, we don't need this, do we? // We have to go and fix any AnimSetMeshLinkup objects that refer to this skeletal mesh, as the reference skeleton has changed. for(TObjectIterator<UAnimSet> It;It;++It) { UAnimSet* AnimSet = *It; // Get DestructibleMesh path name FName SkelMeshName = FName( *DestructibleMesh.GetPathName() ); // See if we have already cached this Skeletal Mesh. const int32* IndexPtr = AnimSet->SkelMesh2LinkupCache.Find( SkelMeshName ); if( IndexPtr ) { AnimSet->LinkupCache( *IndexPtr ).BuildLinkup( &DestructibleMesh, AnimSet ); } } #endif // Now iterate over all skeletal mesh components re-initialising them. for(TObjectIterator<UDestructibleComponent> It; It; ++It) { UDestructibleComponent* DestructibleComponent = *It; if(DestructibleComponent->SkeletalMesh == &DestructibleMesh && DestructibleComponent->GetScene()) { FComponentReregisterContext ReregisterContext(DestructibleComponent); } } } #if INVERT_Y_AND_V // Apply transformation for Y inversion const physx::PxMat44 MirrorY = physx::PxMat44(physx::PxVec4(1.0f, -1.0f, 1.0f, 1.0f)); #if !USE_TEMPORARY_TRANSFORMATION_FUNCTION ApexDestructibleAsset.applyTransformation(MirrorY, 1.0f); #else ApplyTransformationToApexDestructibleAsset( ApexDestructibleAsset, MirrorY ); #endif #endif return true; }
void UTexture::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) { Super::PostEditChangeProperty(PropertyChangedEvent); SetLightingGuid(); // Determine whether any property that requires recompression of the texture, or notification to Materials has changed. bool RequiresNotifyMaterials = false; bool DeferCompressionWasEnabled = false; UProperty* PropertyThatChanged = PropertyChangedEvent.Property; if( PropertyThatChanged ) { static const FName CompressionSettingsName("CompressionSettings"); static const FName LODGroupName("LODGroup"); static const FName DeferCompressionName("DeferCompression"); #if WITH_EDITORONLY_DATA static const FName MaxTextureSizeName("MaxTextureSize"); #endif // #if WITH_EDITORONLY_DATA const FName PropertyName = PropertyThatChanged->GetFName(); if (PropertyName == CompressionSettingsName || PropertyName == LODGroupName) { RequiresNotifyMaterials = true; } else if (PropertyName == DeferCompressionName) { DeferCompressionWasEnabled = DeferCompression; } #if WITH_EDITORONLY_DATA else if (PropertyName == MaxTextureSizeName) { if (MaxTextureSize <= 0) { MaxTextureSize = 0; } else { MaxTextureSize = FMath::Min<int32>(FMath::RoundUpToPowerOfTwo(MaxTextureSize), GetMaximumDimension()); } } #endif // #if WITH_EDITORONLY_DATA bool bPreventSRGB = (CompressionSettings == TC_Alpha || CompressionSettings == TC_Normalmap || CompressionSettings == TC_Masks || CompressionSettings == TC_HDR || CompressionSettings == TC_HDR_Compressed); if(bPreventSRGB && SRGB == true) { SRGB = false; } } else { FMaterialUpdateContext UpdateContext; // Update any material that uses this texture TSet<UMaterial*> BaseMaterialsThatUseThisTexture; for (TObjectIterator<UMaterialInterface> It; It; ++It) { UMaterialInterface* MaterialInterface = *It; if (DoesMaterialUseTexture(MaterialInterface, this)) { UMaterial *Material = MaterialInterface->GetMaterial(); bool MaterialAlreadyCompute = false; BaseMaterialsThatUseThisTexture.Add(Material, &MaterialAlreadyCompute); if (!MaterialAlreadyCompute) { UpdateContext.AddMaterial(Material); if (Material->IsTextureForceRecompileCacheRessource(this)) { Material->UpdateMaterialShaderCacheAndTextureReferences(); } } } } //If the DDC key was different the material is already recompile here RequiresNotifyMaterials = false; } NumCinematicMipLevels = FMath::Max<int32>( NumCinematicMipLevels, 0 ); // Don't update the texture resource if we've turned "DeferCompression" on, as this // would cause it to immediately update as an uncompressed texture if( !DeferCompressionWasEnabled && (PropertyChangedEvent.ChangeType & EPropertyChangeType::Interactive) == 0 ) { // Update the texture resource. This will recache derived data if necessary // which may involve recompressing the texture. UpdateResource(); } // Notify any loaded material instances if changed our compression format if (RequiresNotifyMaterials) { TArray<UMaterialInterface*> MaterialsThatUseThisTexture; // Create a material update context to safely update materials. { FMaterialUpdateContext UpdateContext; // Notify any material that uses this texture TSet<UMaterial*> BaseMaterialsThatUseThisTexture; for (TObjectIterator<UMaterialInterface> It; It; ++It) { UMaterialInterface* MaterialInterface = *It; if (DoesMaterialUseTexture(MaterialInterface,this)) { MaterialsThatUseThisTexture.Add(MaterialInterface); // This is a bit tricky. We want to make sure all materials using this texture are // updated. Materials are always updated. Material instances may also have to be // updated and if they have static permutations their children must be updated // whether they use the texture or not! The safe thing to do is to add the instance's // base material to the update context causing all materials in the tree to update. BaseMaterialsThatUseThisTexture.Add(MaterialInterface->GetMaterial()); } } // Go ahead and update any base materials that need to be. for (TSet<UMaterial*>::TConstIterator It(BaseMaterialsThatUseThisTexture); It; ++It) { UpdateContext.AddMaterial(*It); (*It)->PostEditChange(); } } // Now that all materials and instances have updated send necessary callbacks. for (int32 i = 0; i < MaterialsThatUseThisTexture.Num(); ++i) { FEditorSupportDelegates::MaterialTextureSettingsChanged.Broadcast(MaterialsThatUseThisTexture[i]); } } #if WITH_EDITORONLY_DATA // any texture that is referencing this texture as AssociatedNormalMap needs to be informed { TArray<UTexture*> TexturesThatUseThisTexture; for (TObjectIterator<UTexture> It; It; ++It) { UTexture* Tex = *It; if(Tex != this && Tex->CompositeTexture == this && Tex->CompositeTextureMode != CTM_Disabled) { TexturesThatUseThisTexture.Add(Tex); } } for (int32 i = 0; i < TexturesThatUseThisTexture.Num(); ++i) { TexturesThatUseThisTexture[i]->PostEditChange(); } } #endif }
void Assignment::ApplyToMeshes() { UClass *refMeshClass= AStaticMeshActor::StaticClass(); UClass *refSkeletaMeshClass = ASkeletalMeshActor::StaticClass(); for (TObjectIterator<UObject> Itr; Itr; ++Itr) { if (Itr->GetClass()->IsChildOf(refMeshClass)) { UE_LOG(ModoMaterialImporter, Log, TEXT("Scan materials in: %s %s"), *Itr->GetName(), *Itr->GetClass()->GetDesc()); AStaticMeshActor *aMeshActor = dynamic_cast<AStaticMeshActor*> (*Itr); if (aMeshActor != NULL) { UMeshComponent* meshCompo = aMeshActor->GetStaticMeshComponent(); if (meshCompo != NULL) { for (int i = 0; i < meshCompo->GetNumMaterials(); i++) { UMaterialInterface* material = meshCompo->GetMaterial(i); // It seems a UE4 bug, GetNumMaterials contains NULL materials! if (material == NULL) continue; std::string strName = (TCHAR_TO_UTF8(*material->GetName())); std::map<std::string, UMaterial*>::iterator mat_itr = Materials.find(strName); if (mat_itr != Materials.end()) { UE_LOG(ModoMaterialImporter, Log, TEXT("Set Material: %s"), *material->GetName()); meshCompo->SetMaterial(i, mat_itr->second); } } } } } else if (Itr->GetClass()->IsChildOf(refSkeletaMeshClass)) { UE_LOG(ModoMaterialImporter, Log, TEXT("Scan materials in: %s %s"), *Itr->GetName(), *Itr->GetClass()->GetDesc()); ASkeletalMeshActor *aMeshActor = dynamic_cast<ASkeletalMeshActor*> (*Itr); if (aMeshActor != NULL) { UMeshComponent * meshCompo = aMeshActor->GetSkeletalMeshComponent(); for (int i = 0; i < meshCompo->GetNumMaterials(); i++) { UMaterialInterface* material = meshCompo->GetMaterial(i); // It seems a UE4 bug, GetNumMaterials contains NULL materials! if (material == NULL) continue; std::string strName = (TCHAR_TO_UTF8(*material->GetName())); std::map<std::string, UMaterial*>::iterator mat_itr = Materials.find(strName); if (mat_itr != Materials.end()) { UE_LOG(ModoMaterialImporter, Log, TEXT("Set Material: %s"), *material->GetName()); meshCompo->SetMaterial(i, mat_itr->second); } } } } } }
void FStaticMeshEditorViewportClient::ProcessClick(class FSceneView& InView, class HHitProxy* HitProxy, FKey Key, EInputEvent Event, uint32 HitX, uint32 HitY) { const bool bCtrlDown = Viewport->KeyState(EKeys::LeftControl) || Viewport->KeyState(EKeys::RightControl); bool ClearSelectedSockets = true; bool ClearSelectedPrims = true; bool ClearSelectedEdges = true; if( HitProxy ) { if(HitProxy->IsA( HSMESocketProxy::StaticGetType() ) ) { HSMESocketProxy* SocketProxy = (HSMESocketProxy*)HitProxy; UStaticMeshSocket* Socket = NULL; if(SocketProxy->SocketIndex < StaticMesh->Sockets.Num()) { Socket = StaticMesh->Sockets[SocketProxy->SocketIndex]; } if(Socket) { StaticMeshEditorPtr.Pin()->SetSelectedSocket(Socket); } ClearSelectedSockets = false; } else if (HitProxy->IsA(HSMECollisionProxy::StaticGetType()) && StaticMesh->BodySetup) { HSMECollisionProxy* CollisionProxy = (HSMECollisionProxy*)HitProxy; if (StaticMeshEditorPtr.Pin()->IsSelectedPrim(CollisionProxy->PrimData)) { if (!bCtrlDown) { StaticMeshEditorPtr.Pin()->AddSelectedPrim(CollisionProxy->PrimData, true); } else { StaticMeshEditorPtr.Pin()->RemoveSelectedPrim(CollisionProxy->PrimData); } } else { StaticMeshEditorPtr.Pin()->AddSelectedPrim(CollisionProxy->PrimData, !bCtrlDown); } // Force the widget to translate, if not already set if (WidgetMode == FWidget::WM_None) { WidgetMode = FWidget::WM_Translate; } ClearSelectedPrims = false; } } else { const bool bShiftDown = Viewport->KeyState(EKeys::LeftShift) || Viewport->KeyState(EKeys::RightShift); if(!bCtrlDown && !bShiftDown) { SelectedEdgeIndices.Empty(); } // Check to see if we clicked on a mesh edge if( StaticMeshComponent != NULL && Viewport->GetSizeXY().X > 0 && Viewport->GetSizeXY().Y > 0 ) { FSceneViewFamilyContext ViewFamily( FSceneViewFamily::ConstructionValues( Viewport, GetScene(), EngineShowFlags )); FSceneView* View = CalcSceneView(&ViewFamily); FViewportClick ViewportClick(View, this, Key, Event, HitX, HitY); const FVector ClickLineStart( ViewportClick.GetOrigin() ); const FVector ClickLineEnd( ViewportClick.GetOrigin() + ViewportClick.GetDirection() * HALF_WORLD_MAX ); // Don't bother doing a line check as there is only one mesh in the SME and it makes fuzzy selection difficult // FHitResult CheckResult( 1.0f ); // if( StaticMeshComponent->LineCheck( // CheckResult, // In/Out: Result // ClickLineEnd, // Target // ClickLineStart, // Source // FVector::ZeroVector, // Extend // TRACE_ComplexCollision ) ) // Trace flags { // @todo: Should be in screen space ideally const float WorldSpaceMinClickDistance = 100.0f; float ClosestEdgeDistance = FLT_MAX; TArray< int32 > ClosestEdgeIndices; FVector ClosestEdgeVertices[ 2 ]; const uint32 LODLevel = FMath::Clamp( StaticMeshComponent->ForcedLodModel - 1, 0, StaticMeshComponent->StaticMesh->GetNumLODs() - 1 ); FRawMesh RawMesh; StaticMeshComponent->StaticMesh->SourceModels[LODLevel].RawMeshBulkData->LoadRawMesh(RawMesh); const int32 RawEdgeCount = RawMesh.WedgeIndices.Num() - 1; const int32 NumFaces = RawMesh.WedgeIndices.Num() / 3; int32 NumBackFacingTriangles = 0; for(int32 FaceIndex = 0; FaceIndex < NumFaces; ++FaceIndex) { // We disable edge selection where all adjoining triangles are back face culled and the // material is not two-sided. This prevents edges that are back-face culled from being selected. bool bIsBackFacing = false; bool bIsTwoSided = false; UMaterialInterface* Material = StaticMeshComponent->GetMaterial(RawMesh.FaceMaterialIndices[FaceIndex]); if (Material && Material->GetMaterial()) { bIsTwoSided = Material->IsTwoSided(); } if(!bIsTwoSided) { // Check whether triangle if back facing const FVector A = RawMesh.GetWedgePosition( FaceIndex * 3); const FVector B = RawMesh.GetWedgePosition( FaceIndex * 3 + 1); const FVector C = RawMesh.GetWedgePosition( FaceIndex * 3 + 2); // Compute the per-triangle normal const FVector BA = A - B; const FVector CA = A - C; const FVector TriangleNormal = (CA ^ BA).SafeNormal(); // Transform the view position from world to component space const FVector ComponentSpaceViewOrigin = StaticMeshComponent->ComponentToWorld.InverseTransformPosition( View->ViewMatrices.ViewOrigin); // Determine which side of the triangle's plane that the view position lies on. bIsBackFacing = (FVector::PointPlaneDist( ComponentSpaceViewOrigin, A, TriangleNormal) < 0.0f); } for( int32 VertIndex = 0; VertIndex < 3; ++VertIndex ) { const int32 EdgeIndex = FaceIndex * 3 + VertIndex; const int32 EdgeIndex2 = FaceIndex * 3 + ((VertIndex + 1) % 3); FVector EdgeVertices[ 2 ]; EdgeVertices[0] = RawMesh.GetWedgePosition(EdgeIndex); EdgeVertices[1] = RawMesh.GetWedgePosition(EdgeIndex2); // First check to see if this edge is already in our "closest to click" list. // Most edges are shared by two faces in our raw triangle data set, so we want // to select (or deselect) both of these edges that the user clicks on (what // appears to be) a single edge if( ClosestEdgeIndices.Num() > 0 && ( ( EdgeVertices[ 0 ].Equals( ClosestEdgeVertices[ 0 ] ) && EdgeVertices[ 1 ].Equals( ClosestEdgeVertices[ 1 ] ) ) || ( EdgeVertices[ 0 ].Equals( ClosestEdgeVertices[ 1 ] ) && EdgeVertices[ 1 ].Equals( ClosestEdgeVertices[ 0 ] ) ) ) ) { // Edge overlaps the closest edge we have so far, so just add it to the list ClosestEdgeIndices.Add( EdgeIndex ); // Increment the number of back facing triangles if the adjoining triangle // is back facing and isn't two-sided if(bIsBackFacing && !bIsTwoSided) { ++NumBackFacingTriangles; } } else { FVector WorldSpaceEdgeStart( StaticMeshComponent->ComponentToWorld.TransformPosition( EdgeVertices[ 0 ] ) ); FVector WorldSpaceEdgeEnd( StaticMeshComponent->ComponentToWorld.TransformPosition( EdgeVertices[ 1 ] ) ); // Determine the mesh edge that's closest to the ray cast through the eye towards the click location FVector ClosestPointToEdgeOnClickLine; FVector ClosestPointToClickLineOnEdge; FMath::SegmentDistToSegment( ClickLineStart, ClickLineEnd, WorldSpaceEdgeStart, WorldSpaceEdgeEnd, ClosestPointToEdgeOnClickLine, ClosestPointToClickLineOnEdge ); // Compute the minimum distance (squared) const float MinDistanceToEdgeSquared = ( ClosestPointToClickLineOnEdge - ClosestPointToEdgeOnClickLine ).SizeSquared(); if( MinDistanceToEdgeSquared <= WorldSpaceMinClickDistance ) { if( MinDistanceToEdgeSquared <= ClosestEdgeDistance ) { // This is the closest edge to the click line that we've found so far! ClosestEdgeDistance = MinDistanceToEdgeSquared; ClosestEdgeVertices[ 0 ] = EdgeVertices[ 0 ]; ClosestEdgeVertices[ 1 ] = EdgeVertices[ 1 ]; ClosestEdgeIndices.Reset(); ClosestEdgeIndices.Add( EdgeIndex ); // Reset the number of back facing triangles. NumBackFacingTriangles = (bIsBackFacing && !bIsTwoSided) ? 1 : 0; } } } } } // Did the user click on an edge? Edges must also have at least one adjoining triangle // which isn't back face culled (for one-sided materials) if( ClosestEdgeIndices.Num() > 0 && ClosestEdgeIndices.Num() > NumBackFacingTriangles) { for( int32 CurIndex = 0; CurIndex < ClosestEdgeIndices.Num(); ++CurIndex ) { const int32 CurEdgeIndex = ClosestEdgeIndices[ CurIndex ]; if( bCtrlDown ) { // Toggle selection if( SelectedEdgeIndices.Contains( CurEdgeIndex ) ) { SelectedEdgeIndices.Remove( CurEdgeIndex ); } else { SelectedEdgeIndices.Add( CurEdgeIndex ); } } else { // Append to selection SelectedEdgeIndices.Add( CurEdgeIndex ); } } // Reset cached vertices and uv coordinates. SelectedEdgeVertices.Reset(); for(int32 TexCoordIndex = 0; TexCoordIndex < MAX_STATIC_TEXCOORDS; ++TexCoordIndex) { SelectedEdgeTexCoords[TexCoordIndex].Reset(); } for(FSelectedEdgeSet::TIterator SelectionIt( SelectedEdgeIndices ); SelectionIt; ++SelectionIt) { const uint32 EdgeIndex = *SelectionIt; const uint32 FaceIndex = EdgeIndex / 3; const uint32 WedgeIndex = FaceIndex * 3 + (EdgeIndex % 3); const uint32 WedgeIndex2 = FaceIndex * 3 + ((EdgeIndex + 1) % 3); // Cache edge vertices in local space. FVector EdgeVertices[ 2 ]; EdgeVertices[ 0 ] = RawMesh.GetWedgePosition(WedgeIndex); EdgeVertices[ 1 ] = RawMesh.GetWedgePosition(WedgeIndex2); SelectedEdgeVertices.Add(EdgeVertices[0]); SelectedEdgeVertices.Add(EdgeVertices[1]); // Cache UV for(int32 TexCoordIndex = 0; TexCoordIndex < MAX_STATIC_TEXCOORDS; ++TexCoordIndex) { if( RawMesh.WedgeTexCoords[TexCoordIndex].Num() > 0) { FVector2D UVIndex1, UVIndex2; UVIndex1 = RawMesh.WedgeTexCoords[TexCoordIndex][WedgeIndex]; UVIndex2 = RawMesh.WedgeTexCoords[TexCoordIndex][WedgeIndex2]; SelectedEdgeTexCoords[TexCoordIndex].Add(UVIndex1); SelectedEdgeTexCoords[TexCoordIndex].Add(UVIndex2); } } } ClearSelectedEdges = false; } } } } if (ClearSelectedSockets && StaticMeshEditorPtr.Pin()->GetSelectedSocket()) { StaticMeshEditorPtr.Pin()->SetSelectedSocket(NULL); } if (ClearSelectedPrims) { StaticMeshEditorPtr.Pin()->ClearSelectedPrims(); } if (ClearSelectedEdges) { SelectedEdgeIndices.Empty(); } Invalidate(); }
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); } }
void UTexture::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) { Super::PostEditChangeProperty(PropertyChangedEvent); SetLightingGuid(); // Determine whether any property that requires recompression of the texture, or notification to Materials has changed. bool RequiresNotifyMaterials = false; UProperty* PropertyThatChanged = PropertyChangedEvent.Property; if( PropertyThatChanged ) { FString PropertyName = *PropertyThatChanged->GetName(); if (FCString::Stricmp(*PropertyName, TEXT("CompressionSettings")) == 0) { RequiresNotifyMaterials = true; } bool bPreventSRGB = (CompressionSettings == TC_Alpha || CompressionSettings == TC_Normalmap || CompressionSettings == TC_Masks || CompressionSettings == TC_HDR); if(bPreventSRGB && SRGB == true) { SRGB = false; } } NumCinematicMipLevels = FMath::Max<int32>( NumCinematicMipLevels, 0 ); if( (PropertyChangedEvent.ChangeType & EPropertyChangeType::Interactive) == 0 ) { // Update the texture resource. This will recache derived data if necessary // which may involve recompressing the texture. UpdateResource(); } // Notify any loaded material instances if changed our compression format if (RequiresNotifyMaterials) { TArray<UMaterialInterface*> MaterialsThatUseThisTexture; // Create a material update context to safely update materials. { FMaterialUpdateContext UpdateContext; // Notify any material that uses this texture TSet<UMaterial*> BaseMaterialsThatUseThisTexture; for (TObjectIterator<UMaterialInterface> It; It; ++It) { UMaterialInterface* MaterialInterface = *It; if (DoesMaterialUseTexture(MaterialInterface,this)) { MaterialsThatUseThisTexture.Add(MaterialInterface); // This is a bit tricky. We want to make sure all materials using this texture are // updated. Materials are always updated. Material instances may also have to be // updated and if they have static permutations their children must be updated // whether they use the texture or not! The safe thing to do is to add the instance's // base material to the update context causing all materials in the tree to update. BaseMaterialsThatUseThisTexture.Add(MaterialInterface->GetMaterial()); } } // Go ahead and update any base materials that need to be. for (TSet<UMaterial*>::TConstIterator It(BaseMaterialsThatUseThisTexture); It; ++It) { UpdateContext.AddMaterial(*It); (*It)->PostEditChange(); } } // Now that all materials and instances have updated send necessary callbacks. for (int32 i = 0; i < MaterialsThatUseThisTexture.Num(); ++i) { FEditorSupportDelegates::MaterialTextureSettingsChanged.Broadcast(MaterialsThatUseThisTexture[i]); } } #if WITH_EDITORONLY_DATA // any texture that is referencing this texture as AssociatedNormalMap needs to be informed { TArray<UTexture*> TexturesThatUseThisTexture; for (TObjectIterator<UTexture> It; It; ++It) { UTexture* Tex = *It; if(Tex != this && Tex->CompositeTexture == this && Tex->CompositeTextureMode != CTM_Disabled) { TexturesThatUseThisTexture.Add(Tex); } } for (int32 i = 0; i < TexturesThatUseThisTexture.Num(); ++i) { TexturesThatUseThisTexture[i]->PostEditChange(); } } #endif }