示例#1
0
/** Updates GCurrentSelectedLightmapSample given a selected actor's components and the location of the click. */
void SetDebugLightmapSample(TArray<UActorComponent*>* Components, UModel* Model, int32 iSurf, FVector ClickLocation)
{
	UStaticMeshComponent* SMComponent = NULL;
	if (Components)
	{
		// Find the first supported component
		for (int32 ComponentIndex = 0; ComponentIndex < Components->Num() && !SMComponent; ComponentIndex++)
		{
			SMComponent = Cast<UStaticMeshComponent>((*Components)[ComponentIndex]);
			if (SMComponent && (!SMComponent->StaticMesh || SMComponent->LODData.Num() == 0))
			{
				SMComponent = NULL;
			}
		}
	}
	 
	bool bFoundLightmapSample = false;
	// Only static mesh components and BSP handled for now
	if (SMComponent)
	{
		UStaticMesh* StaticMesh = SMComponent->StaticMesh;
		check(StaticMesh);
		check(StaticMesh->RenderData);
		check(StaticMesh->RenderData->LODResources.Num());
		// Only supporting LOD0
		const int32 LODIndex = 0;
		FStaticMeshLODResources& LODModel = StaticMesh->RenderData->LODResources[LODIndex];
		FIndexArrayView Indices = LODModel.IndexBuffer.GetArrayView();
		const bool bHasStaticLighting = SMComponent->HasStaticLighting();
		if (bHasStaticLighting)
		{
			bool bUseTextureMap = false;
			int32 LightmapSizeX = 0;
			int32 LightmapSizeY = 0;
			SMComponent->GetLightMapResolution(LightmapSizeX, LightmapSizeY);

			if (LightmapSizeX > 0 && LightmapSizeY > 0 
				&& StaticMesh->LightMapCoordinateIndex >= 0 
				&& (uint32)StaticMesh->LightMapCoordinateIndex < LODModel.VertexBuffer.GetNumTexCoords()
				)
			{
				bUseTextureMap = true;
			}
			else
			{
				bUseTextureMap = false;
			}

			// Search through the static mesh's triangles for the one that was hit (since we can't get triangle index from a line check)
			for(int32 TriangleIndex = 0; TriangleIndex < Indices.Num(); TriangleIndex += 3)
			{
				uint32 Index0 = Indices[TriangleIndex];
				uint32 Index1 = Indices[TriangleIndex + 1];
				uint32 Index2 = Indices[TriangleIndex + 2];

				// Transform positions to world space
				FVector Position0 = SMComponent->ComponentToWorld.TransformPosition(LODModel.PositionVertexBuffer.VertexPosition(Index0));
				FVector Position1 = SMComponent->ComponentToWorld.TransformPosition(LODModel.PositionVertexBuffer.VertexPosition(Index1));
				FVector Position2 = SMComponent->ComponentToWorld.TransformPosition(LODModel.PositionVertexBuffer.VertexPosition(Index2));

				FVector BaryCentricWeights;
				// Continue if click location is in the triangle and get its barycentric weights
				if (GetBarycentricWeights(Position0, Position1, Position2, ClickLocation, .001f, BaryCentricWeights))
				{
					RestoreSelectedLightmapSample();

					if (bUseTextureMap)
					{
						// Fetch lightmap UV's
						FVector2D LightmapUV0 = LODModel.VertexBuffer.GetVertexUV(Index0, StaticMesh->LightMapCoordinateIndex);
						FVector2D LightmapUV1 = LODModel.VertexBuffer.GetVertexUV(Index1, StaticMesh->LightMapCoordinateIndex);
						FVector2D LightmapUV2 = LODModel.VertexBuffer.GetVertexUV(Index2, StaticMesh->LightMapCoordinateIndex);
						// Interpolate lightmap UV's to the click location
						FVector2D InterpolatedUV = LightmapUV0 * BaryCentricWeights.X + LightmapUV1 * BaryCentricWeights.Y + LightmapUV2 * BaryCentricWeights.Z;

						int32 PaddedSizeX = LightmapSizeX;
						int32 PaddedSizeY = LightmapSizeY;
						if (GLightmassDebugOptions.bPadMappings && GAllowLightmapPadding && LightmapSizeX - 2 > 0 && LightmapSizeY - 2 > 0)
						{
							PaddedSizeX -= 2;
							PaddedSizeY -= 2;
						}

						const int32 LocalX = FMath::TruncToInt(InterpolatedUV.X * PaddedSizeX);
						const int32 LocalY = FMath::TruncToInt(InterpolatedUV.Y * PaddedSizeY);
						if (LocalX < 0 || LocalX >= PaddedSizeX
							|| LocalY < 0 || LocalY >= PaddedSizeY)
						{
							UE_LOG(LogStaticLightingSystem, Log, TEXT("Texel selection failed because the lightmap UV's wrap!"));
						}
						else
						{
							bFoundLightmapSample = UpdateSelectedTexel(SMComponent, -1, SMComponent->LODData[LODIndex].LightMap, ClickLocation, InterpolatedUV, LocalX, LocalY, LightmapSizeX, LightmapSizeY);
						}
					}

					break;
				}
			}

			if (!bFoundLightmapSample && Indices.Num() > 0)
			{
				const int32 SelectedTriangle = FMath::RandRange(0, Indices.Num() / 3 - 1);

				uint32 Index0 = Indices[SelectedTriangle];
				uint32 Index1 = Indices[SelectedTriangle + 1];
				uint32 Index2 = Indices[SelectedTriangle + 2];

				FVector2D LightmapUV0 = LODModel.VertexBuffer.GetVertexUV(Index0, StaticMesh->LightMapCoordinateIndex);
				FVector2D LightmapUV1 = LODModel.VertexBuffer.GetVertexUV(Index1, StaticMesh->LightMapCoordinateIndex);
				FVector2D LightmapUV2 = LODModel.VertexBuffer.GetVertexUV(Index2, StaticMesh->LightMapCoordinateIndex);

				FVector BaryCentricWeights;
				BaryCentricWeights.X = FMath::FRandRange(0, 1);
				BaryCentricWeights.Y = FMath::FRandRange(0, 1);

				if (BaryCentricWeights.X + BaryCentricWeights.Y >= 1)
				{
					BaryCentricWeights.X = 1 - BaryCentricWeights.X;
					BaryCentricWeights.Y = 1 - BaryCentricWeights.Y;
				}

				BaryCentricWeights.Z = 1 - BaryCentricWeights.X - BaryCentricWeights.Y;

				FVector2D InterpolatedUV = LightmapUV0 * BaryCentricWeights.X + LightmapUV1 * BaryCentricWeights.Y + LightmapUV2 * BaryCentricWeights.Z;

				UE_LOG(LogStaticLightingSystem, Log, TEXT("Failed to intersect any triangles, picking random texel"));

				int32 PaddedSizeX = LightmapSizeX;
				int32 PaddedSizeY = LightmapSizeY;
				if (GLightmassDebugOptions.bPadMappings && GAllowLightmapPadding && LightmapSizeX - 2 > 0 && LightmapSizeY - 2 > 0)
				{
					PaddedSizeX -= 2;
					PaddedSizeY -= 2;
				}

				const int32 LocalX = FMath::TruncToInt(InterpolatedUV.X * PaddedSizeX);
				const int32 LocalY = FMath::TruncToInt(InterpolatedUV.Y * PaddedSizeY);
				if (LocalX < 0 || LocalX >= PaddedSizeX
					|| LocalY < 0 || LocalY >= PaddedSizeY)
				{
					UE_LOG(LogStaticLightingSystem, Log, TEXT("Texel selection failed because the lightmap UV's wrap!"));
				}
				else
				{
					bFoundLightmapSample = UpdateSelectedTexel(SMComponent, -1, SMComponent->LODData[LODIndex].LightMap, ClickLocation, InterpolatedUV, LocalX, LocalY, LightmapSizeX, LightmapSizeY);
				}		
			}
		}
	}
	else if (Model)
	{
		UWorld* World = Model->LightingLevel->OwningWorld;
		check( World);
		for (int32 ModelIndex = 0; ModelIndex < World->GetCurrentLevel()->ModelComponents.Num(); ModelIndex++)
		{
			UModelComponent* CurrentComponent = World->GetCurrentLevel()->ModelComponents[ModelIndex];
			int32 LightmapSizeX = 0;
			int32 LightmapSizeY = 0;
			CurrentComponent->GetLightMapResolution(LightmapSizeX, LightmapSizeY);
			if (LightmapSizeX > 0 && LightmapSizeY > 0)
			{
				for (int32 ElementIndex = 0; ElementIndex < CurrentComponent->GetElements().Num(); ElementIndex++)
				{
					FModelElement& Element = CurrentComponent->GetElements()[ElementIndex];
					TScopedPointer<FRawIndexBuffer16or32>* IndexBufferRef = Model->MaterialIndexBuffers.Find(Element.Material);
					check(IndexBufferRef);
					for(uint32 TriangleIndex = Element.FirstIndex; TriangleIndex < Element.FirstIndex + Element.NumTriangles * 3; TriangleIndex += 3)
					{
						uint32 Index0 = (*IndexBufferRef)->Indices[TriangleIndex];
						uint32 Index1 = (*IndexBufferRef)->Indices[TriangleIndex + 1];
						uint32 Index2 = (*IndexBufferRef)->Indices[TriangleIndex + 2];

						FModelVertex* ModelVertices = (FModelVertex*)Model->VertexBuffer.Vertices.GetData();
						FVector Position0 = ModelVertices[Index0].Position;
						FVector Position1 = ModelVertices[Index1].Position;
						FVector Position2 = ModelVertices[Index2].Position;

						FVector BaryCentricWeights;
						// Continue if click location is in the triangle and get its barycentric weights
						if (GetBarycentricWeights(Position0, Position1, Position2, ClickLocation, .001f, BaryCentricWeights))
						{
							RestoreSelectedLightmapSample();

							// Fetch lightmap UV's
							FVector2D LightmapUV0 = ModelVertices[Index0].ShadowTexCoord;
							FVector2D LightmapUV1 = ModelVertices[Index1].ShadowTexCoord;
							FVector2D LightmapUV2 = ModelVertices[Index2].ShadowTexCoord;
							// Interpolate lightmap UV's to the click location
							FVector2D InterpolatedUV = LightmapUV0 * BaryCentricWeights.X + LightmapUV1 * BaryCentricWeights.Y + LightmapUV2 * BaryCentricWeights.Z;

							// Find the node index belonging to the selected triangle
							const UModel* CurrentModel = CurrentComponent->GetModel();
							int32 SelectedNodeIndex = INDEX_NONE;
							for (int32 ElementNodeIndex = 0; ElementNodeIndex < Element.Nodes.Num(); ElementNodeIndex++)
							{
								const FBspNode& CurrentNode = CurrentModel->Nodes[Element.Nodes[ElementNodeIndex]];
								if ((int32)Index0 >= CurrentNode.iVertexIndex && (int32)Index0 < CurrentNode.iVertexIndex + CurrentNode.NumVertices)
								{
									SelectedNodeIndex = Element.Nodes[ElementNodeIndex];
								}
							}
							check(SelectedNodeIndex >= 0);

							TArray<ULightComponentBase*> DummyLights;

							// fill out the model's NodeGroups (not the mapping part of it, but the nodes part)
							Model->GroupAllNodes(World->GetCurrentLevel(), DummyLights);

							// Find the FGatheredSurface that the selected node got put into during the last lighting rebuild
							TArray<int32> GatheredNodes;

							// find the NodeGroup that this node went into, and get all of its node
							for (TMap<int32, FNodeGroup*>::TIterator It(Model->NodeGroups); It && GatheredNodes.Num() == 0; ++It)
							{
								FNodeGroup* NodeGroup = It.Value();
								for (int32 NodeIndex = 0; NodeIndex < NodeGroup->Nodes.Num(); NodeIndex++)
								{
									if (NodeGroup->Nodes[NodeIndex] == SelectedNodeIndex)
									{
										GatheredNodes = NodeGroup->Nodes;
										break;
									}
								}
							}
							check(GatheredNodes.Num() > 0);

							// use the surface of the selected node, it will have to suffice for the GetSurfaceLightMapResolution() call
							int32 SelectedGatheredSurfIndex = Model->Nodes[SelectedNodeIndex].iSurf;

							// Get the lightmap resolution used by the FGatheredSurface containing the selected node
							FMatrix WorldToMap;
							CurrentComponent->GetSurfaceLightMapResolution(SelectedGatheredSurfIndex, 1, LightmapSizeX, LightmapSizeY, WorldToMap, &GatheredNodes);

							int32 PaddedSizeX = LightmapSizeX;
							int32 PaddedSizeY = LightmapSizeY;
							if (GLightmassDebugOptions.bPadMappings && GAllowLightmapPadding && LightmapSizeX - 2 > 0 && LightmapSizeY - 2 > 0)
							{
								PaddedSizeX -= 2;
								PaddedSizeY -= 2;
							}
							check(LightmapSizeX > 0 && LightmapSizeY > 0);

							// Apply the transform to the intersection position to find the local texel coordinates
							const FVector4 StaticLightingTextureCoordinate = WorldToMap.TransformPosition(ClickLocation);
							const int32 LocalX = FMath::TruncToInt(StaticLightingTextureCoordinate.X * PaddedSizeX);
							const int32 LocalY = FMath::TruncToInt(StaticLightingTextureCoordinate.Y * PaddedSizeY);
							check(LocalX >= 0 && LocalX < PaddedSizeX && LocalY >= 0 && LocalY < PaddedSizeY);

							bFoundLightmapSample = UpdateSelectedTexel(
								CurrentComponent, 
								SelectedNodeIndex, 
								Element.LightMap, 
								ClickLocation, 
								InterpolatedUV, 
								LocalX, LocalY,
								LightmapSizeX, LightmapSizeY);

							if (!bFoundLightmapSample)
							{
								RestoreSelectedLightmapSample();
								GCurrentSelectedLightmapSample = FSelectedLightmapSample();
							}
							return;
						}
					}
				}
			}
		}
	}

	if (!bFoundLightmapSample)
	{
		RestoreSelectedLightmapSample();
		GCurrentSelectedLightmapSample = FSelectedLightmapSample();
	}
}
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);
				}
			}
		}
	}
}
示例#3
0
/**
 * Constructs a raw mesh from legacy render data.
 */
