光束问题

增加接口控制shader参数

sunAlpha和sunBlur这两个pass分别有半径,在PostProcessMobile.usf文件中,这俩值是写死的,我们想要动态改变,所以增加了这俩参数。我们只希望平行光有光束效果,所以,只修改平行光相关的属性。
LightComponent.h文件里增加shaft里shader参数的设置:

	UFUNCTION(BlueprintCallable, Category = "Rendering|Components|Light")
	void SetLightShaftAlphaRadius(float NewValue);

	UFUNCTION(BlueprintCallable, Category = "Rendering|Components|Light")
	void SetLightShaftBlurRadius(float NewValue);

跟BloomTint逻辑一样:

  UFUNCTION(BlueprintCallable, Category="Rendering|Components|Light")
    	void SetBloomThreshold(float NewValue);
    
    	UFUNCTION(BlueprintCallable, Category="Rendering|Components|Light")
    	void SetBloomTint(FColor NewValue);

另外,这两个属性需要在属性窗口里可见,属性定义跟bloomTInt一样,在LightProxy里也有相同名字的属性,update函数也会实时更新这俩属性,FViewInfo里也有这俩属性。

增加接口动态设置光束位置

设置lightShaft位置的接口:

在SceneVisibility文件,PostVisibilityFrameSetup函数中,worldSpaceBlurOrigin是通过LightSceneInfo->Proxy->GetPosition()获取的,那么这个Position是啥?GetPosition返回的是position,Position又是通过Light->GetLightPosition赋值的(),如下所示:

void FScene::UpdateLightTransform(ULightComponent* Light)
{
   if(Light->SceneProxy)
   {
   	FUpdateLightTransformParameters Parameters;
   	Parameters.LightToWorld = Light->GetComponentTransform().ToMatrixNoScale();
   	Parameters.Position = Light->GetLightPosition();
   	ENQUEUE_UNIQUE_RENDER_COMMAND_THREEPARAMETER(
   		UpdateLightTransform,
   		FScene*,Scene,this,
   		FLightSceneInfo*,LightSceneInfo,Light->SceneProxy->GetLightSceneInfo(),
   		FUpdateLightTransformParameters,Parameters,Parameters,
   		{
   			FScopeCycleCounter Context(LightSceneInfo->Proxy->GetStatId());
   			Scene->UpdateLightTransform_RenderThread(LightSceneInfo, Parameters);
   		});
   }
}

而GetLightPosition又是啥?在DirectionalLightComponent.cpp文件中,该函数的重载实现为:

FVector4 UDirectionalLightComponent::GetLightPosition() const
{
	return FVector4(-GetDirection() * WORLD_MAX, 0 );
}

GetDirection又是啥?在LightComponent.cpp文件中,GetDirection函数:

FVector ULightComponent::GetDirection() const 
{ 
	return GetComponentTransform().GetUnitAxis( EAxis::X );
}

我们用我们自己的接口代替LightSceneInfo->Proxy->GetPosition(),为了light位置能用代码控制变化,我们用GetLightShaftOverridePositionForLightShafts()和void UDirectionalLightComponent::SetLightShaftOverridePosition(const FVector4& InPosition)来get和set这个值。
另外,set时,参数就要用一个component位置跟太阳位置变化一样,然后用这个component的GetComponentTransform.GetUnitAxis(EAxis::X),这是方向,然后*-1*WORLD_mAX,然后和0组成FVector4,跟前面分析的GetLightPosition的代码一样实现即可。

编辑器中能编辑上面的position

在编辑器中改变一个值,会从FPropertyNode的NotifyPostChange函数调用到USceneComponent的PostEditChangeChainProperty, 然后UActorComponent::PostEditChangeChainProperty,UObject::PostEditChangeChainProperty,UDirectionalLightComponent::PostEditChangeProperty,ULightComponent::PostEditChangeProperty,ULightComponentBase::PostEditChangeProperty,USceneComponent::PostEditChangeProperty,UActorComponent::PostEditChangeProperty,UActorComponent::ConsolidatedPostEditChange,~FComponentReregisterContext(),ComponentReregisterContext.h里Reregister,UActorComponent::ExecuteRegisterEvents(),ULightComponent::CreateRenderState_Concurrent(),World->Scene->AddLight,在FScene的AddLight函数里,设置坐标更新

void FScene::AddLight(ULightComponent* Light)
{
	// Create the light's scene proxy.
	FLightSceneProxy* Proxy = Light->CreateSceneProxy();
	if(Proxy)
	{
		// Associate the proxy with the light.
		Light->SceneProxy = Proxy;

		// Update the light's transform and position.
		Proxy->SetTransform(Light->GetComponentTransform().ToMatrixNoScale(),Light->GetLightPosition());

		Proxy->SetLightShaftOverridePosition(Light->LightShaftOverridePosition);
		// Create the light scene info.
		Proxy->LightSceneInfo = new FLightSceneInfo(Proxy, true);

		INC_DWORD_STAT(STAT_SceneLights);

		// Adding a new light
		++NumVisibleLights_GameThread;

		// Send a command to the rendering thread to add the light to the scene.
		ENQUEUE_UNIQUE_RENDER_COMMAND_TWOPARAMETER(
			FAddLightCommand,
			FScene*,Scene,this,
			FLightSceneInfo*,LightSceneInfo,Proxy->LightSceneInfo,
			{
				FScopeCycleCounter Context(LightSceneInfo->Proxy->GetStatId());
				Scene->AddLightSceneInfo_RenderThread(LightSceneInfo);
			});
	}
}

