void FStaticMeshEditorViewportClient::DrawCanvas( FViewport& InViewport, FSceneView& View, FCanvas& Canvas ) { #if TODO_STATICMESH if ( StaticMesh->bHasBeenSimplified && SimplygonLogo && SimplygonLogo->Resource ) { const float LogoSizeX = 64.0f; const float LogoSizeY = 40.65f; const float Padding = 6.0f; const float LogoX = Viewport->GetSizeXY().X - Padding - LogoSizeX; const float LogoY = Viewport->GetSizeXY().Y - Padding - LogoSizeY; Canvas->DrawTile( LogoX, LogoY, LogoSizeX, LogoSizeY, 0.0f, 0.0f, 1.0f, 1.0f, FLinearColor::White, SimplygonLogo->Resource, SE_BLEND_Opaque ); } #endif // #if TODO_STATICMESH auto StaticMeshEditor = StaticMeshEditorPtr.Pin(); auto StaticMeshEditorViewport = StaticMeshEditorViewportPtr.Pin(); if (!StaticMeshEditor.IsValid() || !StaticMeshEditorViewport.IsValid()) { return; } const int32 HalfX = Viewport->GetSizeXY().X/2; const int32 HalfY = Viewport->GetSizeXY().Y/2; // Draw socket names if desired. if( bShowSockets ) { for(int32 i=0; i<StaticMesh->Sockets.Num(); i++) { UStaticMeshSocket* Socket = StaticMesh->Sockets[i]; if(Socket!=NULL) { FMatrix SocketTM; Socket->GetSocketMatrix(SocketTM, StaticMeshComponent); const FVector SocketPos = SocketTM.GetOrigin(); const FPlane proj = View.Project( SocketPos ); if(proj.W > 0.f) { const int32 XPos = HalfX + ( HalfX * proj.X ); const int32 YPos = HalfY + ( HalfY * (proj.Y * -1) ); FCanvasTextItem TextItem( FVector2D( XPos, YPos ), FText::FromString( Socket->SocketName.ToString() ), GEngine->GetSmallFont(), FLinearColor(FColor(255,196,196)) ); Canvas.DrawItem( TextItem ); const UStaticMeshSocket* SelectedSocket = StaticMeshEditor->GetSelectedSocket(); if (bManipulating && SelectedSocket == Socket) { //Figure out the text height FTextSizingParameters Parameters(GEngine->GetSmallFont(), 1.0f, 1.0f); UCanvas::CanvasStringSize(Parameters, *Socket->SocketName.ToString()); int32 YL = FMath::TruncToInt(Parameters.DrawYL); DrawAngles(&Canvas, XPos, YPos + YL, Widget->GetCurrentAxis(), GetWidgetMode(), Socket->RelativeRotation, Socket->RelativeLocation); } } } } } TArray<SStaticMeshEditorViewport::FOverlayTextItem> TextItems; int32 CurrentLODLevel = StaticMeshEditor->GetCurrentLODLevel(); if (CurrentLODLevel == 0) { CurrentLODLevel = ComputeStaticMeshLOD(StaticMesh->RenderData, StaticMeshComponent->Bounds.Origin, StaticMeshComponent->Bounds.SphereRadius, View); } else { CurrentLODLevel -= 1; } TextItems.Add(SStaticMeshEditorViewport::FOverlayTextItem( FText::Format(NSLOCTEXT("UnrealEd", "LOD_F", "LOD: {0}"), FText::AsNumber(CurrentLODLevel)))); float CurrentScreenSize = ComputeBoundsScreenSize(StaticMeshComponent->Bounds.Origin, StaticMeshComponent->Bounds.SphereRadius, View); FNumberFormattingOptions FormatOptions; FormatOptions.MinimumFractionalDigits = 3; FormatOptions.MaximumFractionalDigits = 6; FormatOptions.MaximumIntegralDigits = 6; TextItems.Add(SStaticMeshEditorViewport::FOverlayTextItem( FText::Format(NSLOCTEXT("UnrealEd", "ScreenSize_F", "Current Screen Size: {0}"), FText::AsNumber(CurrentScreenSize, &FormatOptions)))); TextItems.Add(SStaticMeshEditorViewport::FOverlayTextItem( FText::Format(NSLOCTEXT("UnrealEd", "Triangles_F", "Triangles: {0}"), FText::AsNumber(StaticMeshEditorPtr.Pin()->GetNumTriangles(CurrentLODLevel))))); TextItems.Add(SStaticMeshEditorViewport::FOverlayTextItem( FText::Format(NSLOCTEXT("UnrealEd", "Vertices_F", "Vertices: {0}"), FText::AsNumber(StaticMeshEditorPtr.Pin()->GetNumVertices(CurrentLODLevel))))); TextItems.Add(SStaticMeshEditorViewport::FOverlayTextItem( FText::Format(NSLOCTEXT("UnrealEd", "UVChannels_F", "UV Channels: {0}"), FText::AsNumber(StaticMeshEditorPtr.Pin()->GetNumUVChannels(CurrentLODLevel))))); if( StaticMesh->RenderData->LODResources.Num() > 0 ) { if (StaticMesh->RenderData->LODResources[0].DistanceFieldData != nullptr ) { const FDistanceFieldVolumeData& VolumeData = *(StaticMesh->RenderData->LODResources[0].DistanceFieldData); if (VolumeData.Size.GetMax() > 0) { float MemoryMb = (VolumeData.Size.X * VolumeData.Size.Y * VolumeData.Size.Z * VolumeData.DistanceFieldVolume.GetTypeSize()) / (1024.0f * 1024.0f); FNumberFormattingOptions NumberOptions; NumberOptions.MinimumFractionalDigits = 2; NumberOptions.MaximumFractionalDigits = 2; if (VolumeData.bMeshWasClosed) { TextItems.Add(SStaticMeshEditorViewport::FOverlayTextItem( FText::Format(NSLOCTEXT("UnrealEd", "DistanceFieldRes_F", "Distance Field: {0}x{1}x{2} = {3}Mb"), FText::AsNumber(VolumeData.Size.X), FText::AsNumber(VolumeData.Size.Y), FText::AsNumber(VolumeData.Size.Z), FText::AsNumber(MemoryMb, &NumberOptions)))); } else { TextItems.Add(SStaticMeshEditorViewport::FOverlayTextItem( NSLOCTEXT("UnrealEd", "DistanceFieldClosed_F", "Distance Field: Mesh was not closed and material was one-sided"))); } } } } TextItems.Add(SStaticMeshEditorViewport::FOverlayTextItem( FText::Format(NSLOCTEXT("UnrealEd", "ApproxSize_F", "Approx Size: {0}x{1}x{2}"), FText::AsNumber(int32(StaticMesh->GetBounds().BoxExtent.X * 2.0f)), // x2 as artists wanted length not radius FText::AsNumber(int32(StaticMesh->GetBounds().BoxExtent.Y * 2.0f)), FText::AsNumber(int32(StaticMesh->GetBounds().BoxExtent.Z * 2.0f))))); // Show the number of collision primitives if we are drawing collision. if(bShowCollision && StaticMesh->BodySetup) { TextItems.Add(SStaticMeshEditorViewport::FOverlayTextItem( FText::Format(NSLOCTEXT("UnrealEd", "NumPrimitives_F", "Num Primitives: {0}"), FText::AsNumber(StaticMesh->BodySetup->AggGeom.GetElementCount())))); } StaticMeshEditorViewport->PopulateOverlayText(TextItems); if(bDrawUVs) { const int32 YPos = 160; DrawUVsForMesh(Viewport, &Canvas, YPos); } }
void FStaticMeshEditorViewportClient::Draw(const FSceneView* View,FPrimitiveDrawInterface* PDI) { FEditorViewportClient::Draw(View, PDI); if (bShowCollision && StaticMesh->BodySetup) { const FColor SelectedColor(149, 223, 157); const FColor UnselectedColor(157, 149, 223); // Draw bodies FKAggregateGeom* AggGeom = &StaticMesh->BodySetup->AggGeom; for (int32 i = 0; i < AggGeom->SphereElems.Num(); ++i) { HSMECollisionProxy* HitProxy = new HSMECollisionProxy(KPT_Sphere, i); PDI->SetHitProxy(HitProxy); const FColor CollisionColor = StaticMeshEditorPtr.Pin()->IsSelectedPrim(HitProxy->PrimData) ? SelectedColor : UnselectedColor; const FKSphereElem& SphereElem = AggGeom->SphereElems[i]; const FTransform ElemTM = SphereElem.GetTransform(); SphereElem.DrawElemWire(PDI, ElemTM, 1.f, CollisionColor); PDI->SetHitProxy(NULL); } for (int32 i = 0; i < AggGeom->BoxElems.Num(); ++i) { HSMECollisionProxy* HitProxy = new HSMECollisionProxy(KPT_Box, i); PDI->SetHitProxy(HitProxy); const FColor CollisionColor = StaticMeshEditorPtr.Pin()->IsSelectedPrim(HitProxy->PrimData) ? SelectedColor : UnselectedColor; const FKBoxElem& BoxElem = AggGeom->BoxElems[i]; const FTransform ElemTM = BoxElem.GetTransform(); BoxElem.DrawElemWire(PDI, ElemTM, 1.f, CollisionColor); PDI->SetHitProxy(NULL); } for (int32 i = 0; i < AggGeom->SphylElems.Num(); ++i) { HSMECollisionProxy* HitProxy = new HSMECollisionProxy(KPT_Sphyl, i); PDI->SetHitProxy(HitProxy); const FColor CollisionColor = StaticMeshEditorPtr.Pin()->IsSelectedPrim(HitProxy->PrimData) ? SelectedColor : UnselectedColor; const FKSphylElem& SphylElem = AggGeom->SphylElems[i]; const FTransform ElemTM = SphylElem.GetTransform(); SphylElem.DrawElemWire(PDI, ElemTM, 1.f, CollisionColor); PDI->SetHitProxy(NULL); } for (int32 i = 0; i < AggGeom->ConvexElems.Num(); ++i) { HSMECollisionProxy* HitProxy = new HSMECollisionProxy(KPT_Convex, i); PDI->SetHitProxy(HitProxy); const FColor CollisionColor = StaticMeshEditorPtr.Pin()->IsSelectedPrim(HitProxy->PrimData) ? SelectedColor : UnselectedColor; const FKConvexElem& ConvexElem = AggGeom->ConvexElems[i]; const FTransform ElemTM = ConvexElem.GetTransform(); ConvexElem.DrawElemWire(PDI, ElemTM, CollisionColor); PDI->SetHitProxy(NULL); } } if( bShowSockets ) { const FColor SocketColor = FColor(255, 128, 128); for(int32 i=0; i < StaticMesh->Sockets.Num(); i++) { UStaticMeshSocket* Socket = StaticMesh->Sockets[i]; if(Socket) { FMatrix SocketTM; Socket->GetSocketMatrix(SocketTM, StaticMeshComponent); PDI->SetHitProxy( new HSMESocketProxy(i) ); DrawWireDiamond(PDI, SocketTM, 5.f, SocketColor, SDPG_Foreground); PDI->SetHitProxy( NULL ); } } } // Draw any edges that are currently selected by the user if( SelectedEdgeIndices.Num() > 0 ) { for(int32 VertexIndex = 0; VertexIndex < SelectedEdgeVertices.Num(); VertexIndex += 2) { FVector EdgeVertices[ 2 ]; EdgeVertices[ 0 ] = SelectedEdgeVertices[VertexIndex]; EdgeVertices[ 1 ] = SelectedEdgeVertices[VertexIndex + 1]; PDI->DrawLine( StaticMeshComponent->ComponentToWorld.TransformPosition( EdgeVertices[ 0 ] ), StaticMeshComponent->ComponentToWorld.TransformPosition( EdgeVertices[ 1 ] ), FColor( 255, 255, 0 ), SDPG_World ); } } if( bDrawNormals || bDrawTangents || bDrawBinormals ) { FStaticMeshLODResources& LODModel = StaticMesh->RenderData->LODResources[StaticMeshEditorPtr.Pin()->GetCurrentLODIndex()]; FIndexArrayView Indices = LODModel.IndexBuffer.GetArrayView(); uint32 NumIndices = Indices.Num(); FMatrix LocalToWorldInverseTranspose = StaticMeshComponent->ComponentToWorld.ToMatrixWithScale().InverseFast().GetTransposed(); for (uint32 i = 0; i < NumIndices; i++) { const FVector& VertexPos = LODModel.PositionVertexBuffer.VertexPosition( Indices[i] ); const FVector WorldPos = StaticMeshComponent->ComponentToWorld.TransformPosition( VertexPos ); const FVector& Normal = LODModel.VertexBuffer.VertexTangentZ( Indices[i] ); const FVector& Binormal = LODModel.VertexBuffer.VertexTangentY( Indices[i] ); const FVector& Tangent = LODModel.VertexBuffer.VertexTangentX( Indices[i] ); const float Len = 5.0f; if( bDrawNormals ) { PDI->DrawLine( WorldPos, WorldPos+LocalToWorldInverseTranspose.TransformVector( Normal ).SafeNormal() * Len, FLinearColor( 0.0f, 1.0f, 0.0f), SDPG_World ); } if( bDrawTangents ) { PDI->DrawLine( WorldPos, WorldPos+LocalToWorldInverseTranspose.TransformVector( Tangent ).SafeNormal() * Len, FLinearColor( 1.0f, 0.0f, 0.0f), SDPG_World ); } if( bDrawBinormals ) { PDI->DrawLine( WorldPos, WorldPos+LocalToWorldInverseTranspose.TransformVector( Binormal ).SafeNormal() * Len, FLinearColor( 0.0f, 0.0f, 1.0f), SDPG_World ); } } } if( bShowPivot ) { FUnrealEdUtils::DrawWidget(View, PDI, StaticMeshComponent->ComponentToWorld.ToMatrixWithScale(), 0, 0, EAxisList::All, EWidgetMovementMode::WMM_Translate, false); } if( bDrawAdditionalData ) { const TArray<UAssetUserData*>* UserDataArray = StaticMesh->GetAssetUserDataArray(); if (UserDataArray != NULL) { for (int32 AdditionalDataIndex = 0; AdditionalDataIndex < UserDataArray->Num(); ++AdditionalDataIndex) { if ((*UserDataArray)[AdditionalDataIndex] != NULL) { (*UserDataArray)[AdditionalDataIndex]->Draw(PDI, View); } } } } }