277 lines
8.3 KiB
GLSL
277 lines
8.3 KiB
GLSL
// File generated by Flax Materials Editor
|
|
// Version: @0
|
|
|
|
#define MATERIAL 1
|
|
#define USE_PER_VIEW_CONSTANTS 1
|
|
@3
|
|
|
|
#include "./Flax/Common.hlsl"
|
|
#include "./Flax/Stencil.hlsl"
|
|
#include "./Flax/MaterialCommon.hlsl"
|
|
#include "./Flax/GBufferCommon.hlsl"
|
|
@7
|
|
// Primary constant buffer (with additional material parameters)
|
|
META_CB_BEGIN(0, Data)
|
|
float4x4 WorldMatrix;
|
|
float4x4 InvWorld;
|
|
float4x4 SvPositionToWorld;
|
|
float3 Padding0;
|
|
uint RenderLayersMask;
|
|
@1META_CB_END
|
|
|
|
// Use depth buffer for per-pixel decal layering
|
|
Texture2D DepthBuffer : register(t0);
|
|
Texture2D<uint2> StencilBuffer : register(t1);
|
|
|
|
// Material shader resources
|
|
@2
|
|
// Material properties generation input
|
|
struct MaterialInput
|
|
{
|
|
float3 WorldPosition;
|
|
float TwoSidedSign;
|
|
float2 TexCoord;
|
|
float4 TexCoord_DDX_DDY;
|
|
float3x3 TBN;
|
|
float4 SvPosition;
|
|
float3 PreSkinnedPosition;
|
|
float3 PreSkinnedNormal;
|
|
};
|
|
|
|
// Calculates decal texcoords for a given pixel position (sampels depth buffer and projects value to decal space).
|
|
float2 SvPositionToDecalUV(float4 svPosition)
|
|
{
|
|
float2 screenUV = svPosition.xy * ScreenSize.zw;
|
|
svPosition.z = SAMPLE_RT(DepthBuffer, screenUV).r;
|
|
float4 positionHS = mul(float4(svPosition.xyz, 1), SvPositionToWorld);
|
|
float3 positionWS = positionHS.xyz / positionHS.w;
|
|
float3 positionOS = mul(float4(positionWS, 1), InvWorld).xyz;
|
|
return positionOS.xz + 0.5f;
|
|
}
|
|
|
|
// Manually compute ddx/ddy for decal texture cooordinates to avoid the 2x2 pixels artifacts on the edges of geometry under decal
|
|
// [Reference: https://www.humus.name/index.php?page=3D&ID=84]
|
|
float4 CalculateTextureDerivatives(float4 svPosition, float2 texCoord)
|
|
{
|
|
float4 svDiffX = float4(1, 0, 0, 0);
|
|
float2 uvDiffX0 = texCoord - SvPositionToDecalUV(svPosition - svDiffX);
|
|
float2 uvDiffX1 = SvPositionToDecalUV(svPosition + svDiffX) - texCoord;
|
|
float2 dx = dot(uvDiffX0, uvDiffX0) < dot(uvDiffX1, uvDiffX1) ? uvDiffX0 : uvDiffX1;
|
|
|
|
float4 svDiffY = float4(0, 1, 0, 0);
|
|
float2 uvDiffY0 = texCoord - SvPositionToDecalUV(svPosition - svDiffY);
|
|
float2 uvDiffY1 = SvPositionToDecalUV(svPosition + svDiffY) - texCoord;
|
|
float2 dy = dot(uvDiffY0, uvDiffY0) < dot(uvDiffY1, uvDiffY1) ? uvDiffY0 : uvDiffY1;
|
|
|
|
return float4(dx, dy);
|
|
}
|
|
|
|
// Computes the mipmap level for a specific texture dimensions to be sampled at decal texture cooordinates.
|
|
// [Reference: https://hugi.scene.org/online/coding/hugi%2014%20-%20comipmap.htm]
|
|
float CalculateTextureMipmap(MaterialInput input, float2 textureSize)
|
|
{
|
|
float2 dx = input.TexCoord_DDX_DDY.xy * textureSize;
|
|
float2 dy = input.TexCoord_DDX_DDY.zw * textureSize;
|
|
float d = max(dot(dx, dx), dot(dy, dy));
|
|
return (0.5 * 0.5) * log2(d); // Hardcoded half-mip rate reduction to avoid artifacts when decal is moved over dither texture
|
|
}
|
|
float CalculateTextureMipmap(MaterialInput input, Texture2D t)
|
|
{
|
|
float2 textureSize;
|
|
t.GetDimensions(textureSize.x, textureSize.y);
|
|
return CalculateTextureMipmap(input, textureSize);
|
|
}
|
|
float CalculateTextureMipmap(MaterialInput input, TextureCube t)
|
|
{
|
|
float2 textureSize;
|
|
t.GetDimensions(textureSize.x, textureSize.y);
|
|
return CalculateTextureMipmap(input, textureSize);
|
|
}
|
|
|
|
// Transforms a vector from tangent space to world space
|
|
float3 TransformTangentVectorToWorld(MaterialInput input, float3 tangentVector)
|
|
{
|
|
return mul(tangentVector, input.TBN);
|
|
}
|
|
|
|
// Transforms a vector from world space to tangent space
|
|
float3 TransformWorldVectorToTangent(MaterialInput input, float3 worldVector)
|
|
{
|
|
return mul(input.TBN, worldVector);
|
|
}
|
|
|
|
// Transforms a vector from world space to view space
|
|
float3 TransformWorldVectorToView(MaterialInput input, float3 worldVector)
|
|
{
|
|
return mul(worldVector, (float3x3)ViewMatrix);
|
|
}
|
|
|
|
// Transforms a vector from view space to world space
|
|
float3 TransformViewVectorToWorld(MaterialInput input, float3 viewVector)
|
|
{
|
|
return mul((float3x3)ViewMatrix, viewVector);
|
|
}
|
|
|
|
// Transforms a vector from local space to world space
|
|
float3 TransformLocalVectorToWorld(MaterialInput input, float3 localVector)
|
|
{
|
|
float3x3 localToWorld = (float3x3)WorldMatrix;
|
|
return mul(localVector, localToWorld);
|
|
}
|
|
|
|
// Transforms a vector from local space to world space
|
|
float3 TransformWorldVectorToLocal(MaterialInput input, float3 worldVector)
|
|
{
|
|
float3x3 localToWorld = (float3x3)WorldMatrix;
|
|
return mul(localToWorld, worldVector);
|
|
}
|
|
|
|
// Gets the current object position (supports instancing)
|
|
float3 GetObjectPosition(MaterialInput input)
|
|
{
|
|
return WorldMatrix[3].xyz;
|
|
}
|
|
|
|
// Gets the current object size
|
|
float3 GetObjectSize(MaterialInput input)
|
|
{
|
|
return float3(1, 1, 1);
|
|
}
|
|
|
|
// Gets the current object scale (supports instancing)
|
|
float3 GetObjectScale(MaterialInput input)
|
|
{
|
|
return float3(1, 1, 1);
|
|
}
|
|
|
|
// Get the current object random value supports instancing)
|
|
float GetPerInstanceRandom(MaterialInput input)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
// Get the current object LOD transition dither factor (supports instancing)
|
|
float GetLODDitherFactor(MaterialInput input)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
// Gets the interpolated vertex color (in linear space)
|
|
float4 GetVertexColor(MaterialInput input)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
@8
|
|
|
|
// Get material properties function (for pixel shader)
|
|
Material GetMaterialPS(MaterialInput input)
|
|
{
|
|
@4
|
|
}
|
|
|
|
// Input macro specified by the material: DECAL_BLEND_MODE
|
|
#define DECAL_BLEND_MODE_TRANSLUCENT 0
|
|
#define DECAL_BLEND_MODE_STAIN 1
|
|
#define DECAL_BLEND_MODE_NORMAL 2
|
|
#define DECAL_BLEND_MODE_EMISSIVE 3
|
|
|
|
// Vertex Shader function for decals rendering
|
|
META_VS(true, FEATURE_LEVEL_ES2)
|
|
META_VS_IN_ELEMENT(POSITION, 0, R32G32B32_FLOAT, 0, 0, PER_VERTEX, 0, true)
|
|
void VS_Decal(in float3 Position : POSITION0, out float4 SvPosition : SV_Position)
|
|
{
|
|
// Compute world space vertex position
|
|
float3 worldPosition = mul(float4(Position.xyz, 1), WorldMatrix).xyz;
|
|
|
|
// Compute clip space position
|
|
SvPosition = mul(float4(worldPosition.xyz, 1), ViewProjectionMatrix);
|
|
}
|
|
|
|
// Pixel Shader function for decals rendering
|
|
META_PS(true, FEATURE_LEVEL_ES2)
|
|
void PS_Decal(
|
|
in float4 SvPosition : SV_Position
|
|
, out float4 Out0 : SV_Target0
|
|
#if DECAL_BLEND_MODE == DECAL_BLEND_MODE_TRANSLUCENT
|
|
, out float4 Out1 : SV_Target1
|
|
#if USE_NORMAL || USE_EMISSIVE
|
|
, out float4 Out2 : SV_Target2
|
|
#endif
|
|
#if USE_NORMAL && USE_EMISSIVE
|
|
, out float4 Out3 : SV_Target3
|
|
#endif
|
|
#endif
|
|
)
|
|
{
|
|
// Stencil masking
|
|
uint stencilObjectLayer = STENCIL_BUFFER_OBJECT_LAYER(STENCIL_BUFFER_LOAD(StencilBuffer, SvPosition.xy));
|
|
if ((RenderLayersMask & (1 << stencilObjectLayer)) == 0)
|
|
{
|
|
clip(-1);
|
|
return;
|
|
}
|
|
|
|
float2 screenUV = SvPosition.xy * ScreenSize.zw;
|
|
SvPosition.z = SAMPLE_RT(DepthBuffer, screenUV).r;
|
|
|
|
float4 positionHS = mul(float4(SvPosition.xyz, 1), SvPositionToWorld);
|
|
float3 positionWS = positionHS.xyz / positionHS.w;
|
|
float3 positionOS = mul(float4(positionWS, 1), InvWorld).xyz;
|
|
|
|
clip(0.5 - abs(positionOS.xyz));
|
|
float2 decalUVs = positionOS.xz + 0.5f;
|
|
|
|
// Setup material input
|
|
MaterialInput materialInput = (MaterialInput)0;
|
|
materialInput.WorldPosition = positionWS;
|
|
materialInput.TexCoord = decalUVs;
|
|
materialInput.TwoSidedSign = 1;
|
|
materialInput.SvPosition = SvPosition;
|
|
materialInput.TexCoord_DDX_DDY = CalculateTextureDerivatives(materialInput.SvPosition, materialInput.TexCoord);
|
|
|
|
// Calculate tangent-space
|
|
float3 ddxWp = ddx(positionWS);
|
|
float3 ddyWp = ddy(positionWS);
|
|
materialInput.TBN[0] = normalize(ddyWp);
|
|
materialInput.TBN[1] = normalize(ddxWp);
|
|
materialInput.TBN[2] = normalize(cross(ddxWp, ddyWp));
|
|
|
|
// Sample material
|
|
Material material = GetMaterialPS(materialInput);
|
|
|
|
// Masking
|
|
#if MATERIAL_MASKED
|
|
clip(material.Mask - MATERIAL_MASK_THRESHOLD);
|
|
#endif
|
|
|
|
// Set the output
|
|
#if DECAL_BLEND_MODE == DECAL_BLEND_MODE_TRANSLUCENT
|
|
// GBuffer0
|
|
Out0 = float4(material.Color, material.Opacity);
|
|
// GBuffer2
|
|
Out1 = float4(material.Roughness, material.Metalness, material.Specular, material.Opacity);
|
|
#if USE_EMISSIVE
|
|
// Light Buffer
|
|
Out2 = float4(material.Emissive, material.Opacity);
|
|
#if USE_NORMAL
|
|
// GBuffer1
|
|
Out3 = float4(material.WorldNormal * 0.5f + 0.5f, material.Opacity);
|
|
#endif
|
|
#elif USE_NORMAL
|
|
// GBuffer1
|
|
Out2 = float4(material.WorldNormal * 0.5f + 0.5f, material.Opacity);
|
|
#endif
|
|
#elif DECAL_BLEND_MODE == DECAL_BLEND_MODE_STAIN
|
|
Out0 = float4(material.Color, material.Opacity);
|
|
#elif DECAL_BLEND_MODE == DECAL_BLEND_MODE_NORMAL
|
|
Out0 = float4(material.WorldNormal * 0.5f + 0.5f, material.Opacity);
|
|
#elif DECAL_BLEND_MODE == DECAL_BLEND_MODE_EMISSIVE
|
|
Out0 = float4(material.Emissive * material.Opacity, material.Opacity);
|
|
#else
|
|
#error "Invalid decal blending mode"
|
|
#endif
|
|
}
|
|
|
|
@9
|