Beispiel #1
0
/**
 * Creates a static lighting vertex to represent the given static mesh vertex.
 * @param VertexBuffer - The static mesh's vertex buffer.
 * @param VertexIndex - The index of the static mesh vertex to access.
 * @param OutVertex - Upon return, contains a static lighting vertex representing the specified static mesh vertex.
 */
static void GetStaticLightingVertex(
	const FPositionVertexBuffer& PositionVertexBuffer,
	const FStaticMeshVertexBuffer& VertexBuffer,
	uint32 VertexIndex,
	const FMatrix& LocalToWorld,
	const FMatrix& LocalToWorldInverseTranspose,
	FStaticLightingVertex& OutVertex
	)
{
	OutVertex.WorldPosition = LocalToWorld.TransformPosition(PositionVertexBuffer.VertexPosition(VertexIndex));
	OutVertex.WorldTangentX = LocalToWorld.TransformVector(VertexBuffer.VertexTangentX(VertexIndex)).GetSafeNormal();
	OutVertex.WorldTangentY = LocalToWorld.TransformVector(VertexBuffer.VertexTangentY(VertexIndex)).GetSafeNormal();
	OutVertex.WorldTangentZ = LocalToWorldInverseTranspose.TransformVector(VertexBuffer.VertexTangentZ(VertexIndex)).GetSafeNormal();

	checkSlow(VertexBuffer.GetNumTexCoords() <= ARRAY_COUNT(OutVertex.TextureCoordinates));
	for(uint32 LightmapTextureCoordinateIndex = 0;LightmapTextureCoordinateIndex < VertexBuffer.GetNumTexCoords();LightmapTextureCoordinateIndex++)
	{
		OutVertex.TextureCoordinates[LightmapTextureCoordinateIndex] = VertexBuffer.GetVertexUV(VertexIndex,LightmapTextureCoordinateIndex);
	}
}
void RemapPaintedVertexColors(
	const TArray<FPaintedVertex>& InPaintedVertices,
	const FColorVertexBuffer& InOverrideColors,
	const FPositionVertexBuffer& NewPositions,
	const FStaticMeshVertexBuffer* OptionalVertexBuffer,
	TArray<FColor>& OutOverrideColors
	)
{

	// Local copy of painted vertices we can scratch on.
	TArray<FPaintedVertex> PaintedVertices(InPaintedVertices);

	// Find the extents formed by the cached vertex positions in order to optimize the octree used later
	FVector MinExtents( PaintedVertices[ 0 ].Position );
	FVector MaxExtents( PaintedVertices[ 0 ].Position );

	for (int32 VertIndex = 0; VertIndex < PaintedVertices.Num(); ++VertIndex)
	{
		FVector& CurVector = PaintedVertices[ VertIndex ].Position;

		MinExtents.X = FMath::Min<float>( MinExtents.X, CurVector.X );
		MinExtents.Y = FMath::Min<float>( MinExtents.Y, CurVector.Y );
		MinExtents.Z = FMath::Min<float>( MinExtents.Z, CurVector.Z );

		MaxExtents.X = FMath::Max<float>( MaxExtents.X, CurVector.X );
		MaxExtents.Y = FMath::Max<float>( MaxExtents.Y, CurVector.Y );
		MaxExtents.Z = FMath::Max<float>( MaxExtents.Z, CurVector.Z );
	}

	// Create an octree which spans the extreme extents of the old and new vertex positions in order to quickly query for the colors
	// of the new vertex positions
	for (int32 VertIndex = 0; VertIndex < (int32)NewPositions.GetNumVertices(); ++VertIndex)
	{
		FVector CurVector = NewPositions.VertexPosition(VertIndex);

		MinExtents.X = FMath::Min<float>( MinExtents.X, CurVector.X );
		MinExtents.Y = FMath::Min<float>( MinExtents.Y, CurVector.Y );
		MinExtents.Z = FMath::Min<float>( MinExtents.Z, CurVector.Z );

		MaxExtents.X = FMath::Max<float>( MaxExtents.X, CurVector.X );
		MaxExtents.Y = FMath::Max<float>( MaxExtents.Y, CurVector.Y );
		MaxExtents.Z = FMath::Max<float>( MaxExtents.Z, CurVector.Z );
	}

	FBox Bounds( MinExtents, MaxExtents );
	TSMCVertPosOctree VertPosOctree( Bounds.GetCenter(), Bounds.GetExtent().GetMax() );

	// Add each old vertex to the octree
	for ( int32 PaintedVertexIndex = 0; PaintedVertexIndex < PaintedVertices.Num(); ++PaintedVertexIndex )
	{
		VertPosOctree.AddElement( PaintedVertices[ PaintedVertexIndex ] );
	}


	// Iterate over each new vertex position, attempting to find the old vertex it is closest to, applying
	// the color of the old vertex to the new position if possible.
	OutOverrideColors.Empty(NewPositions.GetNumVertices());
	const float DistanceOverNormalThreshold = OptionalVertexBuffer ? KINDA_SMALL_NUMBER : 0.0f;
	for ( uint32 NewVertIndex = 0; NewVertIndex < NewPositions.GetNumVertices(); ++NewVertIndex )
	{
		TArray<FPaintedVertex> PointsToConsider;
		TSMCVertPosOctree::TConstIterator<> OctreeIter( VertPosOctree );
		const FVector& CurPosition = NewPositions.VertexPosition( NewVertIndex );
		FVector CurNormal = FVector::ZeroVector;
		if (OptionalVertexBuffer)
		{
			CurNormal = OptionalVertexBuffer->VertexTangentZ( NewVertIndex );
		}

		// Iterate through the octree attempting to find the vertices closest to the current new point
		while ( OctreeIter.HasPendingNodes() )
		{
			const TSMCVertPosOctree::FNode& CurNode = OctreeIter.GetCurrentNode();
			const FOctreeNodeContext& CurContext = OctreeIter.GetCurrentContext();

			// Find the child of the current node, if any, that contains the current new point
			FOctreeChildNodeRef ChildRef = CurContext.GetContainingChild( FBoxCenterAndExtent( CurPosition, FVector::ZeroVector ) );

			if ( !ChildRef.IsNULL() )
			{
				const TSMCVertPosOctree::FNode* ChildNode = CurNode.GetChild( ChildRef );

				// If the specified child node exists and contains any of the old vertices, push it to the iterator for future consideration
				if ( ChildNode && ChildNode->GetInclusiveElementCount() > 0 )
				{
					OctreeIter.PushChild( ChildRef );
				}
				// If the child node doesn't have any of the old vertices in it, it's not worth pursuing any further. In an attempt to find
				// anything to match vs. the new point, add all of the children of the current octree node that have old points in them to the
				// iterator for future consideration.
				else
				{
					FOREACH_OCTREE_CHILD_NODE( ChildRef )
					{
						if( CurNode.HasChild( ChildRef ) && CurNode.GetChild( ChildRef )->GetInclusiveElementCount() > 0 )
						{
							OctreeIter.PushChild( ChildRef );
						}
					}
				}
			}

			// Add all of the elements in the current node to the list of points to consider for closest point calculations
			PointsToConsider.Append( CurNode.GetElements() );
			OctreeIter.Advance();
		}

		// If any points to consider were found, iterate over each and find which one is the closest to the new point 
		if ( PointsToConsider.Num() > 0 )
		{
			FPaintedVertex BestVertex = PointsToConsider[0];
			float BestDistanceSquared = ( BestVertex.Position - CurPosition ).SizeSquared();
			float BestNormalDot = FVector( BestVertex.Normal ) | CurNormal;

			for ( int32 ConsiderationIndex = 1; ConsiderationIndex < PointsToConsider.Num(); ++ConsiderationIndex )
			{
				FPaintedVertex& Vertex = PointsToConsider[ ConsiderationIndex ];
				const float DistSqrd = ( Vertex.Position - CurPosition ).SizeSquared();
				const float NormalDot = FVector( Vertex.Normal ) | CurNormal;
				if ( DistSqrd < BestDistanceSquared - DistanceOverNormalThreshold )
				{
					BestVertex = Vertex;
					BestDistanceSquared = DistSqrd;
					BestNormalDot = NormalDot;
				}
				else if ( OptionalVertexBuffer && DistSqrd < BestDistanceSquared + DistanceOverNormalThreshold && NormalDot > BestNormalDot )
				{
					BestVertex = Vertex;
					BestDistanceSquared = DistSqrd;
					BestNormalDot = NormalDot;
				}
			}

			OutOverrideColors.Add(BestVertex.Color);
		}
	}
}