BSP

BSP

#Overview

name: BSP

This variable is created as a Console Variable (cvar).

It is referenced in 13 C++ source files.

#Summary

#Usage in the C++ source code

The purpose of BSP is to control the visibility and rendering of Binary Space Partitioning (BSP) geometry in Unreal Engine. BSP is a technique used for spatial partitioning and visibility determination, particularly in level design and rendering.

BSP is primarily used in the rendering system of Unreal Engine. Based on the callsites, it’s evident that the Engine’s rendering, editor, and level editing subsystems rely on this variable.

The value of this variable is typically set through the engine’s show flags system. It can be toggled on or off in the editor viewport or through code by modifying the EngineShowFlags.

Several other variables interact with BSP:

  1. EngineShowFlags.Brushes: Often used in conjunction with BSP for rendering brush geometry.
  2. EngineShowFlags.BSPTriangles: Controls the rendering of BSP triangles.

Developers should be aware of the following when using this variable:

  1. BSP visibility affects both editor and game views.
  2. It impacts performance, especially in complex scenes with many BSP elements.
  3. In collision views, BSP visibility might be overridden.

Best practices when using this variable include:

  1. Use it judiciously in performance-critical scenarios.
  2. Consider its interaction with other show flags, especially in custom rendering or editor tools.
  3. Be aware of its impact on selection and hit testing in the editor.
  4. In game builds, ensure that BSP visibility is set correctly for the desired visual output.

#References in C++ code

#Callsites

This variable is referenced in the following C++ source code:

#Loc: <Workspace>/Engine/Source/Editor/UnrealEd/Private/DragTool_BoxSelect.cpp:71

Scope (from outer to inner):

file
function     void FDragTool_ActorBoxSelect::StartDrag

