void FLightmapCustomNodeBuilder::RefreshLightmapItems()
{
	LightmapItems.Empty();

	FWorldContext& Context = GEditor->GetEditorWorldContext();
	UWorld* World = Context.World();
	if ( World )
	{
		TArray<UTexture2D*> LightMapsAndShadowMaps;
		World->GetLightMapsAndShadowMaps(World->GetCurrentLevel(), LightMapsAndShadowMaps);

		for ( auto ObjIt = LightMapsAndShadowMaps.CreateConstIterator(); ObjIt; ++ObjIt )
		{
			UTexture2D* CurrentObject = *ObjIt;
			if (CurrentObject)
			{
				FAssetData AssetData = FAssetData(CurrentObject);
				const uint32 ThumbnailResolution = 64;
				TSharedPtr<FAssetThumbnail> LightMapThumbnail = MakeShareable( new FAssetThumbnail( AssetData, ThumbnailResolution, ThumbnailResolution, ThumbnailPool ) );
				TSharedPtr<FLightmapItem> NewItem = MakeShareable( new FLightmapItem(CurrentObject->GetPathName(), LightMapThumbnail) );
				LightmapItems.Add(NewItem);
			}
		}
	}

	if ( LightmapListView.IsValid() )
	{
		LightmapListView->RequestListRefresh();
	}
}
bool FLightPointLightSetLocation::RunTest(const FString& Parameters)
{
	//** SETUP **//
	// Create a new level.
	UWorld* World = AutomationEditorCommonUtils::CreateNewMap();
	ULevel* CurrentLevel = World->GetCurrentLevel();
	// Light Setup
	APointLight* PointLight = nullptr;
	const FTransform Transform;

	if (!LightingTestHelpers::DoesActorExistInTheLevel(CurrentLevel, TEXT("PointLight"), APointLight::StaticClass()))
	{
		//** TEST **//
		// Add a point light to the level.
		PointLight = Cast<APointLight>(GEditor->AddActor(World->GetCurrentLevel(), APointLight::StaticClass(), Transform));
		PointLight->SetActorLocation(POINT_LIGHT_UPDATED_LOCATION);

		//** VERIFY **//
		FVector CurrentLocation;
		LightingTestHelpers::GetActorCurrentLocation(CurrentLevel, PointLight->GetName(), CurrentLocation);

		TestEqual<FVector>(TEXT("The point light is not in correct location"), POINT_LIGHT_UPDATED_LOCATION, CurrentLocation);
		return true;
	}

	AddError(TEXT("A point light already exists in this level which will block the verification of a new point light."));
	return false;
}
bool FLightingPromotionModifyProperties::RunTest(const FString& Parameters)
{
	//** SETUP **//
	UWorld* World = AutomationEditorCommonUtils::CreateNewMap();
	ULevel* CurrentLevel = World->GetCurrentLevel();
	// Test Summary
	AddLogItem(TEXT("The properties values for a point light are modified.\n- Intensity is set to 1000.\n- Color is set to R=0,G=0,B=255.\n- Attenuation Radius is set to 1024."));

	if (!LightingTestHelpers::DoesActorExistInTheLevel(CurrentLevel, TEXT("PointLight"), APointLight::StaticClass()))
	{
		//** TEST **//
		// Add a point light to the level.
		APointLight* PointLight = Cast<APointLight>(GEditor->AddActor(World->GetCurrentLevel(), APointLight::StaticClass(), FTransform()));
		// Modify the Lights Intensity, Light Color, and Attenuation Radius using it's properties.
		LightingTestHelpers::SetPropertyByName(PointLight->PointLightComponent, TEXT("Intensity"), TEXT("1000.f"));
		LightingTestHelpers::SetPropertyByName(PointLight->PointLightComponent, TEXT("LightColor"), TEXT("(R=0,G=0,B=255)"));
		LightingTestHelpers::SetPropertyByName(PointLight->PointLightComponent, TEXT("AttenuationRadius"), TEXT("1024.f"));

		//** VERIFY **//
		TestEqual<float>(TEXT("Light brightness property was not modified."), 1000.f, PointLight->PointLightComponent->Intensity);
		TestEqual<FColor>(TEXT("Light color property was not modified."), FColor(0,0,255), PointLight->PointLightComponent->LightColor);
		TestEqual<float>(TEXT("Light attenuation radius was not modified."), 1024.f, PointLight->PointLightComponent->AttenuationRadius);

		return true;
	}

	AddError(TEXT("A point light already exists in this level which will block the verification of a new point light."));
	return false;
}
bool FLightingPromotionDuplicationTest::RunTest(const FString& Parameters)
{
	//** SETUP **//
	UWorld* World = AutomationEditorCommonUtils::CreateNewMap();
	ULevel* CurrentLevel = World->GetCurrentLevel();
	// Test Summary
	AddLogItem(TEXT("Duplicate and Copy Paste\n- Duplicates a point light.\n- Copies and Pastes a point light."));

	if (!LightingTestHelpers::DoesActorExistInTheLevel(CurrentLevel, TEXT("PointLight"), APointLight::StaticClass()))
	{
		//** TEST **//
		// Add a point light to the level.
		APointLight* PointLight = Cast<APointLight>(GEditor->AddActor(World->GetCurrentLevel(), APointLight::StaticClass(), FTransform()));
		// Deselect all and then Select the light
		LightingTestHelpers::SelectActorInLevel(PointLight);
		// Copy and Paste.
		GEngine->Exec(World, TEXT("EDIT COPY"));
		GEngine->Exec(World, TEXT("EDIT PASTE"));
		// Deselect all and then select a light
		LightingTestHelpers::SelectActorInLevel(PointLight);
		// Duplicate the light
		GEngine->Exec(World, TEXT("DUPLICATE"));

		//** Verify **//
		int32 NumberOfPointLights = 0;
		// Count the number of point lights in the level.
		for (TObjectIterator<APointLight> It; It; ++It)
		{
			NumberOfPointLights++;
		}
		
		// We are expecting three point lights to be in the level now.
		TestEqual<int32>(TEXT("After duplicating a light the total number of them in the level is not correct."), 3, NumberOfPointLights);

		return true;
	}

	AddError(TEXT("A point light already exists in this level which would dirty the test results."));
	return false;
}
void FScriptExecutionInstance::RefreshPIEInstance() const
{
	if (!bPIEInstanceDestroyed)
	{
		const FWorldContext* PIEWorldContext = GEditor->GetPIEWorldContext();
		UWorld* PIEWorld = PIEWorldContext ? PIEWorldContext->World() : nullptr;
		ULevel* CurrentLevel = PIEWorld ? PIEWorld->GetCurrentLevel() : nullptr;
		if (CurrentLevel && ObservedObject.IsValid())
		{
			PIEInstance = FindObject<UObject>(CurrentLevel, *ObservedObject.Get()->GetName());
		}
	}
}
bool FLightingPromotionPointLightPlaceRotScaleTest::RunTest(const FString& Parameters)
{
	//** SETUP **//
	// Create the world.
	UWorld* World = AutomationEditorCommonUtils::CreateNewMap();
	ULevel* CurrentLevel = World->GetCurrentLevel();
	// Test Summary
	AddLogItem(TEXT("Place, Scale, and Rotate.\n- A Point light is placed into the world.\n- The light is moved.\n- The light is rotated.\n- The light is scaled up."));

	if (!LightingTestHelpers::DoesActorExistInTheLevel(CurrentLevel, TEXT("PointLight"), APointLight::StaticClass()))
	{
		//** TEST **//
		// Add a point light to the level.
		APointLight* PointLight = Cast<APointLight>(GEditor->AddActor(World->GetCurrentLevel(), APointLight::StaticClass(), FTransform()));
		// Set the actors location, rotation, and scale3D.
		PointLight->SetActorLocation(POINT_LIGHT_UPDATED_LOCATION);
		PointLight->SetActorRotation(POINT_LIGHT_UPDATED_ROTATION);
		PointLight->SetActorScale3D(POINT_LIGHT_UPDATED_SCALE3D);

		//** VERIFY **//
		FVector CurrentLocation;
		LightingTestHelpers::GetActorCurrentLocation(CurrentLevel, PointLight->GetName(), CurrentLocation);
		FRotator CurrentRotation;
		LightingTestHelpers::GetActorCurrentRotation(CurrentLevel, PointLight->GetName(), CurrentRotation);
		FVector CurrentScale3D;
		LightingTestHelpers::GetActorCurrentScale3D(CurrentLevel, PointLight->GetName(), CurrentScale3D);
		bool RotationsAreEqual = CurrentRotation.Equals(POINT_LIGHT_UPDATED_ROTATION, 1);

		TestTrue(TEXT("The placed point light was not found."), LightingTestHelpers::DoesActorExistInTheLevel(CurrentLevel, PointLight->GetName(), PointLight->GetClass()));
		TestEqual<FVector>(TEXT("The point light is not in correct location"), POINT_LIGHT_UPDATED_LOCATION, CurrentLocation);
		TestTrue(TEXT("The point light is not rotated correctly."), RotationsAreEqual);
		TestEqual<FVector>(TEXT("The point light is not scaled correctly."), POINT_LIGHT_UPDATED_SCALE3D, CurrentScale3D);

		return true;
	}

	AddError(TEXT("A point light already exists in this level which will block the verification of a new point light."));
	return false;
}
bool FSaveLevelCommand::Update()
{
	if (!GUnrealEd->IsLightingBuildCurrentlyExporting() && !GUnrealEd->IsLightingBuildCurrentlyRunning())
	{
		UWorld* World = GEditor->GetEditorWorldContext().World();
		ULevel* Level = World->GetCurrentLevel();
		MapName += TEXT("_Copy.umap");
		FString TempMapLocation = FPaths::Combine(*FPaths::GameContentDir(), TEXT("Maps"), TEXT("Automation_TEMP"), *MapName);
		FEditorFileUtils::SaveLevel(Level, TempMapLocation);

		return true;
	}
	return false;
}
bool FLightPointLightPlacement::RunTest(const FString& Parameters)
{
	//** SETUP **//
	// Create a new level.
	UWorld* World = AutomationEditorCommonUtils::CreateNewMap();
	ULevel* CurrentLevel = World->GetCurrentLevel();
	// Light Setup
	APointLight* PointLight = nullptr;
	const FTransform Transform;
	
	if (!LightingTestHelpers::DoesActorExistInTheLevel(CurrentLevel, TEXT("PointLight"), APointLight::StaticClass()))
	{
		//** TEST **//
		// Add a point light to the level.
		PointLight = Cast<APointLight>(GEditor->AddActor(World->GetCurrentLevel(), APointLight::StaticClass(), Transform));

		//** VERIFY **//
		TestTrue(TEXT("The placed point light was not found."), LightingTestHelpers::DoesActorExistInTheLevel(CurrentLevel, PointLight->GetName(), PointLight->GetClass()));
		return true;
	}

	AddError(TEXT("A point light already exists in this level which will block the verification of a new point light."));
	return false;
}
Example #9
0
void UUnrealEdEngine::ConvertMatinees()
{
	FVector StartLocation= FVector::ZeroVector;
	UWorld* World = GWorld;
	if( World )
	{
		ULevel* Level = World->GetCurrentLevel();
		if( !Level )
		{
			Level = World->PersistentLevel;
		}
		check(Level);
		for( TObjectIterator<UInterpData> It; It; ++It )
		{
			UInterpData* InterpData = *It;
			if( InterpData->IsIn( Level ) ) 
			{
				// We dont care about renaming references or adding redirectors.  References to this will be old seqact_interps
				GEditor->RenameObject( InterpData, Level->GetOutermost(), *InterpData->GetName() );

				AMatineeActor* MatineeActor = Level->OwningWorld->SpawnActor<AMatineeActor>(StartLocation, FRotator::ZeroRotator);
				StartLocation.Y += 50;
								
				MatineeActor->MatineeData = InterpData;
				UProperty* MatineeDataProp = NULL;
				for( UProperty* Property = MatineeActor->GetClass()->PropertyLink; Property != NULL; Property = Property->PropertyLinkNext )
				{
					if( Property->GetName() == TEXT("MatineeData") )
					{
						MatineeDataProp = Property;
						break;
					}
				}

				FPropertyChangedEvent PropertyChangedEvent( MatineeDataProp ); 
				MatineeActor->PostEditChangeProperty( PropertyChangedEvent );
			}
		}
	}

}
Example #10
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();
	}
}