shader渲染管线分析整理

执行在postProcessing.cpp文件的ProcessES2函数。pass先后包括sunMask,BloomSetup,dof,4个bloomDown,3个bloomUp,SunAlpha,SunBlur,SunMerge,SunAverage,FRCSeparateTranslucensyPassES2.其中lightShaft涉及的就有sunMask,BloomSetup,4个bloomDown,3个bloomUp,SunAlpha,SUnBlur,SunMerge等。
其中每个pass的输入都可以在代码中看到,比如:SunMerge有3个输入:

FRenderingCompositePass* Pass = Context.Graph.RegisterPass(new(FMemStack::Get()) FRCPassPostProcessSunMergeES2(PrePostSourceViewportSize));
						if(bUseSun)
						{
							Pass->SetInput(ePId_Input0, PostProcessSunBlur);
						}
						if(bUseBloom)
						{
							Pass->SetInput(ePId_Input1, PostProcessBloomSetup);
							Pass->SetInput(ePId_Input2, PostProcessUpsample2);
						}
						PostProcessSunMerge = FRenderingCompositeOutputRef(Pass);

又比如bloomUp的upScale赋值:

{
						FVector4 TintA = FVector4(Settings.Bloom2Tint.R, Settings.Bloom2Tint.G, Settings.Bloom2Tint.B, 0.0f);
						TintA *= View.FinalPostProcessSettings.BloomIntensity;
						// Scaling Bloom2 by extra factor to match filter area difference between PC default and mobile.
						TintA *= 0.5;
						FVector4 TintB = FVector4(1.0f, 1.0f, 1.0f, 0.0f);
						FRenderingCompositePass* Pass = Context.Graph.RegisterPass(new(FMemStack::Get()) FRCPassPostProcessBloomUpES2(PrePostSourceViewportSize/8, FVector2D(UpScale, UpScale), TintA, TintB));
						Pass->SetInput(ePId_Input0, PostProcessDownsample2);
						Pass->SetInput(ePId_Input1, PostProcessUpsample3);
						PostProcessUpsample2 = FRenderingCompositeOutputRef(Pass);
					}

其构造函数会进行赋值:

FRCPassPostProcessBloomUpES2(FIntPoint InPrePostSourceViewportSize, FVector2D InScaleAB, FVector4& InTintA, FVector4& InTintB) : PrePostSourceViewportSize(InPrePostSourceViewportSize), ScaleAB(InScaleAB), TintA(InTintA), TintB(InTintB) { }

该文件中调用的具体shader类,shader变量的赋值在PostProcessMobile.cpp中可以找到。比如SunBLurVS的SetVS:

void SetVS(const FRenderingCompositePassContext& Context)
	{
		const FVertexShaderRHIParamRef ShaderRHI = GetVertexShader();
		FGlobalShader::SetParameters<FViewUniformShaderParameters>(Context.RHICmdList, ShaderRHI, Context.View.ViewUniformBuffer);
		PostprocessParameter.SetVS(ShaderRHI, Context, TStaticSamplerState<SF_Bilinear,AM_Clamp,AM_Clamp,AM_Clamp>::GetRHI());

		SetShaderValue(Context.RHICmdList, ShaderRHI, LightShaftCenter, Context.View.LightShaftCenter);
		SetShaderValue(Context.RHICmdList, ShaderRHI, LightShaftBlurRadius, Context.View.LightShaftBlurRadius);
	}

shader文件是PostProcessMobile.usf:

sunMask Pass:

//
// Convert depth in alpha into combined circle of confusion and sun intensity.
// Or pre-tonemap before hardware box-filtered resolve.
//

void SunMaskVS_ES2(
	in float4 InPosition : ATTRIBUTE0,
	in float2 InTexCoord : ATTRIBUTE1,
	out float4 OutUVPos : TEXCOORD0,
	out float4 OutPosition : SV_POSITION
	)
{
	DrawRectangle(InPosition, InTexCoord, OutPosition, OutUVPos.xy);
	OutUVPos.zw = OutPosition.xy;
}

void SunMaskPS_ES2(
	float4 InUVPos : TEXCOORD0,
	out half4 OutColor : SV_Target0
	)
{
	#if ((COMPILER_GLSL_ES2||COMPILER_GLSL_ES3_1)  && ES2_USE_FETCH) || (METAL_PROFILE && !MAC)
		OutColor = FramebufferFetchES2();
	#else
		OutColor = PostprocessInput0.Sample(PostprocessInput0Sampler, InUVPos.xy);
	#endif

	#if ES2_USE_MSAA
		// On-chip pre-tonemap before MSAA resolve.
		OutColor.rgb *= rcp(OutColor.r*0.299 + OutColor.g*0.587 + OutColor.b*0.114 + 1.0);
	#else

		#if ES2_USE_DEPTHTEXTURE
			half InDepth = CalcSceneDepth(InUVPos.xy);  //深度信息,
		#else
			half InDepth = OutColor.a;
		#endif
	
		#if ES2_USE_SUN
			half2 DepthMaskScaleBias = SunConstDepthMaskScaleBias();
			half FarAmount = saturate(InDepth * DepthMaskScaleBias.x + DepthMaskScaleBias.y); //较远地方的farAmount为1,较近地方的FarAmount值为0
			half3 SunAmount = OutColor.rgb * S
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值