Exemplo n.º 1
0
void FogWorker::FloodFill(int32 x, int32 y)
{
    if(x < 0 || x >= TextureSize || y < 0 || y >= TextureSize)
    {
        return;
    }

    // Wikipedia
    // Flood-fill (node, target-color, replacement-color):
    // 1. If target - color is equal to replacement - color, return.
    // 2. If color of node is not equal to target - color, return.
    if(FMath::IsNearlyEqual(UnfoggedData[x + y * TextureSize], 1.0f))
    {
        return;
    }
    // 3. Set Q to the empty queue.
    TQueue<FIntVector> Q;
    // 4. Add node to Q.
    Q.Enqueue(FIntVector(x, y, 0));

    FIntVector N;
    // 5. For each element N of Q :
    while(Q.Dequeue(N))
    {
        // 6. Set w and e equal to N.
        auto w = N, e = N;
        // 7. Move w to the west until the color of the node to the west of w no longer matches target - color.
        while(w.X - 1 > 0 && !FMath::IsNearlyEqual(UnfoggedData[w.X - 1 + w.Y * TextureSize], 1.0f))
        {
            w.X--;
        }
        // 8. Move e to the east until the color of the node to the east of e no longer matches target - color.
        while(e.X + 1 < TextureSize && !FMath::IsNearlyEqual(UnfoggedData[e.X + 1 + e.Y * TextureSize], 1.0f))
        {
            e.X++;
        }
        // 9. For each node n between w and e :
        for(auto i = w.X; i <= e.X; ++i)
        {
            FIntVector n(i, N.Y, 0);
            // 10. Set the color of n to replacement - color.
            UnfoggedData[n.X + n.Y * TextureSize] = 1.0f;
            // 11. If the color of the node to the north of n is target - color, add that node to Q.
            if(n.Y + 1 < TextureSize && !FMath::IsNearlyEqual(UnfoggedData[n.X + (n.Y + 1) * TextureSize], 1.0f))
                Q.Enqueue(FIntVector(n.X, n.Y + 1, 0));
            // 12. If the color of the node to the south of n is target - color, add that node to Q.
            if(n.Y - 1 > 0 && !FMath::IsNearlyEqual(UnfoggedData[n.X + (n.Y - 1) * TextureSize], 1.0f))
            {
                Q.Enqueue(FIntVector(n.X, n.Y - 1, 0));
            }
        }
        // 13. Continue looping until Q is exhausted.
    }
    // 14. Return.
}
FIntVector UWorldComposition::GetLevelOffset(ULevel* InLevel) const
{
	UWorld* OwningWorld = GetWorld();
	UPackage* LevelPackage = Cast<UPackage>(InLevel->GetOutermost());
	
	FIntVector LevelPosition = FIntVector::ZeroValue;
	if (LevelPackage->WorldTileInfo)
	{
		FIntPoint AbsolutePosition = LevelPackage->WorldTileInfo->AbsolutePosition;
		LevelPosition = FIntVector(AbsolutePosition.X, AbsolutePosition.Y, 0);
	}
	
	return LevelPosition - OwningWorld->OriginLocation;
}
bool FIndirectLightingCache::AllocateBlock(int32 Size, FIntVector& OutMin)
{
	if (Size == 1)
	{
		// Assign a min that won't overlap with any of the samples allocated from the volume texture, so we can be added to VolumeBlocks without collisions
		// This min is not used for anything else for point samples
		OutMin = FIntVector(NextPointId, 0, 0);
		NextPointId++;
		// Point samples don't go through the volume texture, allocation always succeeds
		return true;
	}
	else
	{
		return BlockAllocator.AddElement((uint32&)OutMin.X, (uint32&)OutMin.Y, (uint32&)OutMin.Z, Size, Size, Size);
	}
}
void UWorldComposition::EvaluateWorldOriginLocation(const FVector& ViewLocation)
{
	UWorld* OwningWorld = GetWorld();
	
	FVector Location = ViewLocation;

	if (!bRebaseOriginIn3DSpace)
	{
		// Consider only XY plane
		Location.Z = 0.f;
	}
		
	// Request to shift world in case current view is quite far from current origin
	if (Location.SizeSquared() > FMath::Square(RebaseOriginDistance))
	{
		OwningWorld->RequestNewWorldOrigin(FIntVector(Location.X, Location.Y, Location.Z) + OwningWorld->OriginLocation);
	}
}
Exemplo n.º 5
0
void UCheatManager::SetWorldOrigin()
{
	UWorld* World = GetWorld();
	check(World);

	APlayerController* const MyPlayerController = GetOuterAPlayerController();

	FVector ViewLocation;
	FRotator ViewRotation;
	MyPlayerController->GetPlayerViewPoint( ViewLocation, ViewRotation );
	if( MyPlayerController->GetPawn() != NULL )
	{
		ViewLocation = MyPlayerController->GetPawn()->GetActorLocation();
	}
	
	// Consider only XY plane
	ViewLocation.Z = 0;

	FIntVector NewOrigin = FIntVector(ViewLocation.X, ViewLocation.Y, ViewLocation.Z) + World->OriginLocation;
	World->RequestNewWorldOrigin(NewOrigin);
}
Exemplo n.º 6
0
bool UVoxelComponent::IsUnbeheldVolume(const FIntVector& InVector) const
{
	static const TArray<FIntVector> Direction = TArrayBuilder<FIntVector>()
		.Add(FIntVector(+0, +0, +1))	// Up
		.Add(FIntVector(+0, +0, -1))	// Down
		.Add(FIntVector(+1, +0, +0))	// Forward
		.Add(FIntVector(-1, +0, +0))	// Backward
		.Add(FIntVector(+0, +1, +0))	// Right
		.Add(FIntVector(+0, -1, +0));	// Left
	int count = 0;
	for (int i = 0; i < Direction.Num(); ++i) {
		if (INDEX_NONE != Voxel->Voxel.IndexOfByKey(InVector + Direction[i])) {
			++count;
		}
	}
	return Direction.Num() == count;
}
void FIndirectLightingCache::InterpolateBlock(
	FScene* Scene, 
	const FIndirectLightingCacheBlock& Block, 
	TArray<float>& AccumulatedWeight, 
	TArray<FSHVectorRGB2>& AccumulatedIncidentRadiance)
{
	const FBoxCenterAndExtent BlockBoundingBox(Block.Min + Block.Size / 2, Block.Size / 2);
	const FVector HalfTexelWorldOffset = BlockBoundingBox.Extent / FVector(Block.TexelSize);	

	if (GCacheLimitQuerySize && Block.TexelSize > 2)
	{
		for (int32 VolumeIndex = 0; VolumeIndex < Scene->PrecomputedLightVolumes.Num(); VolumeIndex++)
		{
			const FPrecomputedLightVolume* PrecomputedLightVolume = Scene->PrecomputedLightVolumes[VolumeIndex];

			// Compute the target query size
			// We will try to split up the allocation into groups that are smaller than this before querying the octree
			// This prevents very large objects from finding all the samples in the level in their octree search
			const float WorldTargetSize = PrecomputedLightVolume->GetNodeLevelExtent(GCacheQueryNodeLevel) * 2;

			const FVector WorldCellSize = Block.Size / FVector(Block.TexelSize);

			// Number of cells to increment by for query blocks
			FIntVector NumStepCells;
			NumStepCells.X = FMath::Max(1, FMath::FloorToInt(WorldTargetSize / WorldCellSize.X));
			NumStepCells.Y = FMath::Max(1, FMath::FloorToInt(WorldTargetSize / WorldCellSize.Y));
			NumStepCells.Z = FMath::Max(1, FMath::FloorToInt(WorldTargetSize / WorldCellSize.Z));
			FIntVector NumQueryStepCells(0, 0, 0);

			// World space size to increment by for query blocks
			const FVector WorldStepSize = FVector(NumStepCells) * WorldCellSize;
			FVector QueryWorldStepSize(0, 0, 0);

			check(NumStepCells.X > 0 && NumStepCells.Y > 0 && NumStepCells.Z > 0);

			// This will track the position in cells of the query block being built
			FIntVector CellIndex(0, 0, 0);

			// This will track the min world position of the query block being built
			FVector MinPosition = Block.Min;

			for (MinPosition.Z = Block.Min.Z, CellIndex.Z = 0; 
				CellIndex.Z < Block.TexelSize;
				MinPosition.Z += WorldStepSize.Z, CellIndex.Z += NumStepCells.Z)
			{
				QueryWorldStepSize.Z = WorldStepSize.Z;
				NumQueryStepCells.Z = NumStepCells.Z;

				// If this is the last query block in this dimension, adjust both the world space and cell sizes to match
				if (CellIndex.Z + NumStepCells.Z > Block.TexelSize)
				{
					QueryWorldStepSize.Z = Block.Min.Z + Block.Size.Z - MinPosition.Z;
					NumQueryStepCells.Z = Block.TexelSize - CellIndex.Z;
				}

				for (MinPosition.Y = Block.Min.Y, CellIndex.Y = 0; 
					CellIndex.Y < Block.TexelSize;
					MinPosition.Y += WorldStepSize.Y, CellIndex.Y += NumStepCells.Y)
				{
					QueryWorldStepSize.Y = WorldStepSize.Y;
					NumQueryStepCells.Y = NumStepCells.Y;

					if (CellIndex.Y + NumStepCells.Y > Block.TexelSize)
					{
						QueryWorldStepSize.Y = Block.Min.Y + Block.Size.Y - MinPosition.Y;
						NumQueryStepCells.Y = Block.TexelSize - CellIndex.Y;
					}

					for (MinPosition.X = Block.Min.X, CellIndex.X = 0; 
						CellIndex.X < Block.TexelSize;
						MinPosition.X += WorldStepSize.X, CellIndex.X += NumStepCells.X)
					{
						QueryWorldStepSize.X = WorldStepSize.X;
						NumQueryStepCells.X = NumStepCells.X;

						if (CellIndex.X + NumStepCells.X > Block.TexelSize)
						{
							QueryWorldStepSize.X = Block.Min.X + Block.Size.X - MinPosition.X;
							NumQueryStepCells.X = Block.TexelSize - CellIndex.X;
						}

						FVector BoxExtent = QueryWorldStepSize / 2;
						// Use a 0 query extent in dimensions that only have one cell, these become point queries
						BoxExtent.X = NumQueryStepCells.X == 1 ? 0 : BoxExtent.X;
						BoxExtent.Y = NumQueryStepCells.Y == 1 ? 0 : BoxExtent.Y;
						BoxExtent.Z = NumQueryStepCells.Z == 1 ? 0 : BoxExtent.Z;

						// Build a bounding box for the query block
						const FBoxCenterAndExtent BoundingBox(MinPosition + BoxExtent + HalfTexelWorldOffset, BoxExtent);

						checkSlow(CellIndex.X < Block.TexelSize && CellIndex.Y < Block.TexelSize && CellIndex.Z < Block.TexelSize);
						checkSlow(CellIndex.X + NumQueryStepCells.X <= Block.TexelSize
							&& CellIndex.Y + NumQueryStepCells.Y <= Block.TexelSize
							&& CellIndex.Z + NumQueryStepCells.Z <= Block.TexelSize);

						// Interpolate from the SH volume lighting samples that Lightmass computed
						PrecomputedLightVolume->InterpolateIncidentRadianceBlock(
							BoundingBox,
							NumQueryStepCells,
							FIntVector(Block.TexelSize),
							CellIndex,
							AccumulatedWeight,
							AccumulatedIncidentRadiance);
					}
				}
			}
		}
	}
	else
	{
		for (int32 VolumeIndex = 0; VolumeIndex < Scene->PrecomputedLightVolumes.Num(); VolumeIndex++)
		{
			const FPrecomputedLightVolume* PrecomputedLightVolume = Scene->PrecomputedLightVolumes[VolumeIndex];
			check(PrecomputedLightVolume);
			check(PrecomputedLightVolume->IsUsingHighQualityLightMap() == AllowHighQualityLightmaps(Scene->GetFeatureLevel()));
			// Interpolate from the SH volume lighting samples that Lightmass computed
			// Query using the bounds of all the samples in this block
			// There will be a performance cliff for large objects which end up intersecting with the entire octree
			PrecomputedLightVolume->InterpolateIncidentRadianceBlock(
				FBoxCenterAndExtent(BlockBoundingBox.Center + HalfTexelWorldOffset, BlockBoundingBox.Extent), 
				FIntVector(Block.TexelSize), 
				FIntVector(Block.TexelSize), 
				FIntVector(0), 
				AccumulatedWeight, 
				AccumulatedIncidentRadiance);
		}
	}	
}