此文件还实现了ComputeTransmissionProfile:
void ComputeTransmissionProfile(FLinearColor* TargetBuffer, uint32 TargetBufferSize, FLinearColor SubsurfaceColor, FLinearColor FalloffColor, float ExtinctionScale) { check(TargetBuffer); check(TargetBufferSize > 0); static float MaxTransmissionProfileDistance = 5.0f; // See MAX_TRANSMISSION_PROFILE_DISTANCE in TransmissionCommon.ush for (uint32 i = 0; i < TargetBufferSize; ++i) { //10 mm const float InvSize = 1.0f / TargetBufferSize; float Distance = i * InvSize * MaxTransmissionProfileDistance; FVector TransmissionProfile = SeparableSSS_Profile(Distance, FalloffColor); TargetBuffer[i] = TransmissionProfile; //Use Luminance of scattering as SSSS shadow. TargetBuffer[i].A = exp(-Distance * ExtinctionScale); } // Do this is because 5mm is not enough cool down the scattering to zero, although which is small number but after tone mapping still noticeable // so just Let last pixel be 0 which make sure thickness great than MaxRadius have no scattering static bool bMakeLastPixelBlack = true; if (bMakeLastPixelBlack) { TargetBuffer[TargetBufferSize - 1] = FLinearColor::Black; } }ComputeMirroredSSSKernel和ComputeTransmissionProfile的触发是在FSubsurfaceProfileTexture::CreateTexture内,而后者又是在关卡加载时或者编辑器操作时触发调用(也就是说预计算的,非运行时计算):
void FSubsurfaceProfileTexture::CreateTexture(FRHICommandListImmediate& RHICmdList) { // ... (隐藏了卷积前的处理代码) for (uint32 y = 0; y < Height; ++y) { // ... (隐藏了卷积前的处理代码) // 根据r.SSS.SampleSet的数值(0、1、2),卷积3个不同尺寸的权重。 ComputeMirroredSSSKernel(&TextureRow[SSSS_KERNEL0_OFFSET], SSSS_KERNEL0_SIZE, Data.SubsurfaceColor, Data.FalloffColor); ComputeMirroredSSSKernel(&TextureRow[SSSS_KERNEL1_OFFSET], SSSS_KERNEL1_SIZE, Data.SubsurfaceColor, Data.FalloffColor); ComputeMirroredSSSKernel(&TextureRow[SSSS_KERNEL2_OFFSET], SSSS_KERNEL2_SIZE, Data.SubsurfaceColor, Data.FalloffColor); // 计算透射剖面。 ComputeTransmissionProfile(&TextureRow[SSSS_TRANSMISSION_PROFILE_OFFSET], SSSS_TRANSMISSION_PROFILE_SIZE, Data.SubsurfaceColor, Data.FalloffColor, Data.ExtinctionScale); // ...(隐藏了卷积后的处理代码) } } 2.3.3 PostProcessSubsurface.ush此文件为SeparableSSS.ush定义了大量接口和变量,并且是调用SeparableSSS的使用者:
// .... (隐藏其它代码) #include "SeparableSSS.ush" // .... (隐藏其它代码) // input0 is created by the SetupPS shader void MainPS(noperspective float4 UVAndScreenPos : TEXCOORD0, out float4 OutColor : SV_Target0) { float2 BufferUV = UVAndScreenPos.xy; #if SSS_DIRECTION == 0 // horizontal float2 ViewportDirectionUV = float2(1, 0) * SUBSURFACE_RADIUS_SCALE; #else // vertical float2 ViewportDirectionUV = float2(0, 1) * SUBSURFACE_RADIUS_SCALE * (View.ViewSizeAndInvSize.x * View.ViewSizeAndInvSize.w); #endif #if MANUALLY_CLAMP_UV ViewportDirectionUV *= (View.ViewSizeAndInvSize.x * View.BufferSizeAndInvSize.z); #endif // 获得次表面散射颜色 OutColor = SSSSBlurPS(BufferUV, ViewportDirectionUV, false); #if SSS_DIRECTION == 1 // second pass prepares the setup from the recombine pass which doesn't need depth but wants to reconstruct the color OutColor.a = ComputeMaskFromDepthInAlpha(OutColor.a); #endif }