static void BuildRawMeshFromRenderData(
	FRawMesh& OutRawMesh,
	struct FMeshBuildSettings& OutBuildSettings,
	FLegacyStaticMeshRenderData& RenderData,
	const TCHAR* MeshName
	)
{
	FStaticMeshTriangle* RawTriangles = (FStaticMeshTriangle*)RenderData.RawTriangles.Lock(LOCK_READ_ONLY);
	bool bBuiltFromRawTriangles = BuildRawMeshFromRawTriangles(
		OutRawMesh,
		OutBuildSettings,
		RawTriangles,
		RenderData.RawTriangles.GetElementCount(),
		MeshName
		);
	RenderData.RawTriangles.Unlock();

	if (bBuiltFromRawTriangles)
	{
		return;
	}

	OutRawMesh.Empty();
	
	FIndexArrayView Indices = RenderData.IndexBuffer.GetArrayView();
	int32 NumVertices = RenderData.PositionVertexBuffer.GetNumVertices();
	int32 NumTriangles = Indices.Num() / 3;
	int32 NumWedges = NumTriangles * 3;

	// Copy vertex positions.
	{
		OutRawMesh.VertexPositions.AddUninitialized(NumVertices);
		for (int32 i = 0; i < NumVertices; ++i)
		{
			OutRawMesh.VertexPositions[i] = RenderData.PositionVertexBuffer.VertexPosition(i);
		}
	}

	// Copy per-wedge texture coordinates.
	for (uint32 TexCoordIndex = 0; TexCoordIndex < RenderData.VertexBuffer.GetNumTexCoords(); ++TexCoordIndex)
	{
		OutRawMesh.WedgeTexCoords[TexCoordIndex].AddUninitialized(NumWedges);
		for (int32 i = 0; i < NumWedges; ++i)
		{
			uint32 VertIndex = Indices[i];
			OutRawMesh.WedgeTexCoords[TexCoordIndex][i] = RenderData.VertexBuffer.GetVertexUV(VertIndex, TexCoordIndex);
		}
	}

	// Copy per-wedge colors if they exist.
	if (RenderData.ColorVertexBuffer.GetNumVertices() > 0)
	{
		OutRawMesh.WedgeColors.AddUninitialized(NumWedges);
		for (int32 i = 0; i < NumWedges; ++i)
		{
			uint32 VertIndex = Indices[i];
			OutRawMesh.WedgeColors[i] = RenderData.ColorVertexBuffer.VertexColor(VertIndex);
		}
	}

	// Copy per-wedge tangents.
	{
		OutRawMesh.WedgeTangentX.AddUninitialized(NumWedges);
		OutRawMesh.WedgeTangentY.AddUninitialized(NumWedges);
		OutRawMesh.WedgeTangentZ.AddUninitialized(NumWedges);
		for (int32 i = 0; i < NumWedges; ++i)
		{
			uint32 VertIndex = Indices[i];
			OutRawMesh.WedgeTangentX[i] = RenderData.VertexBuffer.VertexTangentX(VertIndex);
			OutRawMesh.WedgeTangentY[i] = RenderData.VertexBuffer.VertexTangentY(VertIndex);
			OutRawMesh.WedgeTangentZ[i] = RenderData.VertexBuffer.VertexTangentZ(VertIndex);
		}
	}

	// Copy per-face information.
	{
		OutRawMesh.FaceMaterialIndices.AddZeroed(NumTriangles);
		OutRawMesh.FaceSmoothingMasks.AddZeroed(NumTriangles);
		OutRawMesh.WedgeIndices.AddZeroed(NumWedges);
		for (int32 SectionIndex = 0; SectionIndex < RenderData.Elements.Num(); ++SectionIndex)
		{
			const FLegacyStaticMeshElement& Section = RenderData.Elements[SectionIndex];
			int32 FirstFace = Section.FirstIndex / 3;
			int32 LastFace = FirstFace + Section.NumTriangles;
			for (int32 i = FirstFace; i < LastFace; ++i)
			{
				OutRawMesh.FaceMaterialIndices[i] = Section.MaterialIndex;
				// Smoothing group information has been lost but is already baked in to the tangent basis.
				for (int32 j = 0; j < 3; ++j)
				{
					OutRawMesh.WedgeIndices[i * 3 + j] = Indices[i * 3 + j];
				}
			}
		}
	}

	check(OutRawMesh.IsValid());

	OutBuildSettings.bRecomputeNormals = false;
	OutBuildSettings.bRecomputeTangents = false;
	OutBuildSettings.bRemoveDegenerates = false;
	OutBuildSettings.bUseFullPrecisionUVs = RenderData.VertexBuffer.GetUseFullPrecisionUVs();
}
static void StaticMeshToSlateRenderData(const UStaticMesh& DataSource, TArray<FSlateMeshVertex>& OutSlateVerts, TArray<uint32>& OutIndexes, FVector2D& OutExtentMin, FVector2D& OutExtentMax )
{
	OutExtentMin = FVector2D(FLT_MAX, FLT_MAX);
	OutExtentMax = FVector2D(-FLT_MAX, -FLT_MAX);

	const FStaticMeshLODResources& LOD = DataSource.RenderData->LODResources[0];
	const int32 NumSections = LOD.Sections.Num();
	if (NumSections > 1)
	{
		UE_LOG(LogUMG, Warning, TEXT("StaticMesh %s has %d sections. SMeshWidget expects a static mesh with 1 section."), *DataSource.GetName(), NumSections);
	}
	else
	{
		// Populate Vertex Data
		{
			const uint32 NumVerts = LOD.PositionVertexBuffer.GetNumVertices();
			OutSlateVerts.Empty();
			OutSlateVerts.Reserve(NumVerts);

			static const int32 MAX_SUPPORTED_UV_SETS = 6;
			const int32 TexCoordsPerVertex = LOD.GetNumTexCoords();
			if (TexCoordsPerVertex > MAX_SUPPORTED_UV_SETS)
			{
				UE_LOG(LogStaticMesh, Warning, TEXT("[%s] has %d UV sets; slate vertex data supports at most %d"), *DataSource.GetName(), TexCoordsPerVertex, MAX_SUPPORTED_UV_SETS);
			}

			for (uint32 i = 0; i < NumVerts; ++i)
			{
				// Copy Position
				const FVector& Position = LOD.PositionVertexBuffer.VertexPosition(i);
				OutExtentMin.X = FMath::Min(Position.X, OutExtentMin.X);
				OutExtentMin.Y = FMath::Min(Position.Y, OutExtentMin.Y);
				OutExtentMax.X = FMath::Max(Position.X, OutExtentMax.X);
				OutExtentMax.Y = FMath::Max(Position.Y, OutExtentMax.Y);
				
				// Copy Color
				FColor Color = (LOD.ColorVertexBuffer.GetNumVertices() > 0) ? LOD.ColorVertexBuffer.VertexColor(i) : FColor::White;
				
				// Copy all the UVs that we have, and as many as we can fit.
				const FVector2D& UV0 = (TexCoordsPerVertex > 0) ? LOD.VertexBuffer.GetVertexUV(i, 0) : FVector2D(1, 1);

				const FVector2D& UV1 = (TexCoordsPerVertex > 1) ? LOD.VertexBuffer.GetVertexUV(i, 1) : FVector2D(1, 1);

				const FVector2D& UV2 = (TexCoordsPerVertex > 2) ? LOD.VertexBuffer.GetVertexUV(i, 2) : FVector2D(1, 1);

				const FVector2D& UV3 = (TexCoordsPerVertex > 3) ? LOD.VertexBuffer.GetVertexUV(i, 3) : FVector2D(1, 1);

				const FVector2D& UV4 = (TexCoordsPerVertex > 4) ? LOD.VertexBuffer.GetVertexUV(i, 4) : FVector2D(1, 1);

				const FVector2D& UV5 = (TexCoordsPerVertex > 5) ? LOD.VertexBuffer.GetVertexUV(i, 5) : FVector2D(1, 1);

				OutSlateVerts.Add(FSlateMeshVertex(
					FVector2D(Position.X, Position.Y),
					Color,
					UV0,
					UV1,
					UV2,
					UV3,
					UV4,
					UV5
				));
			}
		}

		// Populate Index data
		{
			FIndexArrayView SourceIndexes = LOD.IndexBuffer.GetArrayView();
			const int32 NumIndexes = SourceIndexes.Num();
			OutIndexes.Empty();
			OutIndexes.Reserve(NumIndexes);
			for (int32 i = 0; i < NumIndexes; ++i)
			{
				OutIndexes.Add(SourceIndexes[i]);
			}


			// Sort the index buffer such that verts are drawn in Z-order.
			// Assume that all triangles are coplanar with Z == SomeValue.
			ensure(NumIndexes % 3 == 0);
			for (int32 a = 0; a < NumIndexes; a += 3)
			{
				for (int32 b = 0; b < NumIndexes; b += 3)
				{
					const float VertADepth = LOD.PositionVertexBuffer.VertexPosition(OutIndexes[a]).Z;
					const float VertBDepth = LOD.PositionVertexBuffer.VertexPosition(OutIndexes[b]).Z;
					if ( VertADepth < VertBDepth )
					{
						// Swap the order in which triangles will be drawn
						Swap(OutIndexes[a + 0], OutIndexes[b + 0]);
						Swap(OutIndexes[a + 1], OutIndexes[b + 1]);
						Swap(OutIndexes[a + 2], OutIndexes[b + 2]);
					}
				}
			}
		}
	}
}