VisibilityNormalOffsetDistance

VisibilityNormalOffsetDistance

#Overview

name: VisibilityNormalOffsetDistance

The value of this variable can be defined or overridden in .ini config files. 1 .ini config file referencing this setting variable.

It is referenced in 8 C++ source files.

#Summary

#Usage in the C++ source code

The purpose of VisibilityNormalOffsetDistance is to prevent self-shadowing artifacts in static lighting calculations within Unreal Engine 5’s Lightmass system. It’s used to offset the starting point of visibility rays along the surface normal direction when performing shadow and visibility tests.

This setting variable is primarily used in the lighting and shadow mapping subsystems of Unreal Engine, specifically within the Lightmass global illumination solver. It’s referenced in modules related to static lighting, photon mapping, and texture mapping for lightmaps.

The value of this variable is typically set in the Lightmass configuration file (Lightmass.ini) under the [DevOptions.StaticLightingSceneConstants] section. It’s read into the engine during the static lighting build process.

VisibilityNormalOffsetDistance often interacts with other visibility-related variables like VisibilityRayOffsetDistance and VisibilityNormalOffsetSampleRadiusScale. These variables work together to fine-tune the positioning of visibility rays for more accurate lighting calculations.

Developers should be aware that this variable directly affects the accuracy and quality of static lighting. Setting it too low might result in self-shadowing artifacts, while setting it too high could lead to light leaking or loss of detail in shadows.

Best practices when using this variable include:

  1. Adjusting it in small increments and rebuilding lighting to observe the effects.
  2. Considering the scale of your scene, as the appropriate value may vary depending on scene size.
  3. Balancing it with other visibility offset variables for optimal results.
  4. Documenting any changes made to this setting, as it can significantly impact lighting quality across the project.

#Setting Variables

#References In INI files

Location: <Workspace>/Engine/Config/BaseLightmass.ini:42, section: [DevOptions.StaticLightingSceneConstants]

#References in C++ code

#Callsites

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

#Loc: <Workspace>/Engine/Source/Editor/UnrealEd/Private/Lightmass/Lightmass.cpp:2182

Scope (from outer to inner):

file
function     void FLightmassExporter::WriteSceneSettings

