You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
ViewWorldOrigin -> WorldViewOrigin CameraWorldOrigin -> WorldCameraOrigin CameraTranslatedWorldOrigin -> TranslatedWorldCameraOrigin CameraWorldOriginDelta -> WorldCameraMovementSinceLastFrame PrevCameraWorldOrigin -> PrevWorldCameraOrigin PrevViewWorldOrigin -> PrevWorldViewOrigin #code_review: Martin.Mittring [CL 2666624 by Guillaume Abadie in Main branch]
408 lines
12 KiB
Plaintext
408 lines
12 KiB
Plaintext
// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
|
|
|
|
/*=============================================================================
|
|
DeferredDecal.usf: Pixel shader for computing a deferred decal.
|
|
=============================================================================*/
|
|
|
|
// DECAL_BLEND_MODE is set by C++ from EDecalBlendMode e.g. DECALBLENDMODEID_VOLUMETRIC, DECALBLENDMODEID_NORMAL, ...
|
|
// DECAL_RENDERTARGET_COUNT is set by C++ e.g. 1: single RT, 2: two MRT, 3: three MRT
|
|
// DECAL_RENDERSTAGE is set by C++ from EDecalRenderStage e.g. 0:before base pass, 1:after base pass, 2: before lighting
|
|
|
|
#include "Common.usf"
|
|
|
|
// from screen space position to decal space (for position)
|
|
float4x4 ScreenToDecal;
|
|
// to transform position from decal space to world space, for normals use transpose of inverse
|
|
float4x4 DecalToWorld;
|
|
// to transform position from world space to decal space, for normals use transpose of inverse
|
|
float4x4 WorldToDecal;
|
|
|
|
#if DECAL_PROJECTION
|
|
#include "Material.usf"
|
|
#endif
|
|
|
|
#include "DeferredShadingCommon.usf" // GBufferData
|
|
|
|
// from component to clip space (for decal frustum)
|
|
float4x4 FrustumComponentToClip;
|
|
// fade alpha from screen size fading
|
|
float FadeAlpha;
|
|
|
|
// only for StencilDecalMaskMain, to get ShaderComplexity for Decals (doesn't look at the DecalMask yet)
|
|
float MaskComparison;
|
|
|
|
void StencilDecalMaskMain(
|
|
FScreenVertexOutput Input,
|
|
out float4 OutColor : SV_Target0
|
|
)
|
|
{
|
|
FGBufferData InGBufferData = GetGBufferData(Input.UV);
|
|
|
|
// Write 1 to the stencil buffer for pixels that are masked out of receiving decals
|
|
clip(MaskComparison - InGBufferData.DecalMask);
|
|
|
|
OutColor = 0;
|
|
}
|
|
|
|
half3 FrameBufferDecalBlendOp(half4 Source)
|
|
{
|
|
#if (COMPILER_GLSL_ES2)
|
|
half4 Dest = FramebufferFetchES2();
|
|
Dest.rgb = Decode32BPPHDR(Dest);
|
|
#else
|
|
half4 Dest = half4(0, 0, 0, 0);
|
|
#endif
|
|
|
|
#if DECAL_BLEND_MODE == DECALBLENDMODEID_STAIN
|
|
return (Source.rgb*Dest.rgb) + (Dest.rgb*(1.0 - Source.a));
|
|
#elif DECAL_BLEND_MODE == DECALBLENDMODEID_TRANSLUCENT
|
|
return (Source.rgb*Source.a) + (Dest.rgb*(1.0 - Source.a));
|
|
#elif DECAL_BLEND_MODE == DECALBLENDMODEID_EMISSIVE
|
|
return (Source.rgb*Source.a) + Dest.rgb;
|
|
#else
|
|
return Source.rgb;
|
|
#endif
|
|
}
|
|
|
|
// decal vertex shader
|
|
void MainVS(
|
|
in float4 InPosition : ATTRIBUTE0,
|
|
out float4 OutScreenPosition : TEXCOORD0,
|
|
out float4 OutPosition : SV_POSITION
|
|
)
|
|
{
|
|
OutPosition = OutScreenPosition = mul(InPosition, FrustumComponentToClip);
|
|
}
|
|
|
|
float DistanceFunction(float4 ScreenPosition, float3 Pos)
|
|
{
|
|
float3 SwizzlePos = Pos.zyx;
|
|
|
|
#if DECAL_PROJECTION && DECAL_BLEND_MODE == DECALBLENDMODEID_VOLUMETRIC
|
|
|
|
FMaterialPixelParameters MaterialParameters = MakeInitializedMaterialPixelParameters();
|
|
#if NUM_MATERIAL_TEXCOORDS
|
|
for(int CoordinateIndex = 0;CoordinateIndex < NUM_MATERIAL_TEXCOORDS;CoordinateIndex++)
|
|
{
|
|
MaterialParameters.TexCoords[CoordinateIndex] = SwizzlePos.xy * 0.5f + 0.5f;
|
|
}
|
|
#endif
|
|
|
|
MaterialParameters.VertexColor = 1;
|
|
MaterialParameters.ScreenPosition = ScreenPosition;
|
|
MaterialParameters.LightVector = SwizzlePos * 0.5f + 0.5f; // to be compatible with decals but *0.5+0.5 seems wrong
|
|
MaterialParameters.WorldPosition =
|
|
MaterialParameters.WorldPosition_CamRelative =
|
|
MaterialParameters.WorldPosition_NoOffsets =
|
|
MaterialParameters.WorldPosition_NoOffsets_CamRelative = mul(DecalToWorld, float4(Pos, 1)).xyz;
|
|
MaterialParameters.CameraVector = normalize(View.WorldCameraOrigin - MaterialParameters.WorldPosition);
|
|
|
|
// the material needs to output the distance from "Opacity" depending on LightVector (in 0..1 range)
|
|
return GetMaterialMaskInputRaw(MaterialParameters);
|
|
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
// @return t=0..1, -1: no hit
|
|
float Raycast(float4 ScreenPosition, float3 StartPos, float3 EndPos)
|
|
{
|
|
const uint steps = 300;
|
|
|
|
float t = 0;
|
|
|
|
float RayLength = length(EndPos - StartPos);
|
|
float3 Direction = normalize(EndPos - StartPos);
|
|
|
|
LOOP for(uint i = 0; i < steps; ++i)
|
|
{
|
|
float Distance = DistanceFunction(ScreenPosition, StartPos + t * Direction);
|
|
|
|
if(Distance <= i * 0.001f)
|
|
{
|
|
return t / RayLength;
|
|
}
|
|
|
|
t += Distance;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
// like explained here http://iquilezles.org/www/articles/derivative/derivative.htm
|
|
float3 GradientNotNormalized(float4 ScreenPosition, float3 OSPos)
|
|
{
|
|
float eps = 0.1f;
|
|
|
|
float2 e = float2(eps, 0);
|
|
|
|
return float3(DistanceFunction(ScreenPosition, OSPos + e.xyy) - DistanceFunction(ScreenPosition, OSPos - e.xyy),
|
|
DistanceFunction(ScreenPosition, OSPos + e.yxy) - DistanceFunction(ScreenPosition, OSPos - e.yxy),
|
|
DistanceFunction(ScreenPosition, OSPos + e.yyx) - DistanceFunction(ScreenPosition, OSPos - e.yyx));
|
|
}
|
|
|
|
|
|
|
|
// decal pixel shader
|
|
#if DECAL_PROJECTION
|
|
|
|
#if DECAL_BLEND_MODE == DECALBLENDMODEID_VOLUMETRIC
|
|
// should work, but doesn't EARLYDEPTHSTENCIL
|
|
#endif
|
|
|
|
void MainPS(
|
|
in float4 ScreenPosition : TEXCOORD0 // is ClipPosition
|
|
|
|
, in INPUT_POSITION_QUALIFIERS float4 SvPosition : SV_Position
|
|
|
|
#if DECAL_RENDERTARGET_COUNT > 0
|
|
, out float4 OutTarget0 : SV_Target0
|
|
#endif
|
|
|
|
#if DECAL_RENDERTARGET_COUNT > 1
|
|
, out float4 OutTarget1 : SV_Target1
|
|
#endif
|
|
|
|
#if DECAL_RENDERTARGET_COUNT > 2
|
|
, out float4 OutTarget2 : SV_Target2
|
|
#endif
|
|
|
|
#if DECAL_RENDERTARGET_COUNT > 3
|
|
, out float4 OutTarget3 : SV_Target3
|
|
#endif
|
|
|
|
OPTIONAL_OutDepth
|
|
|
|
)
|
|
{
|
|
bool bVolumetric = DECAL_BLEND_MODE == DECALBLENDMODEID_VOLUMETRIC;
|
|
|
|
float3 OSPosition;
|
|
float3 WSPosition;
|
|
|
|
if(bVolumetric)
|
|
{
|
|
// LineBoxIntersect want's to clip a long ray so we provide one, this could be done differently as it limites the draw distance and reduces precision
|
|
float SceneW = 100000000;
|
|
|
|
float4 ProjectedScreenPosition = float4(ScreenPosition.xy / ScreenPosition.w * SceneW, SceneW, 1); // is ProjectedClipPosition
|
|
|
|
ProjectedScreenPosition = float4(ScreenPosition.xy / ScreenPosition.w * SceneW, SceneW, 1);
|
|
|
|
float4 WorldPosHom = mul(ProjectedScreenPosition, View.ScreenToWorld);
|
|
|
|
float3 WSStartRay = View.WorldCameraOrigin;
|
|
float3 WSEndRay = WorldPosHom.xyz;
|
|
|
|
// in object/decal space
|
|
float4 OSStartRayHom = mul(float4(WSStartRay,1), WorldToDecal);
|
|
float4 OSEndRayHom = mul(float4(WSEndRay, 1), WorldToDecal);
|
|
|
|
float3 OSStartRay = OSStartRayHom.xyz / OSStartRayHom.w;
|
|
float3 OSEndRay = OSEndRayHom.xyz / OSEndRayHom.w;
|
|
|
|
float2 OSBoxMinMax = LineBoxIntersect(OSStartRay, OSEndRay, -1, 1);
|
|
|
|
float3 OSBoxStartRay = OSStartRay + OSBoxMinMax.x * (OSEndRay - OSStartRay);
|
|
float3 OSBoxEndRay = OSStartRay + OSBoxMinMax.y * (OSEndRay - OSStartRay);
|
|
|
|
float HitT = Raycast(ScreenPosition, OSBoxStartRay, OSBoxEndRay);
|
|
|
|
clip(HitT);
|
|
|
|
OSPosition = OSBoxStartRay + HitT * (OSBoxEndRay - OSBoxStartRay);
|
|
WSPosition = mul(float4(OSPosition, 1), DecalToWorld).xyz;
|
|
|
|
#if OUTPUT_PIXEL_DEPTH_OFFSET
|
|
float4 CSHitPos = mul(float4(WSPosition, 1), View.WorldToClip);
|
|
OutDepth = CSHitPos.z / CSHitPos.w;
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
half SceneW = PreviousDepth(ScreenPosition);
|
|
float4 ProjectedScreenPosition = float4(ScreenPosition.xy / ScreenPosition.w * SceneW, SceneW, 1);
|
|
|
|
float4 DecalVectorHom = mul(ProjectedScreenPosition, ScreenToDecal);
|
|
OSPosition = DecalVectorHom.xyz / DecalVectorHom.w;
|
|
|
|
// clip content outside the decal
|
|
// not needed if we stencil out the decal but we do that only on large (screen space) ones
|
|
clip(OSPosition.xyz + 1.0f);
|
|
clip(1.0f - OSPosition.xyz);
|
|
|
|
float4 WSPositionHom = mul(ProjectedScreenPosition, View.ScreenToWorld);
|
|
WSPosition = WSPositionHom.xyz / WSPositionHom.w;
|
|
}
|
|
|
|
float3 CameraVector = normalize(View.WorldCameraOrigin - WSPosition);
|
|
|
|
// can be optimized
|
|
float3 DecalVector = OSPosition * 0.5f + 0.5f;
|
|
|
|
// Swizzle so that DecalVector.xy are perpendicular to the projection direction and DecalVector.z is distance along the projection direction
|
|
float3 SwizzlePos = DecalVector.zyx;
|
|
|
|
// By default, map textures using the vectors perpendicular to the projection direction
|
|
float2 DecalUVs = SwizzlePos.xy;
|
|
|
|
FMaterialPixelParameters MaterialParameters = MakeInitializedMaterialPixelParameters();
|
|
#if NUM_MATERIAL_TEXCOORDS
|
|
for(int CoordinateIndex = 0;CoordinateIndex < NUM_MATERIAL_TEXCOORDS;CoordinateIndex++)
|
|
{
|
|
MaterialParameters.TexCoords[CoordinateIndex] = DecalUVs;
|
|
}
|
|
#endif
|
|
MaterialParameters.VertexColor = 1;
|
|
MaterialParameters.CameraVector = CameraVector;
|
|
MaterialParameters.ScreenPosition = ScreenPosition;
|
|
MaterialParameters.LightVector = SwizzlePos;
|
|
MaterialParameters.WorldPosition =
|
|
MaterialParameters.WorldPosition_CamRelative =
|
|
MaterialParameters.WorldPosition_NoOffsets =
|
|
MaterialParameters.WorldPosition_NoOffsets_CamRelative = WSPosition;
|
|
|
|
{
|
|
if(bVolumetric)
|
|
{
|
|
// not normalized
|
|
float3 OSNormal = GradientNotNormalized(ScreenPosition, OSPosition);
|
|
|
|
// not normalized
|
|
float3 WSNormal = mul(float4(OSNormal, 0), transpose(WorldToDecal)).xyz;
|
|
|
|
MaterialParameters.WorldNormal = normalize(WSNormal);
|
|
}
|
|
else
|
|
{
|
|
// not normalized
|
|
float3 MaterialNormal = GetMaterialNormal(MaterialParameters);
|
|
|
|
// tangent/decal space to world space
|
|
#if MATERIAL_TANGENTSPACENORMAL
|
|
// normals are transformed by the tranposed of the inverse
|
|
// DecalToWorld becomes transpose(WorldToDecal)
|
|
MaterialParameters.WorldNormal = normalize(mul(float4(-MaterialNormal.z, MaterialNormal.y, MaterialNormal.x, 0), transpose(WorldToDecal)).xyz);
|
|
#else
|
|
MaterialParameters.WorldNormal = normalize(MaterialNormal);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
MaterialParameters.ReflectionVector = -MaterialParameters.CameraVector + MaterialParameters.WorldNormal * dot(MaterialParameters.WorldNormal, MaterialParameters.CameraVector) * 2.0;
|
|
|
|
// Store the results in local variables and reuse instead of calling the functions multiple times.
|
|
half3 BaseColor = GetMaterialBaseColor( MaterialParameters );
|
|
half Metallic = GetMaterialMetallic( MaterialParameters );
|
|
half Specular = GetMaterialSpecular( MaterialParameters );
|
|
|
|
float3 Color = 1;
|
|
|
|
#if DECAL_BLEND_MODE == DECALBLENDMODEID_NORMAL
|
|
// -1..1 range to 0..1
|
|
Color = MaterialParameters.WorldNormal * 0.5f + 0.5f;
|
|
#else
|
|
Color = GetMaterialEmissive(MaterialParameters);
|
|
|
|
#if (ES2_PROFILE || ES3_1_PROFILE) // only for mobile
|
|
Color+= BaseColor;
|
|
#endif
|
|
#endif
|
|
|
|
float Opacity = GetMaterialOpacity(MaterialParameters);
|
|
|
|
#if 0
|
|
// Normal based fade
|
|
float3 FaceNormal = normalize( cross( ddx_fine(WorldPosition), ddy_fine(WorldPosition) ) );
|
|
float3 DecalZ = mul(float4(-1, 0, 0, 0), DecalToWorld).xyz;
|
|
Opacity *= saturate( 2 * dot( FaceNormal, DecalZ ) );
|
|
#endif
|
|
|
|
// Z fade
|
|
Opacity *= saturate( 4 - 4 * abs( SwizzlePos.z * 2 - 1 ) );
|
|
|
|
Opacity *= FadeAlpha;
|
|
|
|
// RETURN_COLOR not needed unless writing to SceneColor
|
|
OutTarget0 = float4(Color, Opacity);
|
|
|
|
#if (ES2_PROFILE || ES3_1_PROFILE)
|
|
#if (COMPILER_GLSL_ES2) || (MOBILE_EMULATION)
|
|
// Do decal blending if encoding requires it.
|
|
if (GetHDR32bppEncodeMode() == HDR_ENCODE_RGBA)
|
|
{
|
|
OutTarget0.rgb = FrameBufferDecalBlendOp(OutTarget0);
|
|
}
|
|
// do 32bpp hdr encoding for mobile if required.
|
|
OutTarget0 = Encode32BPPHDR(OutTarget0, SvPosition.xy);
|
|
#endif
|
|
#endif
|
|
|
|
#if DECAL_RENDERTARGET_COUNT > 1
|
|
// some MRT rendering
|
|
|
|
FGBufferData Data;
|
|
|
|
Data.WorldNormal = MaterialParameters.WorldNormal;
|
|
Data.BaseColor = BaseColor;
|
|
Data.Metallic = Metallic;
|
|
Data.Specular = Specular;
|
|
Data.Roughness = GetMaterialRoughness(MaterialParameters);
|
|
Data.CustomData = 0;
|
|
Data.IndirectIrradiance = 0;
|
|
Data.PrecomputedShadowFactors = 0;
|
|
Data.GBufferAO = 1;
|
|
Data.Opacity = Opacity;
|
|
Data.ShadingModelID = SHADINGMODELID_DEFAULT_LIT;
|
|
Data.DecalMask = 1;
|
|
Data.HasDistanceFieldRepresentation = 1;
|
|
Data.HasHeightfieldRepresentation = 1;
|
|
|
|
#if DECAL_RENDERSTAGE == 0
|
|
{
|
|
// before base pass (DBuffer)
|
|
|
|
// @param MultiOpacity .x: Color, .y:Normal, .z:Roughness
|
|
float3 MultiOpacity = Data.Opacity;
|
|
|
|
EncodeDBufferData(Data, MultiOpacity, OutTarget0, OutTarget1, OutTarget2);
|
|
}
|
|
#elif DECAL_RENDERSTAGE == 1
|
|
{
|
|
// after base pass (GBuffer)
|
|
|
|
// static lighting isn't updated by decals so we don't need to update that render target
|
|
float4 OutTarget4 = 0;
|
|
float4 OutTarget5 = 0;
|
|
float4 OutTarget6 = 0;
|
|
|
|
EncodeGBuffer(Data, OutTarget1, OutTarget2, OutTarget3, OutTarget4, OutTarget5, OutTarget6);
|
|
}
|
|
#elif DECAL_RENDERSTAGE == 2
|
|
{
|
|
// before lighting (GBuffer)
|
|
|
|
// static lighting isn't updated by decals so we don't need to update that render target
|
|
float4 OutTarget4 = 0;
|
|
float4 OutTarget5 = 0;
|
|
float4 OutTarget6 = 0;
|
|
|
|
EncodeGBuffer(Data, OutTarget1, OutTarget2, OutTarget3, OutTarget4, OutTarget5, OutTarget6);
|
|
|
|
#if DECAL_BLEND_MODE == DECALBLENDMODEID_STAIN
|
|
OutTarget3.rgb *= Opacity;
|
|
#endif
|
|
|
|
OutTarget0.a = Opacity; // Emissive
|
|
OutTarget1.a = Opacity; // Normal
|
|
OutTarget2.a = Opacity; // Metallic, Specular, Roughness
|
|
OutTarget3.a = Opacity; // BaseColor
|
|
}
|
|
#endif // DECAL_RENDERSTAGE
|
|
#endif //DECAL_RENDERTARGET_COUNT > 1
|
|
}
|
|
|
|
#endif // DECAL_PROJECTION
|
|
|