ue4 lightmass研究
Posted shaojunping
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ue4 lightmass研究相关的知识,希望对你有一定的参考价值。
Exporter.cpp文件中:导出shadowDepthMap:
void FLightmassSolverExporter::ExportStaticShadowDepthMap(const FGuid& LightGuid, const FStaticShadowDepthMap& StaticShadowDepthMap) const { const FString ChannelName = CreateChannelName(LightGuid, LM_DOMINANTSHADOW_VERSION, LM_DOMINANTSHADOW_EXTENSION); const int32 ErrorCode = Swarm->OpenChannel(*ChannelName, LM_DOMINANTSHADOW_CHANNEL_FLAGS, true); if( ErrorCode >= 0 ) { Swarm->Write(&StaticShadowDepthMap, sizeof(FStaticShadowDepthMapData)); static_assert(sizeof(FStaticShadowDepthMapSample) == sizeof(FStaticShadowDepthMapSampleData), "ShadowDerivedSizeMustMatch"); WriteArray(StaticShadowDepthMap.ShadowMap); Swarm->CloseCurrentChannel(); } else { UE_LOG(LogLightmass, Log, TEXT("Failed to open static shadow depth map channel!")); } }
WriteArray函数是将TArray中的数据写道swarm栈的顶:
/** Writes a TArray to the channel on the top of the Swarm stack. */ template<class T> void FLightmassSolverExporter::WriteArray(const TArray<T>& Array) const { const int32 ArrayNum = Array.Num(); Swarm->Write((void*)&ArrayNum, sizeof(ArrayNum)); if (ArrayNum > 0) { Swarm->Write(Array.GetData(), Array.GetTypeSize() * ArrayNum); } }
输出staticLightData:
int32 FLightmassSolverExporter::BeginExportResults(struct FTextureMappingStaticLightingData& LightingData, uint32 NumMappings) const { const FString ChannelName = CreateChannelName(LightingData.Mapping->Guid, LM_TEXTUREMAPPING_VERSION, LM_TEXTUREMAPPING_EXTENSION); const int32 ErrorCode = Swarm->OpenChannel(*ChannelName, LM_TEXTUREMAPPING_CHANNEL_FLAGS, true); if( ErrorCode < 0 ) { UE_LOG(LogLightmass, Log, TEXT("Failed to open texture mapping channel %s!"), *ChannelName); } else { // Write out the number of mappings this channel will contain Swarm->Write(&NumMappings, sizeof(NumMappings)); } return ErrorCode; }
这个函数被ExportResults函数调用:
void FLightmassSolverExporter::ExportResults( FTextureMappingStaticLightingData& LightingData, bool bUseUniqueChannel ) const { UE_LOG(LogLightmass, Verbose, TEXT("Exporting texture lighting %s [%.3fs]"), *(LightingData.Mapping->Guid.ToString()), LightingData.ExecutionTime); // If requested, use a unique channel for this mapping, otherwise, just use the one that is already open if (bUseUniqueChannel) { if (BeginExportResults(LightingData, 1) < 0) { return; } } const int32 PaddedOffset = LightingData.Mapping->bPadded ? 1 : 0; const int32 DebugSampleIndex = LightingData.Mapping == Scene.DebugMapping ? (Scene.DebugInput.LocalY + PaddedOffset) * LightingData.Mapping->SizeX + Scene.DebugInput.LocalX + PaddedOffset : INDEX_NONE; if (bDumpTextures) { WriteBitmap<4>(*(LightingData.Mapping->Guid.ToString() + TEXT("_LM")), LightingData.LightMapData->GetData(), LightingData.LightMapData->GetSizeX(), LightingData.LightMapData->GetSizeY()); } // If we need to compress the data before writing out, do it now LightingData.LightMapData->Compress(DebugSampleIndex); // UE_LOG(LogLightmass, Log, TEXT("LM data went from %d to %d bytes"), LightingData.LightMapData->UncompressedDataSize, LightingData.LightMapData->CompressedDataSize); const int32 ShadowMapCount = LightingData.ShadowMaps.Num(); const int32 SignedDistanceFieldShadowMapCount = LightingData.SignedDistanceFieldShadowMaps.Num(); const int32 NumLights = LightingData.LightMapData->Lights.Num(); #pragma pack (push,1) struct FTextureHeader { FTextureHeader(FGuid& InGuid, double InExecutionTime, FLightMapData2DData& InData, int32 InShadowMapCount, int32 InSignedDistanceFieldShadowMapCount, int32 InLightCount) : Guid(InGuid), ExecutionTime(InExecutionTime), Data(InData), ShadowMapCount(InShadowMapCount), SignedDistanceFieldShadowMapCount(InSignedDistanceFieldShadowMapCount), LightCount(InLightCount) {} FGuid Guid; double ExecutionTime; FLightMapData2DData Data; int32 ShadowMapCount; int32 SignedDistanceFieldShadowMapCount; int32 LightCount; }; #pragma pack (pop) FTextureHeader Header(LightingData.Mapping->Guid, LightingData.ExecutionTime, *(FLightMapData2DData*)LightingData.LightMapData, LightingData.ShadowMaps.Num(), LightingData.SignedDistanceFieldShadowMaps.Num(), NumLights); Swarm->Write(&Header, sizeof(Header)); for (int32 LightIndex = 0; LightIndex < NumLights; LightIndex++) { FGuid CurrentGuid = LightingData.LightMapData->Lights[LightIndex]->Guid; Swarm->Write(&CurrentGuid, sizeof(CurrentGuid)); } // Write out compressed data if supported Swarm->Write(LightingData.LightMapData->GetCompressedData(), LightingData.LightMapData->CompressedDataSize ? LightingData.LightMapData->CompressedDataSize : LightingData.LightMapData->UncompressedDataSize); // The resulting light GUID --> shadow map data int32 ShadowIndex = 0; for (TMap<const FLight*,FSignedDistanceFieldShadowMapData2D*>::TIterator It(LightingData.SignedDistanceFieldShadowMaps); It; ++It, ++ShadowIndex) { FGuid OutGuid = It.Key()->Guid; FSignedDistanceFieldShadowMapData2D* OutData = It.Value(); // If we need to compress the data before writing out, do it now OutData->Compress(INDEX_NONE); Swarm->Write(&OutGuid, sizeof(FGuid)); Swarm->Write((FSignedDistanceFieldShadowMapData2DData*)OutData, sizeof(FSignedDistanceFieldShadowMapData2DData)); // Write out compressed data if supported Swarm->Write(OutData->GetCompressedData(), OutData->CompressedDataSize ? OutData->CompressedDataSize : OutData->UncompressedDataSize); } WriteDebugLightingOutput(LightingData.DebugOutput); // free up the calculated data delete LightingData.LightMapData; LightingData.ShadowMaps.Empty(); LightingData.SignedDistanceFieldShadowMaps.Empty(); // Only close the channel if we opened it if (bUseUniqueChannel) { EndExportResults(); } }
一个贴图映射的静态光照数据:
/** The static lighting data for a texture mapping. */ struct FTextureMappingStaticLightingData { FStaticLightingTextureMapping* Mapping; FLightMapData2D* LightMapData; TMap<const FLight*,FShadowMapData2D*> ShadowMaps; TMap<const FLight*,FSignedDistanceFieldShadowMapData2D*> SignedDistanceFieldShadowMaps; FDebugLightingOutput DebugOutput; /** Stores the time this mapping took to process */ double ExecutionTime; };
裏面shadowmapData2D类:
class FShadowMapData2D : public FShadowMapData2DData { public: FShadowMapData2D(uint32 InSizeX,uint32 InSizeY) : FShadowMapData2DData(InSizeX, InSizeY) , CompressedData(NULL) { Data.Empty(InSizeX * InSizeY); Data.AddZeroed(InSizeX * InSizeY); } virtual ~FShadowMapData2D(){ } // Accessors. const FShadowSample& operator()(uint32 X,uint32 Y) const { return Data[SizeX * Y + X]; } FShadowSample& operator()(uint32 X,uint32 Y) { return Data[SizeX * Y + X]; } uint32 GetSizeX() const { return SizeX; } uint32 GetSizeY() const { return SizeY; } // USurface interface virtual float GetSurfaceWidth() const { return SizeX; } virtual float GetSurfaceHeight() const { return SizeY; } void Quantize(int32 DebugSampleIndex); const FShadowSample* GetData() { return Data.GetData(); } const FQuantizedShadowSampleData* GetQuantizedData() { return QuantizedData.GetData(); } void Compress(int32 DebugSampleIndex); uint8* GetCompressedData() { return CompressedData; } private: TArray<FShadowSample> Data; TArray<FQuantizedShadowSampleData> QuantizedData; uint8* CompressedData; };
FSHadowSample类:
/** * A sample of the visibility factor between a light and a single point. */ class FShadowSample : public FShadowSampleData { public: FShadowSample operator-(const FShadowSample& SampleB) const { FShadowSample Result; Result.bIsMapped = bIsMapped; Result.Visibility = Visibility - SampleB.Visibility; return Result; } FShadowSample operator*(const float& Scalar) const { FShadowSample Result; Result.bIsMapped = bIsMapped; Result.Visibility = Visibility * Scalar; return Result; } };
lightmass的Export
StaticLightingTextureMapping继承了StaticLightingMapping、StaticLightingMappingData:
{
FStaticLightingMesh* Mesh; //和映射关联的mesh,用来计算静态光的mesh。
}
FStaticLightingMesh
{
TArray<FLight*> RelevantLights;
TArray<int32> VisibilityIds;
TArray<FMaterialElement, TInlineAllocator<5>> MaterialElements;
bool IsTranslucent(int32 ElementIndex)
bool IsMasked(int32 ElementIndex)
bool UsesTwoSidedLighting(int32 ElementIndex)
IsTwoSided(int32 ElementIndex)
bool UseVertexNormalForHemisphereGather(int32 ElementIndex)
virtual void GetTriangle(int32 TriangleIndex,FStaticLightingVertex& OutV0,FStaticLightingVertex& OutV1,FStaticLightingVertex& OutV2,int32& ElementIndex) const = 0;
virtual void GetShadingTriangle(int32 TriangleIndex,FStaticLightingVertex& OutV0,FStaticLightingVertex& OutV1,FStaticLightingVertex& OutV2,int32& ElementIndex) const
void GetTriangleIndices(int32 TriangleIndex,int32& OutI0,int32& OutI1,int32& OutI2)
FLinearColor EvaluateBRDF(
const FStaticLightingVertex& Vertex,
int32 ElementIndex,
const FVector4& IncomingDirection,
const FVector4& OutgoingDirection) const;
FLinearColor SampleBRDF(
const FStaticLightingVertex& Vertex,
int32 ElementIndex,
const FVector4& IncomingDirection,
FVector4& OutgoingDirection,
float& DirectionPDF,
FLMRandomStream& RandomStream
) const;
inline FLinearColor EvaluateEmissive(const FVector2D& UVs, int32 ElementIndex) const;
inline FLinearColor EvaluateDiffuse(const FVector2D& UVs, int32 ElementIndex) const;
}
用一个空level, 添加一个点光源和一个cube,进行测试,build lightt后生成一张256*256的HQ_Lightmap_1_1和LQ_Lightmap_1_1。前者包含A通道,后者不包含。一张256*128的ShadowMapTexture2D_2,包含R和G通道。一张64*64
的HQ_Lightmap_1_2和LQ_Lightmap_1_2。一张32*32的shadowmapTexture2D_3,4个通道都有东西,东西差不多一样。
空level什么都不添加,build lightt后生成一张256*256的HQ_Lightmap_1_1和LQ_Lightmap_1_1。前者包含A通道,后者不包含。一张128*128的ShadowMapTexture2D_2,包含4个通道,东西一样。一张64*64的HQ_Lightmap_1_2和LQ_Lightmap_1_2。一张32*32的shadowmapTexture2D_3,4个通道都有东西,东西差不多一样。
综合,不同的地方:1. ShadowMapTexture2D_2的大小;2.ShadowMapTexture2D_2的通道数。
void UEditorEngine::BuildLighting(const FLightingBuildOptions& Options)函数是编辑器按build lighting only触发的,里面调用了OnLightingBUildStarted.Broadcast()和FStaticLightingManager::Get()->createStaticLightingSystem(Options);
createStaticLIghtingSystem函数里StaticLightingSystems数组放置光照系统(如果level是光照场景,则每个level场景一个)。然后第一个静态光照系统作为激活的系统,这个系统开启lightmass程序,下面的函数:
FStaticLightingSystem::BeginLightmassProcess()里面包含 创建lightmass进程(CreateLIghtmassProcessor函数,启动swarm,新建lightmass、关联到swarm),GatherScene函数(lightmassExporter的levelSetting、没用的局部核心、品质等级、level名称、重要度体积、角色间接细节体积、立体lightmap密度体积、lightmassPortal、mesh、mapping、light),初始化lightmass进程(InitiateLightmassProcessor函数)。
以上是关于ue4 lightmass研究的主要内容,如果未能解决你的问题,请参考以下文章
[工作积累] UE4 并行渲染的同步 - Sync between FParallelCommandListSet & FRHICommandListImmediate calls(代码片段
Unreal4 Lightmass 基础知识及间接光照缓存0039bate1