// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "CoreTypes.h" #include "Math/UnrealMathUtility.h" #include "Math/Color.h" #include "Math/Vector2D.h" #include "Containers/EnumAsByte.h" #include "Math/Vector.h" #include "Math/Vector4.h" #include "Math/Box.h" #include "Math/Matrix.h" #include "Math/SHMath.h" #include "Misc/Guid.h" #include "MeshExport.h" #ifdef UE_LIGHTMASS #include "Misc/LMHelpers.h" #endif struct FSplineMeshParams; namespace Lightmass { #if !PLATFORM_MAC && !PLATFORM_LINUX #pragma pack(push, 1) #endif static const int32 NumTexelCorners = 4; /** * General and misc solver settings. * Settings prefixed by Debugging are only useful for development, * Either because one of the options have been proven superior or because it produces a visualization of an intermediate result. * All angles are in Radians, distances are in world space units. */ class FStaticLightingSettings { public: /** Debugging - whether to allow multiple static lighting threads. */ bool bAllowMultiThreadedStaticLighting; /** * Number of local cores to leave unused */ int32 NumUnusedLocalCores; /** * Number of indirect lighting bounces to simulate, 0 is direct lighting only. * The first bounce always costs the most in terms of computation time, with the second bounce following. * With photon mapping, bounces after the second are nearly free. */ int32 NumIndirectLightingBounces; /** * Number of skylight and emissive bounces to simulate. * Lightmass uses a non-distributable radiosity method for skylight bounces whose cost is proportional to the number of bounces. */ int32 NumSkyLightingBounces; /** * Whether to use Embree for ray tracing or not. */ bool bUseEmbree; /** * Whether to check for Embree coherency. */ bool bVerifyEmbree; /** Whether to build Embree data structures for packet tracing. WIP feature - no lightmass algorithms emit packet tracing requests yet. */ bool bUseEmbreePacketTracing; /** Whether to use kDOP trees to accelerate volumetric lightmap voxelization. Useful in scenes like large forest. */ bool bUseFastVoxelization; /** Whether to use static mesh instancing to reduce memory consumption in scenes like large forest. Might slow down small scenes. */ bool bUseEmbreeInstancing; /** * Direct lighting, skylight radiosity and irradiance photons are cached on mapping surfaces to accelerate final gathering. * This controls the downsample factor for that cache, relative to the mapping's lightmap resolution. */ int32 MappingSurfaceCacheDownsampleFactor; /** * Smoothness factor to apply to indirect lighting. This is useful in some lighting conditions when Lightmass cannot resolve accurate indirect lighting. * 1 is default smoothness tweaked for a variety of lighting situations. * Higher values like 3 smooth out the indirect lighting more, but at the cost of indirect shadows losing detail as well. */ float IndirectLightingSmoothness; /** * Warning: Setting this higher than 1 will greatly increase build times! * Can be used to increase the GI solver sample counts in order to get higher quality for levels that need it. * It can be useful to reduce IndirectLightingSmoothness somewhat (~.75) when increasing quality to get defined indirect shadows. * Note that this can't affect compression artifacts or other texture based artifacts. */ float IndirectLightingQuality; /** * Debugging - which single light bounce to view or -1 for all. * This setting has been carefully implemented to only affect the final color and not affect any other part of the solver (sample positions, ray directions, etc). * Most of the debug visualizations are affected by ViewSingleBounceNumber. */ int32 ViewSingleBounceNumber; /** * Debugging - when enabled, multiple samples will be used to detect all the texels that are mapped to geometry. * Otherwise only the center and corner of each texel will be sampled. */ bool bUseConservativeTexelRasterization; /** Debugging - whether to use the texel size in various calculations in an attempt to compensate for point sampling a texel. */ bool bAccountForTexelSize; /** Debugging - whether to use the sample with the largest weight when rasterizing texels or a linear combination. */ bool bUseMaxWeight; /** Maximum lighting samples per triangle for vertex lightmaps. */ int32 MaxTriangleLightingSamples; /** Maximum samples for caching irradiance photons per triangle for vertex lightmaps. */ int32 MaxTriangleIrradiancePhotonCacheSamples; /** Debugging - whether to color texels when invalid settings are detected. */ bool bUseErrorColoring; /** Unmapped texel color */ FLinearColor UnmappedTexelColor; }; /** Scale dependent constants */ class FStaticLightingSceneConstants { public: /** * Scale of the level being lit. * Games using a different scale should use this to convert the defaults into the game-specific scale. */ float StaticLightingLevelScale; /** * World space distance to offset the origin of the ray, along the direction of the ray. * This is used to prevent incorrect self shadowing due to floating point precision. */ float VisibilityRayOffsetDistance; /** * World space distance to offset the origin of the ray along the direction of the normal. * 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; /** * Smallest texel radius allowed, useful for clamping edge cases where some texels have a radius of 0. * This should be smaller than the smallest valid texel radius in the scene. */ float SmallestTexelRadius; /** * Size of the grid that each light will use to cache information. * Larger grids take longer to precompute, but result in accelerated light sampling. */ int32 LightGridSize; }; /** Settings for which material attribute to visualize */ enum EViewMaterialAttribute { VMA_None, VMA_Emissive, VMA_Diffuse, VMA_Transmission, VMA_Normal }; /** The scenes material settings */ struct FSceneMaterialSettings { /** Debugging - Whether to use the debug material */ bool bUseDebugMaterial; /** Debugging - Indicates which material attribute to visualize. */ EViewMaterialAttribute ViewMaterialAttribute; /** The size of the emissive sample */ int32 EmissiveSize; /** The size of the diffuse sample */ int32 DiffuseSize; /** The size of the Transmission sample */ int32 TransmissionSize; /** The size of the normal sample */ int32 NormalSize; /** Whether to use the normal map for lighting, if false the smoothed vertex normal will be used. */ bool bUseNormalMapsForLighting; /** * Debugging - Amount of incoming light to reflect diffusely (equally in all directions). * This is the diffuse term in the modified Phong BRDF, not the original. */ FLinearColor DebugDiffuse; /** Debugging - Emissive value assigned to secondary rays which miss all geometry in the scene. */ FLinearColor EnvironmentColor; }; /** Settings for meshes which emit light from their emissive areas. */ struct FMeshAreaLightSettings { /** Whether to draw debug lines showing the corners of mesh area light primitives when a texel has been selected. */ bool bVisualizeMeshAreaLightPrimitives; /** Emissive intensities must be larger than this to contribute toward scene lighting. */ float EmissiveIntensityThreshold; /** * Size of the grid that each mesh area light will use to cache information. * Larger grids take longer to precompute, but result in accelerated light sampling. */ int32 MeshAreaLightGridSize; /** Cosine of the maximum angle allowed between mesh area light primitives that get merged into the same simplified primitive. */ float MeshAreaLightSimplifyNormalCosAngleThreshold; /** Maximum distance allowed between any mesh area light primitive corners that get merged into the same simplified primitive. */ float MeshAreaLightSimplifyCornerDistanceThreshold; /** Fraction of a mesh's bounds that an emissive texel can be from a simplified primitive and still get merged into that primitive. */ float MeshAreaLightSimplifyMeshBoundingRadiusFractionThreshold; /** Distance along the average normal from the bounds origin of the mesh area light to place a light to handle influencing dynamic objects. */ float MeshAreaLightGeneratedDynamicLightSurfaceOffset; }; /** AO settings */ class FAmbientOcclusionSettings { public: /** * Whether to calculate ambient occlusion. * When enabled, some final gather rays will be traced even if only direct lighting is being calculated. */ bool bUseAmbientOcclusion; /** * Whether to generate textures storing the AO computed by Lightmass. * These can be accessed through the PrecomputedAmbientOcclusion material node, * Which is useful for blending between material layers on environment assets. */ bool bGenerateAmbientOcclusionMaterialMask; /** Debugging - whether to only show the ambient occlusion term, useful for seeing the impact of AO settings in isolation. */ bool bVisualizeAmbientOcclusion; /** * How much of the ambient occlusion term should be applied to direct lighting. * A value of 0 will leave the direct lighting untouched, a value of 1 will apply all of the occlusion. */ float DirectIlluminationOcclusionFraction; /** Same as DirectIlluminationOcclusionFraction, but applied to indirect lighting. */ float IndirectIlluminationOcclusionFraction; /** * Controls the ambient occlusion contrast. * Higher powers result in more contrast, which effectively shorten the occlusion gradient and push it into corners. * An exponent of 1 gives equivalent occlusion as the indirect shadows from a constant environment color, with no other lights in the scene. */ float OcclusionExponent; /** * Fraction of the samples taken that have to be occluded before an occlusion value of 1 is reached for that texel. * A value of 1 means all the samples in the hemisphere have to be occluded, lower values darken areas that are not fully occluded. */ float FullyOccludedSamplesFraction; /** * Maximum distance over which an object can affect the occlusion of a texel. * Lowering this cuts off lower frequencies in the ambient occlusion. */ float MaxOcclusionDistance; }; /** Settings related to precomputations used by dynamic objects. */ class FDynamicObjectSettings { public: /** Debugging - Whether to draw points in the editor to visualize volume lighting samples. */ bool bVisualizeVolumeLightSamples; /** Debugging - Whether to interpolate indirect lighting for surfaces from the precomputed light volume. */ bool bVisualizeVolumeLightInterpolation; /** Scales the number of hemisphere samples that should be used for lighting volume samples. */ float NumHemisphereSamplesScale; /** World space distance between samples placed on upward facing surfaces. */ float SurfaceLightSampleSpacing; /** Height of the first sample layer above the surface. */ float FirstSurfaceSampleLayerHeight; /** Height difference of successive layers. */ float SurfaceSampleLayerHeightSpacing; /** Number of layers to place above surfaces. */ int32 NumSurfaceSampleLayers; /** Distance between samples placed in a 3d uniform grid inside detail volumes. */ float DetailVolumeSampleSpacing; /** Distance between samples placed in a 3d uniform grid inside the importance volume. */ float VolumeLightSampleSpacing; /** Maximum samples placed in the 3d volume, used to limit memory usage. */ int32 MaxVolumeSamples; /** Use Maximum number restriction for Surface Light Sample. */ bool bUseMaxSurfaceSampleNum; /** Maximum samples placed in the surface light sample(only for Landscape currently), used to limit memory usage. */ int32 MaxSurfaceLightSamples; }; /** Settings for the volumetric lightmap. */ class FVolumetricLightmapSettings { public: /** Size of the top level grid covering the volumetric lightmap, in bricks. */ FIntVector TopLevelGridSize; /** World space size of the volumetric lightmap. */ FVector3f VolumeMin; FVector3f VolumeSize; /** * Size of a brick of unique lighting data. Must be a power of 2. * Smaller values provide more granularity, but waste more memory due to padding. */ int32 BrickSize; /** Maximum number of times to subdivide bricks around geometry. */ int32 MaxRefinementLevels; /** * Fraction of a cell's size to expand it by when voxelizing. * Larger values add more resolution around geometry, improving the lighting gradients but costing more memory. */ float VoxelizationCellExpansionForSurfaceGeometry; float VoxelizationCellExpansionForVolumeGeometry; float VoxelizationCellExpansionForLights; /** Bricks with RMSE below this value are culled. */ float MinBrickError; /** Triangles with fewer lightmap texels than this don't cause refinement. */ float SurfaceLightmapMinTexelsPerVoxelAxis; /** Whether to cull bricks entirely below landscape. This can be an invalid optimization if the landscape has holes and caves that pass under landscape. */ bool bCullBricksBelowLandscape; /** Subdivide bricks when a static point or spot light affects some part of the brick with brightness higher than this. */ float LightBrightnessSubdivideThreshold; /** Maximum desired curvature in the lighting stored in Volumetric Lightmaps, used to reduce Spherical Harmonic ringing via a windowing filter. */ float WindowingTargetLaplacian; }; /** Settings for precomputed visibility. */ class FPrecomputedVisibilitySettings { public: /** Whether to export debug lines for visibility. */ bool bVisualizePrecomputedVisibility; /** Whether to only place visibility cells on opaque surfaces. */ bool bPlaceCellsOnOpaqueOnly; /** Whether to place visibility cells only along camera tracks or to also include shadow casting surfaces. */ bool bPlaceCellsOnlyAlongCameraTracks; /** World space size of visibility cells in the x and y dimensions. */ float CellSize; /** Number of tasks that visibility cells are being split up into. */ int32 NumCellDistributionBuckets; /** World space size of visibility cells in the z dimension. */ float PlayAreaHeight; /** Amount to increase the bounds of meshes when querying their visibility. Larger scales reduce visibility errors at the cost of less effective culling. */ float MeshBoundsScale; /** Minimum number of samples on the mesh for each cell - mesh query. Small meshes use less samples. */ int32 MinMeshSamples; /** Maximum number of samples on the mesh for each cell - mesh query. Small meshes use less samples. */ int32 MaxMeshSamples; /** Number of samples on each cell for each cell - mesh query. */ int32 NumCellSamples; /** Number of samples to use when importance sampling each cell - mesh query. */ int32 NumImportanceSamples; }; /** Settings for volume distance field generation. */ class FVolumeDistanceFieldSettings { public: /** World space size of a voxel. Smaller values use significantly more memory and processing time, but allow more detailed shadows. */ float VoxelSize; /** * Maximum world space distance represented in the distance field, used for normalization. * Larger values increase build time and decrease distance field precision, but allow distance field traversal to skip larger areas. */ float VolumeMaxDistance; /** Number of distance traces for each voxel. */ int32 NumVoxelDistanceSamples; /** Upper limit on the number of voxels that can be generated. */ int32 MaxVoxels; }; /** Shadow settings */ class FStaticShadowSettings { public: /** Debugging - Whether to filter a single shadow sample per texel in texture space instead of calculating area shadows. */ bool bUseZeroAreaLightmapSpaceFilteredLights; /** Number of shadow rays to trace to each area light for each texel. */ int32 NumShadowRays; /** Number of shadow rays to trace to each area light once a texel has been determined to lie in a shadow penumbra. */ int32 NumPenumbraShadowRays; /** * Number of shadow rays to trace to each area light for bounced lighting. * This number is divided by bounce number for successive bounces. */ int32 NumBounceShadowRays; /** * Settings for enabling and adjusting a filter pass on the computed shadow factor. The shadow factor is * a value [0,1] that approximates the percentage of an area light visible at a texel. A value of 0 indicates * that the texel is completely in shadow and 1 indicates that it is completely lit. The tolerance value is the * maximum difference in the absolute shadow factor value allowed between any two adjacent texels before enabling * filtering, meant to catch shadow transitions sharper than can be captured in the lightmap. */ bool bFilterShadowFactor; float ShadowFactorGradientTolerance; /** Whether to allow signed distance field shadows, or fall back on area shadows. */ bool bAllowSignedDistanceFieldShadows; /** * Maximum world space distance stored from a texel to the shadow transition. * Larger distances decrease precision but increase the maximum penumbra size that can be reconstructed from the distance field. */ float MaxTransitionDistanceWorldSpace; /** * The number of high resolution samples to calculate per MaxTransitionDistanceWorldSpace. * Higher values increase the distance field reconstruction quality, at the cost of longer build times. */ int32 ApproximateHighResTexelsPerMaxTransitionDistance; /** * The minimum upsample factor to calculate the high resolution samples at. * Larger values increase distance field reconstruction quality on small, high resolution meshes, at the cost of longer build times. */ int32 MinDistanceFieldUpsampleFactor; /** Distance in world space units between dominant light shadow map cells. */ float StaticShadowDepthMapTransitionSampleDistanceX; float StaticShadowDepthMapTransitionSampleDistanceY; /** Amount to super sample dominant shadow map generation, in each dimension. Larger factors increase build time but produce a more conservative shadow map. */ int32 StaticShadowDepthMapSuperSampleFactor; /** Maximum number of dominant shadow samples to generate for one dominant light, used to limit memory used. */ int32 StaticShadowDepthMapMaxSamples; /** Fraction of valid lighting samples (mapped texels or vertex samples) that must be unoccluded in a precomputed shadowmap for the shadowmap to be kept. */ float MinUnoccludedFraction; }; /** * Settings related to solving the light transport equation by starting from the source of importance, * as opposed to starting from the source of radiant power. */ class FImportanceTracingSettings { public: /** * Debugging - whether to stratify hemisphere samples, which reduces variance. */ bool bUseStratifiedSampling; /** * Number of hemisphere samples to evaluate from each irradiance cache sample when not using path tracing. * When photon mapping is enabled, these are called final gather rays. */ int32 NumHemisphereSamples; /** Number of recursive levels allowed for adaptive refinement. This has a huge impact on build time but also quality. */ int32 NumAdaptiveRefinementLevels; /** * Largest angle from the sample normal that a hemisphere sample direction can be. * Useful for preventing rays nearly perpendicular to the normal which may self intersect a flat surface due to imprecision in the normal. */ float MaxHemisphereRayAngle; /** Starting threshold for what relative brightness difference causes a refinement. At each depth the effective threshold will be reduced. */ float AdaptiveBrightnessThreshold; /** Starting threshold for what angle around a first bounce photon causes a refinement on all cells affected. At each depth the effective threshold will be reduced. */ float AdaptiveFirstBouncePhotonConeAngle; float AdaptiveSkyVarianceThreshold; /** * Whether to use radiosity iterations for solving skylight 2nd bounce and up, plus emissive 1st bounce and up. * These light sources are not represented by photons so they need to be handled separately to have multiple bounces. */ bool bUseRadiositySolverForSkylightMultibounce; /** * Whether to cache final gather hit points for the radiosity algorithm, which reduces radiosity iteration time significantly but uses a lot of memory. * Memory use is proportional to the lightmap texels in the scene and number of final gather rays. */ bool bCacheFinalGatherHitPointsForRadiosity; /** * Whether to use radiosity iterations for point / spot / directional lights, instead of photons. * Has lower quality than photons in difficult indoor scenarios but useful as a reference. */ bool bUseRadiositySolverForLightMultibounce; }; /** Settings controlling photon mapping behavior. */ class FPhotonMappingSettings { public: /** * Debugging - whether to use photon mapping. * Photon mapping benefits many parts of the solver so this is mainly for comparing against other methods. */ bool bUsePhotonMapping; /** * Debugging - whether to estimate the first bounce lighting by tracing rays from the sample point, * Which is called final gathering, or by using the density of nearby first bounce photons. * Final gathering is slow but gets vastly better results than using first bounce photons. */ bool bUseFinalGathering; /** * Whether to use photons to represent direct lighting in final gathers. * This is useful to visualize direct photons. When false, explicitly sampled direct lighting will be used instead, which has less leaking. */ bool bUsePhotonDirectLightingInFinalGather; /** * Debugging - whether to replace direct lighting with direct lighting as seen by the final gather. * This will either be direct lighting from photons, or approximate explicitly sampled direct lighting, depending on bUsePhotonDirectLightingInFinalGather. * This is mainly useful for debugging what the final gather rays see. */ bool bVisualizeCachedApproximateDirectLighting; /** Debugging - whether to use the optimization of caching irradiance calculations in deposited photons (called Irradiance photons). */ bool bUseIrradiancePhotons; /** * Debugging - whether to cache the result of the search for the nearest irradiance photon on surfaces. * This results in a constant time lookup at the end of each final gather ray instead of a photon map search. * Only visible photons are cached, which reduces light leaking. */ bool bCacheIrradiancePhotonsOnSurfaces; /** * Debugging - whether to draw lines in the editor representing photon paths. * They will only be drawn if a texel is selected and ViewSingleBounceNumber is >= 0. */ bool bVisualizePhotonPaths; /** * Debugging - whether to draw the photons gathered for the selected texel or the photons gathered by final gather rays from the selected texel. * This includes importance, irradiance and direct photons. */ bool bVisualizePhotonGathers; /** * Debugging - whether to draw lines in the editor showing where rays were traced due to importance photons from the selected texel. * If this is false, lines will be drawn for the rays traced with uniform hemisphere sampling instead. * Note that when irradiance caching is enabled, rays will only be gathered if the selected texel created an irradiance cache sample. */ bool bVisualizePhotonImportanceSamples; /** * Debugging - whether to gather and draw photon map octree nodes that get traversed during the irradiance calculation for the irradiance photon nearest to the select position. * Which photon map search the nodes come from depends on ViewSingleBounceNumber. */ bool bVisualizeIrradiancePhotonCalculation; /** * Debugging - whether to emit any photons outside the importance volume, if one exists. * If this is false, nothing outside the volume will bounce lighting and will be lit with direct lighting only. */ bool bEmitPhotonsOutsideImportanceVolume; /** Cone filter constant, which characterizes the falloff of the filter applied to photon density estimations. */ float ConeFilterConstant; /** Number of photons to find in each photon map when calculating irradiance for an irradiance photon. */ int32 NumIrradianceCalculationPhotons; /** * Fraction of NumHemisphereSamples to use for importance sampling instead of uniform sampling the final gather. * If this fraction is close to 1, no uniform samples will be done and irradiance caching will be forced off as a result. * If this is 0, only uniform samples will be taken. */ float FinalGatherImportanceSampleFraction; /** Cosine of the cone angle from an importance photon direction to generate ray directions for importance sampled final gathering. */ float FinalGatherImportanceSampleCosConeAngle; /** World space radius of the disk around an indirect photon path in which indirect photons will be emitted from directional lights. */ float IndirectPhotonEmitDiskRadius; /** Angle around an indirect photon path in which indirect photons will be emitted from point, spot and mesh area lights. */ float IndirectPhotonEmitConeAngle; /** Maximum distance to search for importance photons. */ float MaxImportancePhotonSearchDistance; /** * Distance to start searching for importance photons at. * For some scenes a small start distance (relative to MaxImportancePhotonSearchDistance) will speed up the search * Since it can early out once enough photons are found. For other scenes a small start distance will just cause redundant photon map searches. */ float MinImportancePhotonSearchDistance; /** Number of importance photons to find at each irradiance cache sample that will be used to guide the final gather. */ int32 NumImportanceSearchPhotons; /** Scales the density at which to gather photons outside of the importance volume, if one exists. */ float OutsideImportanceVolumeDensityScale; /** * Density of direct photons to emit per light, in number of photons per million surface area units. */ float DirectPhotonDensity; /** Density of direct photons which have irradiance cached at their position, in number of photons per million surface area units. */ float DirectIrradiancePhotonDensity; /** Distance to use when searching for direct photons. */ float DirectPhotonSearchDistance; /** * Target density of indirect photon paths to gather, in number of paths per million surface area units. * Densities too small will result in indirect lighting not making it into small pockets. */ float IndirectPhotonPathDensity; /** * Density of indirect photons to emit, in number of photons per million surface area units. * This should be high because first bounce photons are used to guide the final gather. */ float IndirectPhotonDensity; /** Density of indirect photons which have irradiance cached at their position, in number of photons per million surface area units. */ float IndirectIrradiancePhotonDensity; /** Distance to use when searching for indirect photons. */ float IndirectPhotonSearchDistance; /** Maximum cosine of the angle between the search normal and the surface normal of a candidate photon for that photon to be a valid search result. */ float PhotonSearchAngleThreshold; /** Cosine of the angle from the search normal that defines a cone which irradiance photons must be outside of to be valid for that search. */ float MinCosIrradiancePhotonSearchCone; /** * Whether to build a photon segment map, to guide importance sampling for volume queries. * Currently costs too much memory and queries are too slow to be a net positive. */ bool bUsePhotonSegmentsForVolumeLighting; /** Maximum world space length of segments that photons are split into for volumetric queries. */ float PhotonSegmentMaxLength; /** Probability that a first bounce photon will be put into the photon segment map for volumetric queries. */ float GeneratePhotonSegmentChance; }; /** Settings controlling irradiance caching behavior. */ class FIrradianceCachingSettings { public: /** Debugging - whether to allow irradiance caching. When this is disabled, indirect lighting will be many times slower. */ bool bAllowIrradianceCaching; /** Debugging - whether to use irradiance gradients, which effectively allows higher order irradiance cache interpolation. */ bool bUseIrradianceGradients; /** Debugging - whether to only show irradiance gradients. */ bool bShowGradientsOnly; /** Debugging - whether to draw debug elements in the editor showing which irradiance cache samples were used to shade the selected texel. */ bool bVisualizeIrradianceSamples; /** Scale applied to the radius of irradiance cache records. This directly affects sample placement and therefore quality. */ float RecordRadiusScale; /** Maximum angle between a record and the point being shaded allowed for the record to contribute. */ float InterpolationMaxAngle; /** * Maximum angle from the plane defined by the average normal of a record and the point being shaded * That the vector from the point to the record can be for that record to contribute. */ float PointBehindRecordMaxAngle; /** * How much to increase RecordRadiusScale for the shading pass. * This effectively filters the irradiance on flat surfaces. */ float DistanceSmoothFactor; /** * How much to increase InterpolationMaxAngle for the shading pass. * This effectively filters the irradiance on curved surfaces. */ float AngleSmoothFactor; /** * Scale applied to smoothness thresholds for sky occlusion. * This is useful because sky occlusion tends to be less noisy than GI, so less smoothing is needed to hide noise. */ float SkyOcclusionSmoothnessReduction; /** Largest radius an irradiance cache record can have. */ float MaxRecordRadius; /** * Task size for parallelization of irradiance cache population within a mapping. A mapping will be split into pieces of this size which allows other threads to help. * Smaller settings result in more redundant irradiance cache samples, but allow better parallelization. * Setting this to a large value like 4096 will effectively make the irradiance caching single threaded for a given mapping, which is useful for debugging. */ int32 CacheTaskSize; /** * Task size for parallelization of irradiance cache interpolation within a mapping. A mapping will be split into pieces of this size which allows other threads to help. * Smaller settings allow better parallelization. * Setting this to a large value like 4096 will effectively make the irradiance cache interpolation single threaded for a given mapping, which is useful for debugging. */ int32 InterpolateTaskSize; }; struct FDebugLightingInputData { /** Whether the solver should send stats back to Unreal */ bool bRelaySolverStats; /** Guid of the mapping to debug */ FGuid MappingGuid; /** Index of the BSP node to debug if the mapping is a BSP mapping */ int32 NodeIndex; /** World space position of the position that was clicked to select the debug sample */ FVector4f Position; /** Position in the texture mapping of the texel to debug */ int32 LocalX; int32 LocalY; /** Size of the texture mapping that was selected to debug */ int32 MappingSizeX; int32 MappingSizeY; /** Position of the camera */ FVector4f CameraPosition; /** VisibilityId of a component from the currently selected actor or BSP surface. */ int32 DebugVisibilityId; }; //---------------------------------------------------------------------------- // Scene export file header //---------------------------------------------------------------------------- struct FSceneFileHeader { /** FourCC cookie: 'SCEN' */ uint32 Cookie; FGuid FormatVersion; FGuid Guid; /** Settings for the GI solver */ FStaticLightingSettings GeneralSettings; FStaticLightingSceneConstants SceneConstants; FSceneMaterialSettings MaterialSettings; FMeshAreaLightSettings MeshAreaLightSettings; FAmbientOcclusionSettings AmbientOcclusionSettings; FDynamicObjectSettings DynamicObjectSettings; FVolumetricLightmapSettings VolumetricLightmapSettings; FPrecomputedVisibilitySettings PrecomputedVisibilitySettings; FVolumeDistanceFieldSettings VolumeDistanceFieldSettings; FStaticShadowSettings ShadowSettings; FImportanceTracingSettings ImportanceTracingSettings; FPhotonMappingSettings PhotonMappingSettings; FIrradianceCachingSettings IrradianceCachingSettings; FDebugLightingInputData DebugInput; FSceneFileHeader() {} /** Copy ctor that doesn't modify padding in FSceneFileHeader. */ FSceneFileHeader(const FSceneFileHeader& Other); /** If true, pad the mappings (shrink the requested size and then pad) */ uint32 bPadMappings:1; /** If true, draw a solid border as the padding around mappings */ uint32 bDebugPadding:1; /** If true, only calculate lighting on debugged texel's mappings */ uint32 bOnlyCalcDebugTexelMappings:1; /** If true, color lightmaps based on execution time (brighter red = slower) */ uint32 bColorByExecutionTime:1; /** If true, color lightmaps a random color */ uint32 bUseRandomColors:1; /** If true, a green border will be placed around the edges of mappings */ uint32 bColorBordersGreen:1; /** Amount of time to color full red (Color.R = Time / ExecutionTimeDivisor) */ float ExecutionTimeDivisor; int32 NumImportanceVolumes; int32 NumCharacterIndirectDetailVolumes; int32 NumVolumetricLightmapDensityVolumes; int32 NumPortals; int32 NumDirectionalLights; int32 NumPointLights; int32 NumSpotLights; int32 NumRectLights; int32 NumSkyLights; int32 NumStaticMeshes; int32 NumStaticMeshInstances; int32 NumFluidSurfaceInstances; int32 NumLandscapeInstances; int32 NumBSPMappings; int32 NumStaticMeshTextureMappings; int32 NumFluidSurfaceTextureMappings; int32 NumLandscapeTextureMappings; int32 NumSpeedTreeMappings; int32 NumVolumeMappings; int32 NumLandscapeVolumeMappings; int32 NumPrecomputedVisibilityBuckets; int32 NumVolumetricLightmapTasks; }; //---------------------------------------------------------------------------- // Base light struct //---------------------------------------------------------------------------- enum EDawnLightFlags { // maps to ULightComponent::CastShadows GI_LIGHT_CASTSHADOWS = 0x00000001, // maps to ULightComponent::HasStaticLighting() GI_LIGHT_HASSTATICLIGHTING = 0x00000002, // maps to ULightComponent::HasStaticShadowing() GI_LIGHT_HASSTATICSHADOWING = 0x00000008, // maps to ULightComponent::CastStaticShadows GI_LIGHT_CASTSTATICSHADOWS = 0x00000010, GI_LIGHT_STORE_SEPARATE_SHADOW_FACTOR = 0x00000020, GI_LIGHT_INVERSE_SQUARED = 0x00000080, GI_LIGHT_USE_LIGHTPROFILE = 0x00000100, // Whether a stationary light should generate a standard shadowmap (area shadows) or a distance field shadow map GI_LIGHT_USE_AREA_SHADOWS_FOR_SEPARATE_SHADOW_FACTOR = 0x00000200 }; struct FLightData { static const int32 LightProfileTextureDataSize = 256 * 256; FGuid Guid; /** Bit-wise combination of flags from EDawnLightFlags */ uint32 LightFlags; /** Homogeneous coordinates */ FVector4f Position; FVector4f Direction; FLinearColor Color; float Brightness; /** The radius of the light's surface, not the light's influence. */ float LightSourceRadius; /** The length of the light source*/ float LightSourceLength; /** Scale factor for the indirect lighting */ float IndirectLightingScale; /** 0 will be completely desaturated, 1 will be unchanged, 2 will be completely saturated */ float IndirectLightingSaturation; /** Controls the falloff of shadow penumbras */ float ShadowExponent; /** Scales resolution of the static shadowmap for this light. */ float ShadowResolutionScale; // @param WorldPosition position of the point to light in the world // @param LightPosition position of the light in the world // @param LightDirection direction at which the light is emitting (x axis) // @param LightTangent tangent to the direction at which the light is emitting (z axis) inline float ComputeLightProfileMultiplier(const TArray< uint8 >& LightProfileTextureData, FVector3f WorldPosition, FVector3f LightPosition, FVector3f LightDirection, FVector3f LightTangent) const { // optimization - only evaluate this function if needed if(LightFlags & Lightmass::GI_LIGHT_USE_LIGHTPROFILE) { FVector3f LightBitangent = FVector3f::CrossProduct( LightTangent, LightDirection ).GetSafeNormal(); FMatrix44f LightTransform = FMatrix44f( LightDirection, LightBitangent, LightTangent, FVector4f(0.f, 0.f, 0.f, 1.f) ); FMatrix44f InvLightTransform = LightTransform.GetTransposed(); FVector3f ToLight = (LightPosition - WorldPosition).GetSafeNormal(); FVector3f LocalToLight = InvLightTransform.TransformVector( ToLight ); // -1..1 float DotProd = FVector3f::DotProduct(ToLight, LightDirection); // -PI..PI (this distortion could be put into the texture but not without quality loss or more memory) float Angle = FMath::Asin(DotProd); // 0..1 float NormAngle = Angle / PI + 0.5f; float TangentAngle = FMath::Atan2( -LocalToLight.Z, -LocalToLight.Y ); // -Y represents 0/360 horizontal angle and we're rotating counter-clockwise float NormTangentAngle = TangentAngle / (PI * 2.f) + 0.5f; return FilterLightProfile( LightProfileTextureData, NormAngle, NormTangentAngle ); } return 1.0f; } private: // @param X clamped in range 0..1 // @return 0..1 inline float FilterLightProfile(const TArray< uint8 >& LightProfileTextureData, const float X, const float Y) const { const uint32 SizeX = FMath::Sqrt( static_cast(LightProfileTextureDataSize) ); const uint32 SizeY = LightProfileTextureDataSize / SizeX; // can be optimized // not 100% like GPU hardware but simple and almost the same float UnNormalizedX = FMath::Clamp(X * SizeX, 0.0f, (float)(SizeX - 1)); float UnNormalizedY = FMath::Clamp(Y * SizeY, 0.0f, (float)(SizeY - 1)); uint32 X0 = (uint32)UnNormalizedX; uint32 X1 = FMath::Min(X0 + 1, SizeX - 1); uint32 Y0 = (uint32)UnNormalizedY; uint32 Y1 = FMath::Min(Y0 + 1, SizeY - 1); float XFraction = UnNormalizedX - X0; float YFraction = UnNormalizedY - Y0; float V00 = LightProfileTextureData[Y0 * SizeX + X0] / 255.0f; float V10 = LightProfileTextureData[Y1 * SizeX + X0] / 255.0f; float V01 = LightProfileTextureData[Y0 * SizeX + X1] / 255.0f; float V11 = LightProfileTextureData[Y1 * SizeX + X1] / 255.0f; float V0 = FMath::Lerp(V00, V10, YFraction); float V1 = FMath::Lerp(V01, V11, YFraction); return FMath::Lerp(V0, V1, XFraction); } }; //---------------------------------------------------------------------------- // Direction light, extending FLightData //---------------------------------------------------------------------------- struct FDirectionalLightData { /** Angle that the directional light's emissive surface extends from any receiver position, in radians. */ float LightSourceAngle; }; //---------------------------------------------------------------------------- // Point light, extending FLightData //---------------------------------------------------------------------------- struct FPointLightData { float Radius; float FalloffExponent; // Point lights need an additional axis to specify the direction of IES profiles, also used by spot lights for the direction of tube lights FVector3f LightTangent; }; //---------------------------------------------------------------------------- // Spot light, extending FPointLightData //---------------------------------------------------------------------------- struct FSpotLightData { /** Unclamped, in degrees */ float InnerConeAngle; /** Unclamped, in degrees */ float OuterConeAngle; }; //---------------------------------------------------------------------------- // Sky light, extending FLightData //---------------------------------------------------------------------------- struct FSkyLightData { /** * Whether to use a filtered cubemap matching the Skylight Component's CubemapResolution to represent the skylight, or a 3rd order Spherical Harmonic. * The filtered cubemap is much more accurate than 3rd order SH, especially in mostly shadowed areas. */ bool bUseFilteredCubemap; int32 RadianceEnvironmentMapDataSize; FSHVectorRGB3 IrradianceEnvironmentMap; }; struct FRectLightData { uint32 SourceTextureSizeX; uint32 SourceTextureSizeY; FLinearColor SourceTextureAvgColor; }; //---------------------------------------------------------------------------- // Material //---------------------------------------------------------------------------- struct FMaterialElementData { /** Used to find Material on import */ FSHAHash MaterialHash; /** If true, this object will be lit as if it receives light from both sides of its polygons. */ uint32 bUseTwoSidedLighting:1; /** If true, this material element will only shadow indirect lighting. */ uint32 bShadowIndirectOnly:1; /** If true, allow using the emissive for static lighting. */ uint32 bUseEmissiveForStaticLighting:1; /** * Typically the triangle normal is used for hemisphere gathering which prevents incorrect self-shadowing from artist-tweaked vertex normals. * However in the case of foliage whose vertex normal has been setup to match the underlying terrain, gathering in the direction of the vertex normal is desired. */ uint32 bUseVertexNormalForHemisphereGather:1; /** Direct lighting falloff exponent for mesh area lights created from emissive areas on this primitive. */ float EmissiveLightFalloffExponent; /** * Direct lighting influence radius. * The default is 0, which means the influence radius should be automatically generated based on the emissive light brightness. * Values greater than 0 override the automatic method. */ float EmissiveLightExplicitInfluenceRadius; /** Scales the emissive contribution of this material. */ float EmissiveBoost; /** Scales the diffuse contribution of this material. */ float DiffuseBoost; /** * Fraction of the samples taken that have to be occluded before an occlusion value of 1 is reached for that texel. * A value of 1 means all the samples in the hemisphere have to be occluded, lower values darken areas that are not fully occluded. */ float FullyOccludedSamplesFraction; FMaterialElementData() : bUseTwoSidedLighting(false) , bShadowIndirectOnly(false) , bUseEmissiveForStaticLighting(true) , bUseVertexNormalForHemisphereGather(false) , EmissiveLightFalloffExponent(2.0f) , EmissiveLightExplicitInfluenceRadius(0.0f) , EmissiveBoost(1.0f) , DiffuseBoost(1.0f) , FullyOccludedSamplesFraction(1.0f) { } }; enum EMeshInstanceLightingFlags { /** Whether the mesh casts a shadow. */ GI_INSTANCE_CASTSHADOW = 1<<0, /** Whether the mesh uses a two-sided material. */ GI_INSTANCE_TWOSIDED = 1<<1, /** Whether the mesh only casts a shadow on itself. */ GI_INSTANCE_SELFSHADOWONLY = 1<<2, /** Whether to disable casting a shadow on itself. */ GI_INSTANCE_SELFSHADOWDISABLE = 1<<3 }; struct FStaticLightingMeshInstanceData { FGuid Guid; /** The number of triangles in the mesh, used for visibility testing. */ int32 NumTriangles; /** The number of shading triangles in the mesh. */ int32 NumShadingTriangles; /** The number of vertices in the mesh, used for visibility testing. */ int32 NumVertices; /** The number of shading vertices in the mesh. */ int32 NumShadingVertices; /** The texture coordinate index which is used to parametrize materials. */ int32 TextureCoordinateIndex; int32 MeshIndex; FGuid LevelGuid; uint32 LightingFlags; // EMeshInstanceLightingFlags bool bCastShadowAsTwoSided; /** Whether the mesh can be moved in game or not. */ bool bMovable; /** The lights which affect the mesh's primitive. */ int32 NumRelevantLights; /** The bounding box of the mesh. */ FBox3f BoundingBox; }; namespace ESplineMeshAxis { enum Type { X, Y, Z, }; } /** * Parameters used to transform a static mesh based on a spline. * Be sure to update this structure if spline functionality changes in Unreal! */ struct FSplineMeshParams { /** Start location of spline, in component space */ FVector3f StartPos; /** Start tangent of spline, in component space */ FVector3f StartTangent; /** X and Y scale applied to mesh at start of spline */ FVector2f StartScale; /** Roll around spline applied at start */ float StartRoll; /** Offset from the spline at start */ FVector2f StartOffset; /** End location of spline, in component space */ FVector3f EndPos; /** End tangent of spline, in component space */ FVector3f EndTangent; /** X and Y scale applied to mesh at end of spline */ FVector2f EndScale; /** Roll around spline applied at end */ float EndRoll; /** Offset from the base spline at end */ FVector2f EndOffset; /** Axis (in component space) that is used to determine X axis for co-ordinates along spline */ FVector3f SplineUpDir; /** Smoothly (cubic) interpolate the Roll and Scale params over spline. */ bool bSmoothInterpRollScale; /** Minimum Z value of the entire mesh */ float MeshMinZ; /** Range of Z values over entire mesh */ float MeshRangeZ; /** Chooses the forward axis for the spline mesh orientation */ TEnumAsByte ForwardAxis; }; struct FStaticMeshStaticLightingMeshData { /** The LOD this mesh represents. */ uint32 EncodedLODIndices; uint32 EncodedHLODRange; FMatrix44f LocalToWorld; /** true if the primitive has a transform which reverses the winding of its triangles. */ bool bReverseWinding; bool bShouldSelfShadow; FGuid StaticMeshGuid; bool bIsSplineMesh; FSplineMeshParams SplineParameters; }; struct FMinimalStaticLightingVertex { FVector4f WorldPosition; FVector4f WorldTangentZ; FVector2f TextureCoordinates[MAX_TEXCOORDS]; }; struct FStaticLightingVertexData : public FMinimalStaticLightingVertex { FVector4f WorldTangentX; FVector4f WorldTangentY; }; struct FBSPSurfaceStaticLightingData { FVector4f TangentX; FVector4f TangentY; FVector4f TangentZ; FMatrix44f MapToWorld; FMatrix44f WorldToMap; FGuid MaterialGuid; }; struct FStaticLightingMappingData { FGuid Guid; FGuid StaticLightingMeshInstance; }; struct FStaticLightingTextureMappingData { /** The width of the static lighting textures used by the mapping. */ int32 SizeX; /** The height of the static lighting textures used by the mapping. */ int32 SizeY; /** The lightmap texture coordinate index which is used for the mapping. */ int32 LightmapTextureCoordinateIndex; /** Whether to apply a bilinear filter to the sample or not. */ bool bBilinearFilter; }; struct FStaticLightingVertexMappingData { /** Lighting will be sampled at a random number of samples/surface area proportional to this factor. */ float SampleToAreaRatio; /** true to sample at vertices instead of on the surfaces. */ bool bSampleVertices; }; // // Fluid surfaces // struct FFluidSurfaceStaticLightingMeshData { /** The primitive's local to world transform. */ FMatrix44f LocalToWorld; /** The inverse transpose of the primitive's local to world transform. */ FMatrix44f LocalToWorldInverseTranspose; /** The mesh data of the fluid surface, which is represented as a quad. */ FVector4f QuadCorners[4]; FVector4f QuadUVCorners[4]; int32 QuadIndices[6]; }; // // Landscape // struct FLandscapeStaticLightingMeshData { /** The primitive's local to world transform. */ FMatrix44f LocalToWorld; int32 ComponentSizeQuads; float LightMapRatio; /** The number of quads we are expanding to eliminate seams. */ int32 ExpandQuadsX; int32 ExpandQuadsY; }; struct FVolumetricLightmapDensityVolumeData { FBox3f Bounds; FIntPoint AllowedMipLevelRange; int32 NumPlanes; }; #if !PLATFORM_MAC && !PLATFORM_LINUX #pragma pack(pop) #endif } // namespace Lightmass