Ejemplo n.º 1
0
void FSceneRenderer::InitFogConstants()
{
	// console command override
	float FogDensityOverride = -1.0f;
	float FogStartDistanceOverride = -1.0f;

#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
	{
		// console variable overrides
		FogDensityOverride = CVarFogDensity.GetValueOnAnyThread();
		FogStartDistanceOverride = CVarFogStartDistance.GetValueOnAnyThread();
	}
#endif // !(UE_BUILD_SHIPPING || UE_BUILD_TEST)

	for(int32 ViewIndex = 0;ViewIndex < Views.Num();ViewIndex++)
	{
		FViewInfo& View = Views[ViewIndex];
		// set fog consts based on height fog components
		if(ShouldRenderFog(*View.Family))
		{
			if (Scene->ExponentialFogs.Num() > 0)
			{
				const FExponentialHeightFogSceneInfo& FogInfo = Scene->ExponentialFogs[0];
				const float CosTerminatorAngle = FMath::Clamp(FMath::Cos(FogInfo.LightTerminatorAngle * PI / 180.0f), -1.0f + DELTA, 1.0f - DELTA);
				const float CollapsedFogParameterPower = FMath::Clamp(
						-FogInfo.FogHeightFalloff * (View.ViewMatrices.ViewOrigin.Z - FogInfo.FogHeight),
						-126.f + 1.f, // min and max exponent values for IEEE floating points (http://en.wikipedia.org/wiki/IEEE_floating_point)
						+127.f - 1.f
						);
				const float CollapsedFogParameter = FogInfo.FogDensity * FMath::Pow(2.0f, CollapsedFogParameterPower);
				View.ExponentialFogParameters = FVector4(CollapsedFogParameter, FogInfo.FogHeightFalloff, CosTerminatorAngle, FogInfo.StartDistance);
				View.ExponentialFogColor = FVector(FogInfo.FogColor.R, FogInfo.FogColor.G, FogInfo.FogColor.B);
				View.FogMaxOpacity = FogInfo.FogMaxOpacity;

				View.DirectionalInscatteringExponent = FogInfo.DirectionalInscatteringExponent;
				View.DirectionalInscatteringStartDistance = FogInfo.DirectionalInscatteringStartDistance;
				View.bUseDirectionalInscattering = false;
				View.InscatteringLightDirection = FVector(0);

				for (TSparseArray<FLightSceneInfoCompact>::TConstIterator It(Scene->Lights); It; ++It)
				{
					const FLightSceneInfoCompact& LightInfo = *It;

					// This will find the first directional light that is set to be used as an atmospheric sun light of sufficient brightness.
					// If you have more than one directional light with these properties then all subsequent lights will be ignored.
					if (LightInfo.LightSceneInfo->Proxy->GetLightType() == LightType_Directional
						&& LightInfo.LightSceneInfo->Proxy->IsUsedAsAtmosphereSunLight()
						&& LightInfo.LightSceneInfo->Proxy->GetColor().ComputeLuminance() > KINDA_SMALL_NUMBER
						&& FogInfo.DirectionalInscatteringColor.ComputeLuminance() > KINDA_SMALL_NUMBER)
					{
						View.InscatteringLightDirection = -LightInfo.LightSceneInfo->Proxy->GetDirection();
						View.bUseDirectionalInscattering = true;
						View.DirectionalInscatteringColor = FogInfo.DirectionalInscatteringColor * LightInfo.LightSceneInfo->Proxy->GetColor().ComputeLuminance();
						break;
					}
				}
			}
		}
	}
}
/** 
* Renders the view family. 
*/
void FDeferredShadingSceneRenderer::Render()
{
	if(!ViewFamily.EngineShowFlags.Rendering)
	{
		return;
	}

	SCOPED_DRAW_EVENT(Scene,DEC_SCENE_ITEMS);

	// Initialize global system textures (pass-through if already initialized).
	GSystemTextures.InitializeTextures();

	// Allocate the maximum scene render target space for the current view family.
	GSceneRenderTargets.Allocate(ViewFamily);

	// Find the visible primitives.
	InitViews();

	const bool bIsWireframe = ViewFamily.EngineShowFlags.Wireframe;

	static const auto ClearMethodCVar = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.ClearSceneMethod"));
	bool bRequiresRHIClear = true;
	bool bRequiresFarZQuadClear = false;

	if (ClearMethodCVar)
	{
		switch (ClearMethodCVar->GetValueOnRenderThread())
		{
		case 0: // No clear
			{
				bRequiresRHIClear = false;
				bRequiresFarZQuadClear = false;
				break;
			}
		
		case 1: // RHIClear
			{
				bRequiresRHIClear = true;
				bRequiresFarZQuadClear = false;
				break;
			}

		case 2: // Clear using far-z quad
			{
				bRequiresFarZQuadClear = true;
				bRequiresRHIClear = false;
				break;
			}
		}
	}

	// Always perform a full buffer clear for wireframe, shader complexity view mode, and stationary light overlap viewmode.
	if (bIsWireframe || ViewFamily.EngineShowFlags.ShaderComplexity || ViewFamily.EngineShowFlags.StationaryLightOverlap)
	{
		bRequiresRHIClear = true;
	}

	// force using occ queries for wireframe if rendering is parented or frozen in the first view
	check(Views.Num());
	#if (UE_BUILD_SHIPPING || UE_BUILD_TEST)
		const bool bIsViewFrozen = false;
		const bool bHasViewParent = false;
	#else
		const bool bIsViewFrozen = Views[0].State && ((FSceneViewState*)Views[0].State)->bIsFrozen;
		const bool bHasViewParent = Views[0].State && ((FSceneViewState*)Views[0].State)->HasViewParent();
	#endif
	const bool bIsOcclusionTesting = DoOcclusionQueries() && (!bIsWireframe || bIsViewFrozen || bHasViewParent);

	// Dynamic vertex and index buffers need to be committed before rendering.
	FGlobalDynamicVertexBuffer::Get().Commit();
	FGlobalDynamicIndexBuffer::Get().Commit();

	// Notify the FX system that the scene is about to be rendered.
	if (Scene->FXSystem)
	{
		Scene->FXSystem->PreRender();
	}

	// Draw the scene pre-pass / early z pass, populating the scene depth buffer and HiZ
	RenderPrePass();
	
	// Clear scene color buffer if necessary.
	if ( bRequiresRHIClear )
	{
		ClearView();

		// Only clear once.
		bRequiresRHIClear = false;
	}

	// Clear LPVs for all views
	if ( IsFeatureLevelSupported(GRHIShaderPlatform, ERHIFeatureLevel::SM5) )
	{
		ClearLPVs();
	}

	// only temporarily available after early z pass and until base pass
	check(!GSceneRenderTargets.DBufferA);
	check(!GSceneRenderTargets.DBufferB);
	check(!GSceneRenderTargets.DBufferC);

	if(IsDBufferEnabled())
	{
		GSceneRenderTargets.ResolveSceneDepthTexture();

		// Resolve the scene depth to an auxiliary texture when SM3/SM4 is in use. This needs to happen so the auxiliary texture can be bound as a shader parameter
		// while the primary scene depth texture can be bound as the target. Simultaneously binding a single DepthStencil resource as a parameter and target
		// is unsupported in d3d feature level 10.
		if(!(GRHIFeatureLevel >= ERHIFeatureLevel::SM5) && GRHIFeatureLevel >= ERHIFeatureLevel::SM4)
		{
			GSceneRenderTargets.ResolveSceneDepthToAuxiliaryTexture();
		}

		// e.g. ambient cubemaps, ambient occlusion, deferred decals
		for(int32 ViewIndex = 0;ViewIndex < Views.Num();ViewIndex++)
		{	
			SCOPED_CONDITIONAL_DRAW_EVENTF(EventView,Views.Num() > 1, DEC_SCENE_ITEMS, TEXT("View%d"), ViewIndex);
			GCompositionLighting.ProcessBeforeBasePass(Views[ViewIndex]);
		}
	}

	if(bIsWireframe && FDeferredShadingSceneRenderer::ShouldCompositeEditorPrimitives(Views[0]))
	{
		// In Editor we want wire frame view modes to be MSAA for better quality. Resolve will be done with EditorPrimitives
		RHISetRenderTarget(GSceneRenderTargets.GetEditorPrimitivesColor(), GSceneRenderTargets.GetEditorPrimitivesDepth());
		RHIClear(true, FLinearColor(0, 0, 0, 0), true, 0.0f, false, 0, FIntRect());
	}
	else
	{
		// Begin rendering to scene color
		GSceneRenderTargets.BeginRenderingSceneColor(true);
	}

	RenderBasePass();

	if(ViewFamily.EngineShowFlags.VisualizeLightCulling)
	{
		// clear out emissive and baked lighting (not too efficient but simple and only needed for this debug view)
		GSceneRenderTargets.BeginRenderingSceneColor(false);
		RHIClear(true, FLinearColor(0, 0, 0, 0), false, 0, false, 0, FIntRect());
	}

	GSceneRenderTargets.DBufferA.SafeRelease();
	GSceneRenderTargets.DBufferB.SafeRelease();
	GSceneRenderTargets.DBufferC.SafeRelease();

	// only temporarily available after early z pass and until base pass
	check(!GSceneRenderTargets.DBufferA);
	check(!GSceneRenderTargets.DBufferB);
	check(!GSceneRenderTargets.DBufferC);

	if (bRequiresFarZQuadClear)
	{
		// Clears view by drawing quad at maximum Z
		// TODO: if all the platforms have fast color clears, we can replace this with an RHIClear.
		ClearGBufferAtMaxZ();

		bRequiresFarZQuadClear = false;
	}
	
	GSceneRenderTargets.ResolveSceneColor(FResolveRect(0, 0, ViewFamily.FamilySizeX, ViewFamily.FamilySizeY));
	GSceneRenderTargets.ResolveSceneDepthTexture();

	// Resolve the scene depth to an auxiliary texture when SM3/SM4 is in use. This needs to happen so the auxiliary texture can be bound as a shader parameter
	// while the primary scene depth texture can be bound as the target. Simultaneously binding a single DepthStencil resource as a parameter and target
	// is unsupported in d3d feature level 10.
	if(!GSupportsDepthFetchDuringDepthTest)
	{
		GSceneRenderTargets.ResolveSceneDepthToAuxiliaryTexture();
	}
	
	RenderCustomDepthPass();

	// Notify the FX system that opaque primitives have been rendered and we now have a valid depth buffer.
	if (Scene->FXSystem && Views.IsValidIndex(0))
	{
		Scene->FXSystem->PostRenderOpaque(
			Views.GetTypedData(),
			GSceneRenderTargets.GetSceneDepthTexture(),
			GSceneRenderTargets.GetGBufferATexture()
			);
	}

	// Update the quarter-sized depth buffer with the current contents of the scene depth texture.
	// This needs to happen before occlusion tests, which makes use of the small depth buffer.
	UpdateDownsampledDepthSurface();

	// Issue occlusion queries
	// This is done after the downsampled depth buffer is created so that it can be used for issuing queries
	if ( bIsOcclusionTesting )
	{
		BeginOcclusionTests();
	}
	
	// Render lighting.
	if (ViewFamily.EngineShowFlags.Lighting
		&& GRHIFeatureLevel >= ERHIFeatureLevel::SM4
		&& ViewFamily.EngineShowFlags.DeferredLighting
		)
	{
		// Pre-lighting composition lighting stage
		// e.g. deferred decals, blurred GBuffer
		for(int32 ViewIndex = 0;ViewIndex < Views.Num();ViewIndex++)
		{	
			SCOPED_CONDITIONAL_DRAW_EVENTF(EventView,Views.Num() > 1, DEC_SCENE_ITEMS, TEXT("View%d"), ViewIndex);
			GCompositionLighting.ProcessAfterBasePass(Views[ViewIndex]);
		}
		
		// Clear the translucent lighting volumes before we accumulate
		ClearTranslucentVolumeLighting();

		RenderLights();

		InjectAmbientCubemapTranslucentVolumeLighting();

		CompositeIndirectTranslucentVolumeLighting();

		// Filter the translucency lighting volume now that it is complete
		FilterTranslucentVolumeLighting();

		// Clear LPVs for all views
		if ( IsFeatureLevelSupported(GRHIShaderPlatform, ERHIFeatureLevel::SM5) )
		{
			PropagateLPVs();
		}

		// Render reflections that only operate on opaque pixels
		RenderDeferredReflections();

		// Post-lighting composition lighting stage
		// e.g. ambient cubemaps, ambient occlusion, LPV indirect
		for(int32 ViewIndex = 0; ViewIndex < Views.Num(); ++ViewIndex)
		{	
			SCOPED_CONDITIONAL_DRAW_EVENTF(EventView,Views.Num() > 1, DEC_SCENE_ITEMS, TEXT("View%d"), ViewIndex);
			GCompositionLighting.ProcessLighting(Views[ViewIndex]);
		}
	}

	if( ViewFamily.EngineShowFlags.StationaryLightOverlap &&
		GRHIFeatureLevel >= ERHIFeatureLevel::SM4)
	{
		RenderStationaryLightOverlap();
	}

	FLightShaftsOutput LightShaftOutput;

	// Draw Lightshafts
	if (ViewFamily.EngineShowFlags.LightShafts)
	{
		LightShaftOutput = RenderLightShaftOcclusion();
	}

	// Draw atmosphere
	if(ShouldRenderAtmosphere(ViewFamily))
	{
		if (Scene->AtmosphericFog)
		{
			// Update RenderFlag based on LightShaftTexture is valid or not
			if (LightShaftOutput.bRendered)
			{
				Scene->AtmosphericFog->RenderFlag &= EAtmosphereRenderFlag::E_LightShaftMask;
			}
			else
			{
				Scene->AtmosphericFog->RenderFlag |= EAtmosphereRenderFlag::E_DisableLightShaft;
			}
#if WITH_EDITOR
			if (Scene->bIsEditorScene)
			{
				// Precompute Atmospheric Textures
				Scene->AtmosphericFog->PrecomputeTextures(Views.GetTypedData(), &ViewFamily);
			}
#endif
			RenderAtmosphere(LightShaftOutput);
		}
	}

	// Draw fog.
	if(ShouldRenderFog(ViewFamily))
	{
		RenderFog(LightShaftOutput);
	}

	// No longer needed, release
	LightShaftOutput.LightShaftOcclusion = NULL;

	// Draw translucency.
	if(ViewFamily.EngineShowFlags.Translucency)
	{
		SCOPE_CYCLE_COUNTER(STAT_TranslucencyDrawTime);

		if(ViewFamily.EngineShowFlags.Refraction)
		{
			// to apply refraction effect by distorting the scene color
			RenderDistortion();
		}
		RenderTranslucency();
	}

	if (ViewFamily.EngineShowFlags.LightShafts)
	{
		RenderLightShaftBloom();
	}

	// Resolve the scene color for post processing.
	GSceneRenderTargets.ResolveSceneColor(FResolveRect(0, 0, ViewFamily.FamilySizeX, ViewFamily.FamilySizeY));

#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
	if(CVarTestUIBlur.GetValueOnRenderThread() > 0)
	{
		Views[0].UIBlurOverrideRectangles.Add(FIntRect(20, 20, 400, 400));
	}
#endif

	// Finish rendering for each view.
	if(ViewFamily.bResolveScene)
	{
		SCOPED_DRAW_EVENT(FinishRendering, DEC_SCENE_ITEMS);
		SCOPE_CYCLE_COUNTER(STAT_FinishRenderViewTargetTime);
		for(int32 ViewIndex = 0;ViewIndex < Views.Num();ViewIndex++)
		{	
			SCOPED_CONDITIONAL_DRAW_EVENTF(EventView, Views.Num() > 1, DEC_SCENE_ITEMS, TEXT("View%d"), ViewIndex);
			FinishRenderViewTarget(&Views[ViewIndex], ViewIndex == (Views.Num() - 1));
		}
	}

	RenderFinish();
}