Source code excerpt:

	FLevelEditorViewportClient::ClearHoverFromObjects();

	// Create a list of bsp models to check for intersection with the box
	ModelsToCheck.Reset();
	// Do not select BSP if its not visible
	if( InViewportClient->EngineShowFlags.BSP)
	{
		UWorld* World = InViewportClient->GetWorld();
		check(World);
		// Add the persistent level always
		ModelsToCheck.Add( World->PersistentLevel->Model );
		// Add all streaming level models
		for (ULevelStreaming* StreamingLevel : World->GetStreamingLevels())
		{
			// Only add streaming level models if the level is visible
			if (StreamingLevel && StreamingLevel->GetShouldBeVisibleInEditor())
			{	

#Loc: <Workspace>/Engine/Source/Editor/UnrealEd/Private/Editor/ActorPositioning.cpp:135

Scope (from outer to inner):

file
function     bool IsHitIgnoredRenderingThread

Source code excerpt:

		const bool bConsiderInvisibleComponentForPlacement = PrimitiveComponent->bConsiderForActorPlacementWhenHidden;

		// Only use this component if it is visible in the specified scene views
		const FPrimitiveViewRelevance ViewRelevance = PrimitiveComponent->SceneProxy->GetViewRelevance(&InSceneView);
		// BSP is a bit special in that its bDrawRelevance is false even when drawn as wireframe because InSceneView.Family->EngineShowFlags.BSPTriangles is off
		const bool bIsRenderedOnScreen = ViewRelevance.bDrawRelevance || (PrimitiveComponent->IsA(UModelComponent::StaticClass()) && InSceneView.Family->EngineShowFlags.BSP);
		const bool bIgnoreTranslucentPrimitive = ViewRelevance.HasTranslucency() && !GetDefault<UEditorPerProjectUserSettings>()->bAllowSelectTranslucent;
		
		return (!bIsRenderedOnScreen && !bConsiderInvisibleComponentForPlacement) || bIgnoreTranslucentPrimitive;
	}

	return false;
}

FActorPositionTraceResult FActorPositioning::TraceWorldForPosition(const UWorld& InWorld, const FSceneView& InSceneView, const FVector& RayStart, const FVector& RayEnd, const TArray<AActor*>* IgnoreActors)
{
	TArray<FHitResult> Hits;

#Loc: <Workspace>/Engine/Source/Editor/UnrealEd/Private/EditorModeManager.cpp:1596

Scope (from outer to inner):

file
function     void FEditorModeTools::DrawHUD

Source code excerpt:

		return;
	}

	// Temporaries.
	const bool bShowBrushes = View->Family->EngineShowFlags.Brushes;
	const bool bShowBSP = View->Family->EngineShowFlags.BSP;
	const bool bShowBuilderBrush = View->Family->EngineShowFlags.BuilderBrush != 0;

	UTexture2D* VertexTexture = GetVertexTexture();
	const float TextureSizeX = VertexTexture->GetSizeX() * (bLargeVertices ? 1.0f : 0.5f);
	const float TextureSizeY = VertexTexture->GetSizeY() * (bLargeVertices ? 1.0f : 0.5f);

	GetEditorSelectionSet()->ForEachSelectedObject<AStaticMeshActor>([View, Canvas, VertexTexture, TextureSizeX, TextureSizeY, bIsHitTesting](AStaticMeshActor* Actor)
		{
			TArray<FVector> Vertices;
			FCanvasItemTestbed::bTestState = !FCanvasItemTestbed::bTestState;

#Loc: <Workspace>/Engine/Source/Editor/UnrealEd/Private/EditorServer.cpp:5601

Scope (from outer to inner):

file
function     bool UEditorEngine::Exec_Editor

Source code excerpt:

		}
	}
	//------------------------------------------------------------------------------------
	// BSP
	//
	else if( FParse::Command( &Str, TEXT("BSP") ) )
	{
		return CommandIsDeprecated( *CommandTemp, Ar );
	}
	//------------------------------------------------------------------------------------
	// LIGHT
	//
	else if( FParse::Command( &Str, TEXT("LIGHT") ) )
	{
		return CommandIsDeprecated( *CommandTemp, Ar );
	}
	//------------------------------------------------------------------------------------

#Loc: <Workspace>/Engine/Source/Runtime/Core/Public/UObject/UnrealNames.inl:187

Scope: file

Source code excerpt:

REGISTER_NAME(245,GameThread)
REGISTER_NAME(246,RenderThread)
REGISTER_NAME(247,OtherChildren)
REGISTER_NAME(248,Location)
REGISTER_NAME(249,Rotation)
REGISTER_NAME(250,BSP)
REGISTER_NAME(251,EditorSettings)
REGISTER_NAME(252,AudioThread)
REGISTER_NAME(253,ID)
REGISTER_NAME(254,UserDefinedEnum)
REGISTER_NAME(255,Control)
REGISTER_NAME(256,Voice)
REGISTER_NAME(257, Zlib)
REGISTER_NAME(258, Gzip)
REGISTER_NAME(259, LZ4)
REGISTER_NAME(260, Mobile)
REGISTER_NAME(261, Oodle)

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/Components/BrushComponent.cpp:315

Scope (from outer to inner):

file
class        class FBrushSceneProxy final : public FPrimitiveSceneProxy
function     virtual FPrimitiveViewRelevance GetViewRelevance

Source code excerpt:

				}
			}

			if(bNeverShow == false)
			{
				const bool bBSPVisible = View->Family->EngineShowFlags.BSP;
				const bool bBrushesVisible = View->Family->EngineShowFlags.Brushes;

				if ( !bVolume ) // EngineShowFlags.Collision does not apply to volumes
				{
					if( (bBSPVisible && bBrushesVisible) )
					{
						bVisible = true;
					}
				}

				// See if we should be visible because we are in a 'collision view' and have collision enabled

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/Components/BrushComponent.cpp:530

Scope (from outer to inner):

file
function     bool UBrushComponent::IsShown

Source code excerpt:


bool UBrushComponent::IsShown(const FEngineShowFlags& ShowFlags) const
{
	if (const AActor* Actor = GetOwner())
	{
		return (Actor->IsA(AVolume::StaticClass())) ? ShowFlags.Volumes : ShowFlags.BSP;
	}

	return false;
}

#if WITH_EDITOR
bool UBrushComponent::ComponentIsTouchingSelectionBox(const FBox& InSelBBox, const bool bConsiderOnlyBSP, const bool bMustEncompassEntireComponent) const
{
	if (Brush != nullptr && Brush->Polys != nullptr)
	{
		TArray<FVector> Vertices;

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/ModelRender.cpp:303

Scope (from outer to inner):

file
class        class FModelSceneProxy final : public FPrimitiveSceneProxy
function     virtual void GetDynamicMeshElements

Source code excerpt:

				const FSceneView* View = Views[ViewIndex];

				bool bShowSelection = GIsEditor && !View->bIsGameView && ViewFamily.EngineShowFlags.Selection;
				bool bDynamicBSPTriangles = bShowSelection || IsRichView(ViewFamily);
				bool bShowBSPTriangles = ViewFamily.EngineShowFlags.BSPTriangles;
				bool bShowBSP = ViewFamily.EngineShowFlags.BSP;

#if WITH_EDITOR
				bool bDrawCollision = false;
				const bool bInCollisionView = IsCollisionView(View, bDrawCollision);
				// draw bsp as dynamic when in collision view mode
				if(bInCollisionView)
				{
					bDynamicBSPTriangles = true;
				}
#endif

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/ModelRender.cpp:536

Scope (from outer to inner):

file
class        class FModelSceneProxy final : public FPrimitiveSceneProxy
function     virtual FPrimitiveViewRelevance GetViewRelevance

Source code excerpt:

	}

	virtual FPrimitiveViewRelevance GetViewRelevance(const FSceneView* View) const override
	{
		FPrimitiveViewRelevance Result;
		Result.bDrawRelevance = IsShown(View) && View->Family->EngineShowFlags.BSPTriangles && View->Family->EngineShowFlags.BSP;
		bool bShowSelectedTriangles = GIsEditor && !View->bIsGameView && View->Family->EngineShowFlags.Selection;
		bool bCollisionView = View->Family->EngineShowFlags.CollisionPawn || View->Family->EngineShowFlags.CollisionVisibility;
		if (IsRichView(*View->Family) || HasViewDependentDPG() || bCollisionView
			|| (bShowSelectedTriangles && HasSelectedSurfaces()))
		{
			Result.bDynamicRelevance = true;
		}
		else
		{
			Result.bStaticRelevance = true;
		}

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/ShowFlags.cpp:654

Scope (from outer to inner):

file
function     void EngineShowFlagOverride

Source code excerpt:

			 DISABLE_ENGINE_SHOWFLAG(TextRender)
			 DISABLE_ENGINE_SHOWFLAG(Particles)
			 DISABLE_ENGINE_SHOWFLAG(SkeletalMeshes)
			 DISABLE_ENGINE_SHOWFLAG(StaticMeshes)
			 DISABLE_ENGINE_SHOWFLAG(NaniteMeshes)
			 DISABLE_ENGINE_SHOWFLAG(BSP)
			 DISABLE_ENGINE_SHOWFLAG(Paper2DSprites)
#undef DISABLE_ENGINE_SHOWFLAG
		}
	}
#endif

	// Force some show flags to be 0 or 1
	{
		const uint8* Force0Ptr = (const uint8*)&GSystemSettings.GetForce0Mask();
		const uint8* Force1Ptr = (const uint8*)&GSystemSettings.GetForce1Mask();
		uint8* Ptr = (uint8*)&EngineShowFlags;

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Public/ShowFlagsValues.inl:282

Scope: file

Source code excerpt:

/** if this is a game viewport, needed? */
SHOWFLAG_ALWAYS_ACCESSIBLE(Game, SFG_Hidden, NSLOCTEXT("UnrealEd", "GameSF", "Game"))
/** Render objects with colors based on what the actors coloring handlers provides */
SHOWFLAG_FIXED_IN_SHIPPING(0, ActorColoration, SFG_Transient, NSLOCTEXT("UnrealEd", "ActorColorationSF", "Actor Coloration"))
/** Draws BSP brushes (in game or editor textured triangles usually with lightmaps), for now SHOWFLAG_ALWAYS_ACCESSIBLE because it's exposed in SceneCapture */
SHOWFLAG_ALWAYS_ACCESSIBLE(BSP, SFG_Normal, NSLOCTEXT("UnrealEd", "BSPSF", "BSP"))
/** Collision drawing */
SHOWFLAG_FIXED_IN_SHIPPING(0, Collision, SFG_Normal, NSLOCTEXT("UnrealEd", "CollisionWireFrame", "Collision"))
/** Collision blocking visibility against complex **/
SHOWFLAG_FIXED_IN_SHIPPING(0, CollisionVisibility, SFG_Hidden, NSLOCTEXT("UnrealEd", "CollisionVisibility", "Visibility"))
/** Collision blocking pawn against simple collision **/
SHOWFLAG_FIXED_IN_SHIPPING(0, CollisionPawn, SFG_Hidden, NSLOCTEXT("UnrealEd", "CollisionPawn", "Pawn"))
/** Render LightShafts, for now SHOWFLAG_ALWAYS_ACCESSIBLE because it's exposed in SceneCapture */
SHOWFLAG_ALWAYS_ACCESSIBLE(LightShafts, SFG_LightingFeatures, NSLOCTEXT("UnrealEd", "LightShaftsSF", "Light Shafts"))
/** Render the PostProcess Material */
SHOWFLAG_FIXED_IN_SHIPPING(1, PostProcessMaterial, SFG_PostProcess, NSLOCTEXT("UnrealEd", "PostProcessMaterialSF", "Post Process Material"))
/** Render Sky and Atmospheric lighting, for now SHOWFLAG_ALWAYS_ACCESSIBLE because it's exposed in SceneCapture */

#Loc: <Workspace>/Engine/Source/Runtime/Renderer/Private/SceneHitProxyRendering.cpp:1019

Scope (from outer to inner):

file
function     int32 FEditorSelectionMeshProcessor::GetStencilValue

Source code excerpt:


	// Reserved values for the stencil buffer that carry specific meaning
	enum ESelectionStencilValues : int32
	{
		NotSelected = 0,
		BSP = 1, // The outlines of all BSPs should be merged

		COUNT,
	};

	static constexpr int BitsAvailable = 8; // Stencil buffer is 8-bit
	static constexpr int ColorBits = 3; // Can be changed
	static constexpr int UniqueIdBits = BitsAvailable - ColorBits;
	static constexpr int MaxColor = (1 << ColorBits);
	static constexpr int MaxUniqueId = (1 << UniqueIdBits);
	
	auto EncodeSelectionStencilValue = [](int32 ColorIndex, int32 UniqueId) -> int32

#Loc: <Workspace>/Engine/Source/Runtime/Renderer/Private/SceneHitProxyRendering.cpp:1053

Scope (from outer to inner):

file
function     int32 FEditorSelectionMeshProcessor::GetStencilValue

Source code excerpt:

	
	int32 StencilValue = ESelectionStencilValues::NotSelected;

	if (PrimitiveSceneProxy->GetOwnerName() == NAME_BSP)
	{
		StencilValue = ESelectionStencilValues::BSP;
	}
	else if (ExistingStencilValue != nullptr)
	{
		StencilValue = *ExistingStencilValue;
	}
	else if (PrimitiveSceneProxy->IsIndividuallySelected())
	{
		const int Color = 0;
		const int UniqueId = ProxyToStencilIndex.Num();
		StencilValue = EncodeSelectionStencilValue(Color, UniqueId);
		ProxyToStencilIndex.Add(PrimitiveSceneProxy, StencilValue);