Source code excerpt:

		Scene.SceneConstants.StaticLightingLevelScale = GlobalLevelScale * LevelSettings.StaticLightingLevelScale;
		VERIFYLIGHTMASSINI(GConfig->GetFloat(TEXT("DevOptions.StaticLightingSceneConstants"), TEXT("VisibilityRayOffsetDistance"), Scene.SceneConstants.VisibilityRayOffsetDistance, GLightmassIni));
		VERIFYLIGHTMASSINI(GConfig->GetFloat(TEXT("DevOptions.StaticLightingSceneConstants"), TEXT("VisibilityNormalOffsetDistance"), Scene.SceneConstants.VisibilityNormalOffsetDistance, GLightmassIni));
		VERIFYLIGHTMASSINI(GConfig->GetFloat(TEXT("DevOptions.StaticLightingSceneConstants"), TEXT("VisibilityNormalOffsetSampleRadiusScale"), Scene.SceneConstants.VisibilityNormalOffsetSampleRadiusScale, GLightmassIni));
		VERIFYLIGHTMASSINI(GConfig->GetFloat(TEXT("DevOptions.StaticLightingSceneConstants"), TEXT("VisibilityTangentOffsetSampleRadiusScale"), Scene.SceneConstants.VisibilityTangentOffsetSampleRadiusScale, GLightmassIni));
		VERIFYLIGHTMASSINI(GConfig->GetFloat(TEXT("DevOptions.StaticLightingSceneConstants"), TEXT("SmallestTexelRadius"), Scene.SceneConstants.SmallestTexelRadius, GLightmassIni));
		VERIFYLIGHTMASSINI(GConfig->GetInt(TEXT("DevOptions.StaticLightingSceneConstants"), TEXT("LightGridSize"), Scene.SceneConstants.LightGridSize, GLightmassIni));
	}
	{

#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Private/ImportExport/LightmassScene.cpp:512

Scope (from outer to inner):

file
namespace    Lightmass
function     void FScene::ApplyStaticLightingScale

Source code excerpt:

	// Scale world space distances directly
	SceneConstants.VisibilityRayOffsetDistance *= SceneConstants.StaticLightingLevelScale;
	SceneConstants.VisibilityNormalOffsetDistance *= SceneConstants.StaticLightingLevelScale;
	SceneConstants.SmallestTexelRadius *= SceneConstants.StaticLightingLevelScale;
	MeshAreaLightSettings.MeshAreaLightSimplifyCornerDistanceThreshold *= SceneConstants.StaticLightingLevelScale;
	MeshAreaLightSettings.MeshAreaLightGeneratedDynamicLightSurfaceOffset *= SceneConstants.StaticLightingLevelScale;
	DynamicObjectSettings.FirstSurfaceSampleLayerHeight *= SceneConstants.StaticLightingLevelScale;
	DynamicObjectSettings.SurfaceLightSampleSpacing *= SceneConstants.StaticLightingLevelScale;
	DynamicObjectSettings.SurfaceSampleLayerHeightSpacing *= SceneConstants.StaticLightingLevelScale;

#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Private/Lighting/PhotonMapping.cpp:622

Scope (from outer to inner):

file
namespace    Lightmass
function     void FStaticLightingSystem::EmitDirectPhotonsWorkRange

Source code excerpt:

				const FVector4f RayStart = IntersectionVertexWithTangents.WorldPosition 
					+ NewWorldPathDirection * SceneConstants.VisibilityRayOffsetDistance 
					+ IntersectionVertexWithTangents.WorldTangentZ * SceneConstants.VisibilityNormalOffsetDistance;
				const FVector4f RayEnd = IntersectionVertexWithTangents.WorldPosition + NewWorldPathDirection * MaxRayDistance;

				FLightRay IndirectSampleRay(
					RayStart,
					RayEnd,
					NULL,

#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Private/Lighting/PhotonMapping.cpp:1163

Scope (from outer to inner):

file
namespace    Lightmass
function     void FStaticLightingSystem::EmitIndirectPhotonsWorkRange

Source code excerpt:

			const FVector4f RayStart = IntersectionVertexWithTangents.WorldPosition 
				+ NewWorldPathDirection * SceneConstants.VisibilityRayOffsetDistance 
				+ IntersectionVertexWithTangents.WorldTangentZ * SceneConstants.VisibilityNormalOffsetDistance;
			FVector4f RayEnd = IntersectionVertexWithTangents.WorldPosition + NewWorldPathDirection * MaxRayDistance;

			// Clip photon path end points to the importance volume, so we do not bother tracing rays outside the area that photons can be deposited.
			// If the photon path does not intersect the importance volume at all, it did not originate from inside the volume, so skip to the next photon.
			FVector4f ClippedStart, ClippedEnd;
			if (!ClipLineWithBox(Input.ImportanceBounds.GetBox(), RayStart, RayEnd, ClippedStart, ClippedEnd))

#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Private/Lighting/PhotonMapping.cpp:2302

Scope (from outer to inner):

file
namespace    Lightmass
function     FIrradiancePhoton* FStaticLightingSystem::FindNearestIrradiancePhoton

Source code excerpt:

			const FVector4f VertexToPhoton = CurrentPhoton->GetPosition() - Vertex.WorldPosition;
			const FLightRay VertexToPhotonRay(
				Vertex.WorldPosition + VertexToPhoton.GetSafeNormal() * SceneConstants.VisibilityRayOffsetDistance + Vertex.WorldTangentZ * SceneConstants.VisibilityNormalOffsetDistance,
				CurrentPhoton->GetPosition() + CurrentPhoton->GetSurfaceNormal() * SceneConstants.VisibilityNormalOffsetDistance,
				NULL,
				NULL
				);

			MappingContext.Stats.NumIrradiancePhotonSearchRays++;
			const float PreviousShadowTraceTime = MappingContext.RayCache.BooleanRayTraceTime;

#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Private/Lighting/TextureMapping.cpp:1985

Scope (from outer to inner):

file
namespace    Lightmass
function     void FStaticLightingSystem::CalculateDirectSignedDistanceFieldLightingTextureMappingTextureSpace

Source code excerpt:

						TexelToVertex.WorldPosition 
						+ LightVector * SceneConstants.VisibilityRayOffsetDistance 
						+ NormalForOffset * SceneConstants.VisibilityNormalOffsetDistance,
						LightPosition,
						TextureMapping,
						Light
						);

					FLightRayIntersection Intersection;

#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Private/Lighting/TextureMapping.cpp:2215

Scope: file

Source code excerpt:

									HighResSample.GetPosition() 
									+ LightVector * SceneConstants.VisibilityRayOffsetDistance 
									+ NormalForOffset * SceneConstants.VisibilityNormalOffsetDistance,
									LightPosition,
									TextureMapping, 
									Light
									);

								FLightRayIntersection Intersection;

#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Public/SceneExport.h:151

Scope (from outer to inner):

file
namespace    Lightmass
class        class FStaticLightingSceneConstants

Source code excerpt:

	 * This is used to push triangle shaped self shadowing artifacts onto the backfaces of curved objects.
	 */
	float VisibilityNormalOffsetDistance;

	/** 
	 * Fraction of the sample radius to offset the origin of the ray along the sample normal. 
	 * This is applied instead of VisibilityNormalOffsetDistance whenever sample radius is known as it adapts to differently sized texels.
	 */
	float VisibilityNormalOffsetSampleRadiusScale;

	/** 
	 * Fraction of the sample radius to offset the origin of the ray in the tangent XY plane, based on the direction of the ray.
	 * This is only used when bAccountForTexelSize is true.
	 */
	float VisibilityTangentOffsetSampleRadiusScale;