FDeferredShadingSceneRenderer::FDeferredShadingSceneRenderer(const FSceneViewFamily* InViewFamily,FHitProxyConsumer* HitProxyConsumer) : FSceneRenderer(InViewFamily, HitProxyConsumer) , EarlyZPassMode(DDM_NonMaskedOnly) , TranslucentSelfShadowLayout(0, 0, 0, 0) , CachedTranslucentSelfShadowLightId(INDEX_NONE) { if (FPlatformProperties::SupportsWindowedMode()) { // Use a depth only pass if we are using full blown HQ lightmaps // Otherwise base pass pixel shaders will be cheap and there will be little benefit to rendering a depth only pass if (AllowHighQualityLightmaps() || !ViewFamily.EngineShowFlags.Lighting) { EarlyZPassMode = DDM_None; } } // Shader complexity requires depth only pass to display masked material cost correctly if (ViewFamily.EngineShowFlags.ShaderComplexity) { EarlyZPassMode = DDM_AllOccluders; } // developer override, good for profiling, can be useful as project setting { static const auto ICVar = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.EarlyZPass")); const int32 CVarValue = ICVar->GetValueOnGameThread(); switch(CVarValue) { case 0: EarlyZPassMode = DDM_None; break; case 1: EarlyZPassMode = DDM_NonMaskedOnly; break; case 2: EarlyZPassMode = DDM_AllOccluders; break; } } }
void FBasePassForwardOpaqueDrawingPolicyFactory::AddStaticMesh(FRHICommandList& RHICmdList, FScene* Scene, FStaticMesh* StaticMesh) { // Determine the mesh's material and blend mode. const auto FeatureLevel = Scene->GetFeatureLevel(); const FMaterial* Material = StaticMesh->MaterialRenderProxy->GetMaterial(FeatureLevel); const EBlendMode BlendMode = Material->GetBlendMode(); // Only draw opaque materials. if( !IsTranslucentBlendMode(BlendMode) ) { // following check moved from ProcessBasePassMeshForForwardShading to avoid passing feature level. check(!AllowHighQualityLightmaps(Scene->GetFeatureLevel())); ProcessBasePassMeshForForwardShading( RHICmdList, FProcessBasePassMeshParameters( *StaticMesh, Material, StaticMesh->PrimitiveSceneInfo->Proxy, true, false, ESceneRenderTargetsMode::DontSet, FeatureLevel ), FDrawBasePassForwardShadingStaticMeshAction(Scene,StaticMesh) ); } }
/** * Initializes system settings and included texture LOD settings. * * @param bSetupForEditor Whether to initialize settings for Editor */ void FSystemSettings::Initialize( bool bSetupForEditor ) { TestBitFieldFunctions(); RegisterShowFlagConsoleVariables(); // Load the settings that will be the default for every other compat level, and the editor, and the other split screen levels. FSystemSettingsData DefaultSettings; DefaultSettings.LoadFromIni(GetSectionName(false), GEngineIni, false); (FSystemSettingsData&)(*this) = DefaultSettings; LoadFromIni(); ApplyOverrides(); bInitialUseHighQualityLightmaps = AllowHighQualityLightmaps(); IConsoleManager::Get().RegisterConsoleVariableSink(FConsoleCommandDelegate::CreateRaw(this, &FSystemSettings::CVarSink)); // intialize a critical texture streaming value used by texture loading, etc int32 MinTextureResidentMipCount = 1; verify(GConfig->GetInt(TEXT("TextureStreaming"), TEXT("MinTextureResidentMipCount"), MinTextureResidentMipCount, GEngineIni)); UTexture2D::SetMinTextureResidentMipCount(MinTextureResidentMipCount); }
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); } } }
bool FLightMapDensityDrawingPolicyFactory::DrawDynamicMesh( FRHICommandList& RHICmdList, const FViewInfo& View, ContextType DrawingContext, const FMeshBatch& Mesh, bool bBackFace, bool bPreFog, const FPrimitiveSceneProxy* PrimitiveSceneProxy, FHitProxyId HitProxyId ) { bool bDirty = false; const auto FeatureLevel = View.GetFeatureLevel(); const FMaterialRenderProxy* MaterialRenderProxy = Mesh.MaterialRenderProxy; const FMaterial* Material = MaterialRenderProxy->GetMaterial(FeatureLevel); const EBlendMode BlendMode = Material->GetBlendMode(); const FMeshDrawingRenderState DrawRenderState(Mesh.DitheredLODTransitionAlpha); const bool bMaterialMasked = Material->IsMasked(); const bool bMaterialModifiesMesh = Material->MaterialModifiesMeshPosition_RenderThread(); if (!bMaterialMasked && !bMaterialModifiesMesh) { // Override with the default material for opaque materials that are not two sided MaterialRenderProxy = GEngine->LevelColorationLitMaterial->GetRenderProxy(false); } bool bIsLitMaterial = (Material->GetShadingModel() != MSM_Unlit); /*const */FLightMapInteraction LightMapInteraction = (Mesh.LCI && bIsLitMaterial) ? Mesh.LCI->GetLightMapInteraction(FeatureLevel) : FLightMapInteraction(); // force simple lightmaps based on system settings bool bAllowHighQualityLightMaps = AllowHighQualityLightmaps(FeatureLevel) && LightMapInteraction.AllowsHighQualityLightmaps(); if (bIsLitMaterial && PrimitiveSceneProxy && (LightMapInteraction.GetType() == LMIT_Texture)) { // Should this object be texture lightmapped? Ie, is lighting not built for it?? bool bUseDummyLightMapPolicy = Mesh.LCI == NULL || Mesh.LCI->GetLightMapInteraction(FeatureLevel).GetType() != LMIT_Texture; if (!bUseDummyLightMapPolicy) { if (bAllowHighQualityLightMaps) { TLightMapDensityDrawingPolicy< TUniformLightMapPolicy<LMP_HQ_LIGHTMAP> > DrawingPolicy(View, Mesh.VertexFactory, MaterialRenderProxy, TUniformLightMapPolicy<LMP_HQ_LIGHTMAP>(), BlendMode); RHICmdList.BuildAndSetLocalBoundShaderState(DrawingPolicy.GetBoundShaderStateInput(FeatureLevel)); DrawingPolicy.SetSharedState(RHICmdList, &View, TLightMapDensityDrawingPolicy< FUniformLightMapPolicy >::ContextDataType()); for (int32 BatchElementIndex = 0; BatchElementIndex < Mesh.Elements.Num(); BatchElementIndex++) { DrawingPolicy.SetMeshRenderState(RHICmdList, View,PrimitiveSceneProxy,Mesh,BatchElementIndex,bBackFace,DrawRenderState, Mesh.LCI, TLightMapDensityDrawingPolicy<FUniformLightMapPolicy>::ContextDataType() ); DrawingPolicy.DrawMesh(RHICmdList, Mesh,BatchElementIndex); } bDirty = true; } else { TLightMapDensityDrawingPolicy< TUniformLightMapPolicy<LMP_LQ_LIGHTMAP> > DrawingPolicy(View, Mesh.VertexFactory, MaterialRenderProxy, TUniformLightMapPolicy<LMP_LQ_LIGHTMAP>(), BlendMode); RHICmdList.BuildAndSetLocalBoundShaderState(DrawingPolicy.GetBoundShaderStateInput(FeatureLevel)); DrawingPolicy.SetSharedState(RHICmdList, &View, TLightMapDensityDrawingPolicy< FUniformLightMapPolicy >::ContextDataType()); for (int32 BatchElementIndex = 0; BatchElementIndex < Mesh.Elements.Num(); BatchElementIndex++) { DrawingPolicy.SetMeshRenderState(RHICmdList, View,PrimitiveSceneProxy,Mesh,BatchElementIndex,bBackFace,DrawRenderState, Mesh.LCI, TLightMapDensityDrawingPolicy<FUniformLightMapPolicy>::ContextDataType() ); DrawingPolicy.DrawMesh(RHICmdList, Mesh,BatchElementIndex); } bDirty = true; } } else { TLightMapDensityDrawingPolicy<TUniformLightMapPolicy<LMP_DUMMY> > DrawingPolicy(View, Mesh.VertexFactory, MaterialRenderProxy, TUniformLightMapPolicy<LMP_DUMMY>(), BlendMode); RHICmdList.BuildAndSetLocalBoundShaderState(DrawingPolicy.GetBoundShaderStateInput(FeatureLevel)); DrawingPolicy.SetSharedState(RHICmdList, &View, TLightMapDensityDrawingPolicy<FUniformLightMapPolicy >::ContextDataType()); for (int32 BatchElementIndex = 0; BatchElementIndex < Mesh.Elements.Num(); BatchElementIndex++) { DrawingPolicy.SetMeshRenderState(RHICmdList, View,PrimitiveSceneProxy,Mesh,BatchElementIndex,bBackFace,DrawRenderState, Mesh.LCI, TLightMapDensityDrawingPolicy<FUniformLightMapPolicy>::ContextDataType() ); DrawingPolicy.DrawMesh(RHICmdList, Mesh,BatchElementIndex); } bDirty = true; } } else { TLightMapDensityDrawingPolicy<TUniformLightMapPolicy<LMP_NO_LIGHTMAP> > DrawingPolicy(View, Mesh.VertexFactory, MaterialRenderProxy, TUniformLightMapPolicy<LMP_NO_LIGHTMAP>(), BlendMode); RHICmdList.BuildAndSetLocalBoundShaderState(DrawingPolicy.GetBoundShaderStateInput(FeatureLevel)); DrawingPolicy.SetSharedState(RHICmdList, &View, TLightMapDensityDrawingPolicy<TUniformLightMapPolicy<LMP_NO_LIGHTMAP> >::ContextDataType()); for (int32 BatchElementIndex = 0; BatchElementIndex < Mesh.Elements.Num(); BatchElementIndex++) { DrawingPolicy.SetMeshRenderState(RHICmdList, View,PrimitiveSceneProxy,Mesh,BatchElementIndex,bBackFace,DrawRenderState, Mesh.LCI, TLightMapDensityDrawingPolicy<FUniformLightMapPolicy>::ContextDataType() ); DrawingPolicy.DrawMesh(RHICmdList, Mesh,BatchElementIndex); } bDirty = true; } return bDirty; }
void GetPrecomputedLightingParameters( ERHIFeatureLevel::Type FeatureLevel, FPrecomputedLightingParameters& Parameters, const FIndirectLightingCache* LightingCache, const FIndirectLightingCacheAllocation* LightingAllocation, const FLightCacheInterface* LCI ) { // FCachedVolumeIndirectLightingPolicy, FCachedPointIndirectLightingPolicy { if (LightingAllocation) { Parameters.IndirectLightingCachePrimitiveAdd = LightingAllocation->Add; Parameters.IndirectLightingCachePrimitiveScale = LightingAllocation->Scale; Parameters.IndirectLightingCacheMinUV = LightingAllocation->MinUV; Parameters.IndirectLightingCacheMaxUV = LightingAllocation->MaxUV; Parameters.PointSkyBentNormal = LightingAllocation->CurrentSkyBentNormal; Parameters.DirectionalLightShadowing = LightingAllocation->CurrentDirectionalShadowing; for (uint32 i = 0; i < sizeof(FSHVectorRGB2) / sizeof(FVector4); ++i) { Parameters.IndirectLightingSHCoefficients[i] = LightingAllocation->SingleSamplePacked[i]; } Parameters.IndirectLightingSHSingleCoefficient = FVector4(LightingAllocation->SingleSamplePacked[0].X, LightingAllocation->SingleSamplePacked[1].X, LightingAllocation->SingleSamplePacked[2].X) * FSHVector2::ConstantBasisIntegral * .5f; //@todo - why is .5f needed to match directional? } else { Parameters.IndirectLightingCachePrimitiveAdd = FVector(0, 0, 0); Parameters.IndirectLightingCachePrimitiveScale = FVector(1, 1, 1); Parameters.IndirectLightingCacheMinUV = FVector(0, 0, 0); Parameters.IndirectLightingCacheMaxUV = FVector(1, 1, 1); Parameters.PointSkyBentNormal = FVector4(0, 0, 1, 1); Parameters.DirectionalLightShadowing = 1; for (uint32 i = 0; i < sizeof(FSHVectorRGB2) / sizeof(FVector4); ++i) { Parameters.IndirectLightingSHCoefficients[i] = FVector4(0, 0, 0, 0); } Parameters.IndirectLightingSHSingleCoefficient = FVector4(0, 0, 0, 0); } // If we are using FCachedVolumeIndirectLightingPolicy then InitViews should have updated the lighting cache which would have initialized it // However the conditions for updating the lighting cache are complex and fail very occasionally in non-reproducible ways // Silently skipping setting the cache texture under failure for now if (FeatureLevel >= ERHIFeatureLevel::SM4 && LightingCache && LightingCache->IsInitialized()) { Parameters.IndirectLightingCacheTexture0 = const_cast<FIndirectLightingCache*>(LightingCache)->GetTexture0().ShaderResourceTexture; Parameters.IndirectLightingCacheTexture1 = const_cast<FIndirectLightingCache*>(LightingCache)->GetTexture1().ShaderResourceTexture; Parameters.IndirectLightingCacheTexture2 = const_cast<FIndirectLightingCache*>(LightingCache)->GetTexture2().ShaderResourceTexture; Parameters.IndirectLightingCacheTextureSampler0 = TStaticSamplerState<SF_Bilinear,AM_Clamp,AM_Clamp,AM_Clamp>::GetRHI(); Parameters.IndirectLightingCacheTextureSampler1 = TStaticSamplerState<SF_Bilinear,AM_Clamp,AM_Clamp,AM_Clamp>::GetRHI(); Parameters.IndirectLightingCacheTextureSampler2 = TStaticSamplerState<SF_Bilinear,AM_Clamp,AM_Clamp,AM_Clamp>::GetRHI(); } else if (FeatureLevel >= ERHIFeatureLevel::ES3_1) { Parameters.IndirectLightingCacheTexture0 = GBlackVolumeTexture->TextureRHI; Parameters.IndirectLightingCacheTexture1 = GBlackVolumeTexture->TextureRHI; Parameters.IndirectLightingCacheTexture2 = GBlackVolumeTexture->TextureRHI; Parameters.IndirectLightingCacheTextureSampler0 = GBlackVolumeTexture->SamplerStateRHI; Parameters.IndirectLightingCacheTextureSampler1 = GBlackVolumeTexture->SamplerStateRHI; Parameters.IndirectLightingCacheTextureSampler2 = GBlackVolumeTexture->SamplerStateRHI; } else { Parameters.IndirectLightingCacheTexture0 = GBlackTexture->TextureRHI; Parameters.IndirectLightingCacheTexture1 = GBlackTexture->TextureRHI; Parameters.IndirectLightingCacheTexture2 = GBlackTexture->TextureRHI; Parameters.IndirectLightingCacheTextureSampler0 = GBlackTexture->SamplerStateRHI; Parameters.IndirectLightingCacheTextureSampler1 = GBlackTexture->SamplerStateRHI; Parameters.IndirectLightingCacheTextureSampler2 = GBlackTexture->SamplerStateRHI; } } // TDistanceFieldShadowsAndLightMapPolicy const FShadowMapInteraction ShadowMapInteraction = LCI ? LCI->GetShadowMapInteraction() : FShadowMapInteraction(); if (ShadowMapInteraction.GetType() == SMIT_Texture) { const UShadowMapTexture2D* ShadowMapTexture = ShadowMapInteraction.GetTexture(); Parameters.ShadowMapCoordinateScaleBias = FVector4(ShadowMapInteraction.GetCoordinateScale(), ShadowMapInteraction.GetCoordinateBias()); Parameters.StaticShadowMapMasks = FVector4(ShadowMapInteraction.GetChannelValid(0), ShadowMapInteraction.GetChannelValid(1), ShadowMapInteraction.GetChannelValid(2), ShadowMapInteraction.GetChannelValid(3)); Parameters.InvUniformPenumbraSizes = ShadowMapInteraction.GetInvUniformPenumbraSize(); Parameters.StaticShadowTexture = ShadowMapTexture ? ShadowMapTexture->TextureReference.TextureReferenceRHI.GetReference() : GWhiteTexture->TextureRHI; Parameters.StaticShadowTextureSampler = ShadowMapTexture ? ShadowMapTexture->Resource->SamplerStateRHI : GWhiteTexture->SamplerStateRHI; } else { Parameters.StaticShadowMapMasks = FVector4(1, 1, 1, 1); Parameters.InvUniformPenumbraSizes = FVector4(0, 0, 0, 0); Parameters.StaticShadowTexture = GWhiteTexture->TextureRHI; Parameters.StaticShadowTextureSampler = GWhiteTexture->SamplerStateRHI; } // TLightMapPolicy const FLightMapInteraction LightMapInteraction = LCI ? LCI->GetLightMapInteraction(FeatureLevel) : FLightMapInteraction(); if (LightMapInteraction.GetType() == LMIT_Texture) { const bool bAllowHighQualityLightMaps = AllowHighQualityLightmaps(FeatureLevel) && LightMapInteraction.AllowsHighQualityLightmaps(); // Vertex Shader const FVector2D LightmapCoordinateScale = LightMapInteraction.GetCoordinateScale(); const FVector2D LightmapCoordinateBias = LightMapInteraction.GetCoordinateBias(); Parameters.LightMapCoordinateScaleBias = FVector4(LightmapCoordinateScale.X, LightmapCoordinateScale.Y, LightmapCoordinateBias.X, LightmapCoordinateBias.Y); // Pixel Shader const ULightMapTexture2D* LightMapTexture = LightMapInteraction.GetTexture(bAllowHighQualityLightMaps); const ULightMapTexture2D* SkyOcclusionTexture = LightMapInteraction.GetSkyOcclusionTexture(); const ULightMapTexture2D* AOMaterialMaskTexture = LightMapInteraction.GetAOMaterialMaskTexture(); Parameters.LightMapTexture = LightMapTexture ? LightMapTexture->TextureReference.TextureReferenceRHI.GetReference() : GBlackTexture->TextureRHI; Parameters.SkyOcclusionTexture = SkyOcclusionTexture ? SkyOcclusionTexture->TextureReference.TextureReferenceRHI.GetReference() : GWhiteTexture->TextureRHI; Parameters.AOMaterialMaskTexture = AOMaterialMaskTexture ? AOMaterialMaskTexture->TextureReference.TextureReferenceRHI.GetReference() : GBlackTexture->TextureRHI; Parameters.LightMapSampler = LightMapTexture ? LightMapTexture->Resource->SamplerStateRHI : GBlackTexture->SamplerStateRHI; Parameters.SkyOcclusionSampler = SkyOcclusionTexture ? SkyOcclusionTexture->Resource->SamplerStateRHI : GWhiteTexture->SamplerStateRHI; Parameters.AOMaterialMaskSampler = AOMaterialMaskTexture ? AOMaterialMaskTexture->Resource->SamplerStateRHI : GBlackTexture->SamplerStateRHI; const uint32 NumCoef = bAllowHighQualityLightMaps ? NUM_HQ_LIGHTMAP_COEF : NUM_LQ_LIGHTMAP_COEF; const FVector4* Scales = LightMapInteraction.GetScaleArray(); const FVector4* Adds = LightMapInteraction.GetAddArray(); for (uint32 CoefIndex = 0; CoefIndex < NumCoef; ++CoefIndex) { Parameters.LightMapScale[CoefIndex] = Scales[CoefIndex]; Parameters.LightMapAdd[CoefIndex] = Adds[CoefIndex]; } } else { // Vertex Shader Parameters.LightMapCoordinateScaleBias = FVector4(1, 1, 0, 0); // Pixel Shader Parameters.LightMapTexture = GBlackTexture->TextureRHI; Parameters.SkyOcclusionTexture = GWhiteTexture->TextureRHI; Parameters.AOMaterialMaskTexture = GBlackTexture->TextureRHI; Parameters.LightMapSampler = GBlackTexture->SamplerStateRHI; Parameters.SkyOcclusionSampler = GWhiteTexture->SamplerStateRHI; Parameters.AOMaterialMaskSampler = GBlackTexture->SamplerStateRHI; const uint32 NumCoef = FMath::Max<uint32>(NUM_HQ_LIGHTMAP_COEF, NUM_LQ_LIGHTMAP_COEF); for (uint32 CoefIndex = 0; CoefIndex < NumCoef; ++CoefIndex) { Parameters.LightMapScale[CoefIndex] = FVector4(1, 1, 1, 1); Parameters.LightMapAdd[CoefIndex] = FVector4(0, 0, 0, 0); } } }
FArchive& operator<<(FArchive& Ar,FPrecomputedLightVolume& Volume) { if (Ar.IsCountingMemory()) { const int32 AllocatedBytes = Volume.GetAllocatedBytes(); Ar.CountBytes(AllocatedBytes, AllocatedBytes); } else if (Ar.IsLoading()) { Ar << Volume.bInitialized; if (Volume.bInitialized) { FBox Bounds; Ar << Bounds; float SampleSpacing = 0.0f; Ar << SampleSpacing; Volume.Initialize(Bounds); TArray<FVolumeLightingSample> HighQualitySamples; // Deserialize samples as an array, and add them to the octree Ar << HighQualitySamples; if (FPlatformProperties::SupportsHighQualityLightmaps() && (GIsEditor || AllowHighQualityLightmaps(GMaxRHIFeatureLevel))) { for(int32 SampleIndex = 0; SampleIndex < HighQualitySamples.Num(); SampleIndex++) { Volume.AddHighQualityLightingSample(HighQualitySamples[SampleIndex]); } } TArray<FVolumeLightingSample> LowQualitySamples; if (Ar.UE4Ver() >= VER_UE4_VOLUME_SAMPLE_LOW_QUALITY_SUPPORT) { Ar << LowQualitySamples; } if (FPlatformProperties::SupportsLowQualityLightmaps() && (GIsEditor || !AllowHighQualityLightmaps(GMaxRHIFeatureLevel))) { for(int32 SampleIndex = 0; SampleIndex < LowQualitySamples.Num(); SampleIndex++) { Volume.AddLowQualityLightingSample(LowQualitySamples[SampleIndex]); } } Volume.FinalizeSamples(); } } else if (Ar.IsSaving()) { Ar << Volume.bInitialized; if (Volume.bInitialized) { Ar << Volume.Bounds; float SampleSpacing = 0.0f; Ar << SampleSpacing; TArray<FVolumeLightingSample> HighQualitySamples; if (!Ar.IsCooking() || Ar.CookingTarget()->SupportsFeature(ETargetPlatformFeatures::HighQualityLightmaps)) { // Gather an array of samples from the octree for(FLightVolumeOctree::TConstIterator<> NodeIt(Volume.HighQualityLightmapOctree); NodeIt.HasPendingNodes(); NodeIt.Advance()) { const FLightVolumeOctree::FNode& CurrentNode = NodeIt.GetCurrentNode(); FOREACH_OCTREE_CHILD_NODE(ChildRef) { if(CurrentNode.HasChild(ChildRef)) { NodeIt.PushChild(ChildRef); } } for (FLightVolumeOctree::ElementConstIt ElementIt(CurrentNode.GetElementIt()); ElementIt; ++ElementIt) { const FVolumeLightingSample& Sample = *ElementIt; HighQualitySamples.Add(Sample); } } } Ar << HighQualitySamples; TArray<FVolumeLightingSample> LowQualitySamples; if (!Ar.IsCooking() || Ar.CookingTarget()->SupportsFeature(ETargetPlatformFeatures::LowQualityLightmaps)) { // Gather an array of samples from the octree for(FLightVolumeOctree::TConstIterator<> NodeIt(Volume.LowQualityLightmapOctree); NodeIt.HasPendingNodes(); NodeIt.Advance()) { const FLightVolumeOctree::FNode& CurrentNode = NodeIt.GetCurrentNode(); FOREACH_OCTREE_CHILD_NODE(ChildRef) { if(CurrentNode.HasChild(ChildRef)) { NodeIt.PushChild(ChildRef); } } for (FLightVolumeOctree::ElementConstIt ElementIt(CurrentNode.GetElementIt()); ElementIt; ++ElementIt) { const FVolumeLightingSample& Sample = *ElementIt; LowQualitySamples.Add(Sample); } } } Ar << LowQualitySamples; }