Unreal Engine 4 – wet shader for all objects

It’s not an actual and complete wet shader or course, there are no many thing done in shader side, but it gives to you a good start-up to add more functionality to change all objects material things like roughness or normal or base color or whatever else ūüôā in the scene in one time.

wet_function_01

To see your changes you need have a UE4 project generated for building your own custom Editor (I use VS2015).

Go to the ..\Engine\Source\Runtime\Engine\Classes\Engine\Scene.h and add this near other structs:

 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Overrides, meta = (PinHiddenByDefault, InlineEditConditionToggle))
 uint32 bOverride_customWetFunctionIntensity:1;

UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Overrides, meta = (PinHiddenByDefault, InlineEditConditionToggle))
 uint32 bOverride_customDiffuseFactor:1;

UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Overrides, meta = (PinHiddenByDefault, InlineEditConditionToggle))
 uint32 bOverride_customNormalSmoothExample:1;

Next is to register the properties:

// The wet intensity 
 UPROPERTY(interp, BlueprintReadWrite, Category = "Rendering Features|Custom Rain Effects", meta = (ClampMin = "0.0", ClampMax = "1.0", editcondition = "bOverride_customWetFunctionIntensity"))
 float customWetFunctionIntensity;

// diffuse factor
 UPROPERTY(interp, BlueprintReadWrite, Category = "Rendering Features|Custom Rain Effects", meta = (ClampMin = "0.0", ClampMax = "10.0", editcondition = "bOverride_customDiffuseFactor"))
 float customDiffuseFactor;

// normal smoothness
 UPROPERTY(interp, BlueprintReadWrite, Category = "Rendering Features|Custom Rain Effects", meta = (ClampMin = "0.0", ClampMax = "0.1", editcondition = "bOverride_customNormalSmoothExample"))
 float customNormalSmoothExample;

Default values, at the bottom:

customWetFunctionIntensity = 0.0f;
customDiffuseFactor = 1.0f;
customNormalSmoothExample = 0.0025;

Good, next is to register in the SceneView.cpp at the  FSceneView::OverridePostProcessSettings:

LERP_PP(customWetFunctionIntensity);
LERP_PP(customDiffuseFactor);
LERP_PP(customNormalSmoothExample);

The idea is to change the GBufffer in order to have changes on everything what we have in the scene, located in the current postprocess volume. The best shader in this case probably will BasePassRendering.

Go to ..\Engine\Source\Runtime\Renderer\Private\BasePassRendering.h and find the class TBasePassPixelShaderPolicyParamType.

Add to the TBasePassPixelShaderPolicyParamType:

 customDiffuseFactor.Bind(Initializer.ParameterMap, TEXT("customDiffuseFactor"));
 customNormalSmoothExample.Bind(Initializer.ParameterMap, TEXT("customNormalSmoothExample"));

In the void SetParameters get the settings from postprocess:

SetShaderValue(RHICmdList, ShaderRHI, customDiffuseFactor, View->FinalPostProcessSettings.customDiffuseFactor);
SetShaderValue(RHICmdList, ShaderRHI, customNormalSmoothExample, View->FinalPostProcessSettings.customNormalSmoothExample);

Next is to add in virtual bool Serialize:

FShaderParameter customWetFunctionIntensity;
FShaderParameter customDiffuseFactor;
FShaderParameter customNormalSmoothExample;

Good, now let’s add our wet computation in the shader ../Engine/Shaders/BasePassPixelShader.usf

On the top:

float customDiffuseFactor;
float customNormalSmoothExample;
float customWetFunctionIntensity;

Find this part:

GBuffer.WorldNormal = MaterialParameters.WorldNormal;
GBuffer.BaseColor = BaseColor;
GBuffer.Metallic = Metallic;
GBuffer.Specular = Specular;
GBuffer.Roughness = Roughness;
GBuffer.GBufferAO = MaterialAO;
GBuffer.PerObjectGBufferData = Primitive.PerObjectGBufferData;
GBuffer.Depth = MaterialParameters.ScreenPosition.w;

and add below:

// if statement if the value more than 0
if (customWetFunctionIntensity > 0)
 {
 // old roughness 
 float oldRoughness = Roughness;
 // roughness factor
 customDiffuseFactor *= 0.2;
 float porosity = saturate( ( (oldRoughness) - 0.5) / 0.1 );
 float metalness = saturate( ( dot( GBuffer.Specular, 0.33 ) * 1000 - 500 ) );
 float factor = lerp( 0.1, 1, metalness * porosity ); 
 
 // wet roughness modification 
 float CustomRoughness = lerp(0.0,oldRoughness,lerp(1.0,factor,customWetFunctionIntensity*2.0));
 GBuffer.Roughness = CustomRoughness;

// normal blending example
 float3 customNormal = lerp( GBuffer.WorldNormal, float3(0, 0, 1), factor*(customNormalSmoothExample*100));
 GBuffer.WorldNormal = customNormal;

// diffuse wet factor
 porosity = saturate( ((oldRoughness) - 0.5) / 0.4);
 factor = lerp(0.2, 1.0, ( metalness) * porosity);
 float diffuseFactor = lerp(1.0, factor, customDiffuseFactor);
 GBuffer.BaseColor *= diffuseFactor;
}

This computations come from S√©bastien Lagarde post series about PBR wet surfaces[0], also I’ve add as an example the normal function which just blended the original normal with plane color.

Good thing to know that there are different solutions how to isolate this wet function on certain objects, one of them is to use a specific flag, in the mesh settings to prevent serializing each time the main shader from an instance materials (in case adding the option inside the material).

 

Leave a Reply

Your email address will not be published. Required fields are marked *