您最多选择25个主题 主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 
 

243 行
11 KiB

#include "Decal.hlsl"
DECLARE_DBUFFER_TEXTURE(_DBufferTexture);
DecalData FetchDecal(uint start, uint i)
{
#ifdef LIGHTLOOP_TILE_PASS
int j = FetchIndex(start, i);
#else
int j = start + i;
#endif
return _DecalDatas[j];
}
// Caution: We can't compute LOD inside a dynamic loop. The gradient are not accessible.
// we need to find a way to calculate mips. For now just fetch first mip of the decals
void ApplyBlendNormal(inout float4 dst, inout int matMask, float2 texCoords, int mapMask, float3x3 decalToWorld, float blend, float lod)
{
float4 src;
src.xyz = mul(decalToWorld, UnpackNormalmapRGorAG(SAMPLE_TEXTURE2D_LOD(_DecalAtlas2D, _trilinear_clamp_sampler_DecalAtlas2D, texCoords, lod))) * 0.5f + 0.5f;
src.w = blend;
dst.xyz = src.xyz * src.w + dst.xyz * (1.0f - src.w);
dst.w = dst.w * (1.0f - src.w);
matMask |= mapMask;
}
void ApplyBlendDiffuse(inout float4 dst, inout int matMask, float2 texCoords, float4 src, int mapMask, inout float blend, float lod, int diffuseTextureBound)
{
if (diffuseTextureBound)
{
src *= SAMPLE_TEXTURE2D_LOD(_DecalAtlas2D, _trilinear_clamp_sampler_DecalAtlas2D, texCoords, lod);
}
src.w *= blend;
blend = src.w; // diffuse texture alpha affects all other channels
dst.xyz = src.xyz * src.w + dst.xyz * (1.0f - src.w);
dst.w = dst.w * (1.0f - src.w);
matMask |= mapMask;
}
// albedoBlend is overall decal blend combined with distance fade and albedo alpha
// decalBlend is decal blend with distance fade to be able to construct normal and mask blend if they come from mask map blue channel
// normalBlend is calculated in this function and used later to blend the normal
// blendParams are material settings to determing blend source and mode for normal and mask map
void ApplyBlendMask(inout float4 dbuffer2, inout float2 dbuffer3, inout int matMask, float2 texCoords, int mapMask, float albedoBlend, float lod, float decalBlend, inout float normalBlend, float3 blendParams) // too many blends!!!
{
float4 src = SAMPLE_TEXTURE2D_LOD(_DecalAtlas2D, _trilinear_clamp_sampler_DecalAtlas2D, texCoords, lod);
float maskBlend;
if (blendParams.x == 1.0f) // normal blend source is mask blue channel
normalBlend = src.z * decalBlend;
else
normalBlend = albedoBlend; // normal blend source is albedo alpha
if (blendParams.y == 1.0f) // mask blend source is mask blue channel
maskBlend = src.z * decalBlend;
else
maskBlend = albedoBlend; // mask blend siurce is albedo alpha
src.z = src.w; // remap so smoothness goes to blue and mask blend goes to alpha
src.w = maskBlend;
float4 dbuffer2Mask;
float2 dbuffer3Mask;
if (blendParams.z == 0)
{
dbuffer2Mask = float4(1, 1, 1, 1); // M, AO, S, S alpha
dbuffer3Mask = float2(1, 1); // M alpha, AO alpha
}
else if (blendParams.z == 1)
{
dbuffer2Mask = float4(1, 0, 0, 0); // M, _, _, _
dbuffer3Mask = float2(1, 0); // M alpha, _
}
else if (blendParams.z == 2)
{
dbuffer2Mask = float4(0, 1, 0, 0); // _, AO, _, _
dbuffer3Mask = float2(0, 1); // _, AO alpha
}
else if (blendParams.z == 3)
{
dbuffer2Mask = float4(1, 1, 0, 0); // M, AO, _, _
dbuffer3Mask = float2(1, 1); // M Alpha, AO alpha
}
else if (blendParams.z == 4)
{
dbuffer2Mask = float4(0, 0, 1, 1); // _, _, S, S alpha
dbuffer3Mask = float2(0, 0); // _, _
}
else if (blendParams.z == 5)
{
dbuffer2Mask = float4(1, 0, 1, 1); // M, _, S, S alpha
dbuffer3Mask = float2(1, 0); // M alpha, _
}
else if (blendParams.z == 6)
{
dbuffer2Mask = float4(0, 1, 1, 1); // _, AO, S, S alpha
dbuffer3Mask = float2(0, 1); // _, AO alpha
}
else if (blendParams.z == 7)
{
dbuffer2Mask = float4(1, 1, 1, 1); // M, AO, S, S alpha
dbuffer3Mask = float2(1, 1); // M alpha, AO alpha
}
dbuffer2.xyz = (dbuffer2Mask.xyz == 1) ? src.xyz * src.w + dbuffer2.xyz * (1.0f - src.w) : dbuffer2.xyz;
dbuffer2.w = (dbuffer2Mask.w == 1) ? dbuffer2.w * (1.0f - src.w) : dbuffer2.w;
dbuffer3.xy = (dbuffer3Mask.xy == 1) ? dbuffer3.xy * (1.0f - src.w) : dbuffer3.xy;
matMask |= mapMask;
}
void AddDecalContribution(PositionInputs posInput, inout SurfaceData surfaceData, inout float alpha)
{
if (_EnableDecals)
{
int mask = 0;
// the code in the macros, gets moved inside the conditionals by the compiler
FETCH_DBUFFER(DBuffer, _DBufferTexture, posInput.positionSS);
#ifdef _SURFACE_TYPE_TRANSPARENT // forward transparent using clustered decals
uint decalCount, decalStart;
DBuffer0 = float4(0.0f, 0.0f, 0.0f, 1.0f);
DBuffer1 = float4(0.5f, 0.5f, 0.5f, 1.0f);
DBuffer2 = float4(0.0f, 0.0f, 0.0f, 1.0f);
#ifdef DECALS_4RT
DBuffer3 = float2(1.0f, 1.0f);
#else
float2 DBuffer3 = float2(1.0f, 1.0f);
#endif
#ifdef LIGHTLOOP_TILE_PASS
GetCountAndStart(posInput, LIGHTCATEGORY_DECAL, decalStart, decalCount);
#else
decalCount = _DecalCount;
decalStart = 0;
#endif
float3 positionRWS = posInput.positionWS;
// get world space ddx/ddy for adjacent pixels to be used later in mipmap lod calculation
float3 positionRWSDdx = ddx(positionRWS);
float3 positionRWSDdy = ddy(positionRWS);
for (uint i = 0; i < decalCount; i++)
{
DecalData decalData = FetchDecal(decalStart, i);
// Get the relative world camera to decal matrix
float4x4 worldToDecal = ApplyCameraTranslationToInverseMatrix(decalData.worldToDecal);
float3 positionDS = mul(worldToDecal, float4(positionRWS, 1.0)).xyz;
positionDS = positionDS * float3(1.0, -1.0, 1.0) + float3(0.5, 0.5f, 0.5); // decal clip space
if ((all(positionDS.xyz > 0.0f) && all(1.0f - positionDS.xyz > 0.0f)))
{
float2 uvScale = float2(decalData.normalToWorld[3][0], decalData.normalToWorld[3][1]);
float2 uvBias = float2(decalData.normalToWorld[3][2], decalData.normalToWorld[3][3]);
positionDS.xz = positionDS.xz * uvScale + uvBias;
positionDS.xz = frac(positionDS.xz);
// clamp by half a texel to avoid sampling neighboring textures in the atlas
float2 clampAmount = float2(0.5f / _DecalAtlasResolution.x, 0.5f / _DecalAtlasResolution.y);
float2 diffuseMin = decalData.diffuseScaleBias.zw + clampAmount; // offset into atlas is in .zw
float2 diffuseMax = decalData.diffuseScaleBias.zw + decalData.diffuseScaleBias.xy - clampAmount; // scale relative to full atlas size is in .xy so total texture extent in atlas is (1,1) * scale
float2 normalMin = decalData.normalScaleBias.zw + clampAmount;
float2 normalMax = decalData.normalScaleBias.zw + decalData.normalScaleBias.xy - clampAmount;
float2 maskMin = decalData.maskScaleBias.zw + clampAmount;
float2 maskMax = decalData.maskScaleBias.zw + decalData.maskScaleBias.xy - clampAmount;
float2 sampleDiffuse = clamp(positionDS.xz * decalData.diffuseScaleBias.xy + decalData.diffuseScaleBias.zw, diffuseMin, diffuseMax);
float2 sampleNormal = clamp(positionDS.xz * decalData.normalScaleBias.xy + decalData.normalScaleBias.zw, normalMin, normalMax);
float2 sampleMask = clamp(positionDS.xz * decalData.maskScaleBias.xy + decalData.maskScaleBias.zw, maskMin, maskMax);
// need to compute the mipmap LOD manually because we are sampling inside a loop
float3 positionDSDdx = mul(worldToDecal, float4(positionRWSDdx, 0.0)).xyz; // transform the derivatives to decal space, any translation is irrelevant
float3 positionDSDdy = mul(worldToDecal, float4(positionRWSDdy, 0.0)).xyz;
float2 sampleDiffuseDdx = positionDSDdx.xz * decalData.diffuseScaleBias.xy; // factor in the atlas scale
float2 sampleDiffuseDdy = positionDSDdy.xz * decalData.diffuseScaleBias.xy;
float lodDiffuse = ComputeTextureLOD(sampleDiffuseDdx, sampleDiffuseDdy, _DecalAtlasResolution);
float2 sampleNormalDdx = positionDSDdx.xz * decalData.normalScaleBias.xy;
float2 sampleNormalDdy = positionDSDdy.xz * decalData.normalScaleBias.xy;
float lodNormal = ComputeTextureLOD(sampleNormalDdx, sampleNormalDdy, _DecalAtlasResolution);
float2 sampleMaskDdx = positionDSDdx.xz * decalData.maskScaleBias.xy;
float2 sampleMaskDdy = positionDSDdy.xz * decalData.maskScaleBias.xy;
float lodMask = ComputeTextureLOD(sampleMaskDdx, sampleMaskDdy, _DecalAtlasResolution);
float albedoBlend = decalData.normalToWorld[0][3];
float4 src = decalData.baseColor;
int diffuseTextureBound = (decalData.diffuseScaleBias.x > 0) && (decalData.diffuseScaleBias.y > 0);
ApplyBlendDiffuse(DBuffer0, mask, sampleDiffuse, src, DBUFFERHTILEBIT_DIFFUSE, albedoBlend, lodDiffuse, diffuseTextureBound);
alpha = alpha < albedoBlend ? albedoBlend : alpha; // use decal alpha if it is higher than transparent alpha
float albedoContribution = decalData.normalToWorld[1][3];
if (albedoContribution == 0.0f)
{
mask = 0; // diffuse will not get modified
}
float normalBlend = albedoBlend;
if ((decalData.maskScaleBias.x > 0) && (decalData.maskScaleBias.y > 0))
{
ApplyBlendMask(DBuffer2, DBuffer3, mask, sampleMask, DBUFFERHTILEBIT_MASK, albedoBlend, lodMask, decalData.normalToWorld[0][3], normalBlend, decalData.blendParams);
}
if ((decalData.normalScaleBias.x > 0) && (decalData.normalScaleBias.y > 0))
{
ApplyBlendNormal(DBuffer1, mask, sampleNormal, DBUFFERHTILEBIT_NORMAL, (float3x3)decalData.normalToWorld, normalBlend, lodNormal);
}
}
}
#else
mask = UnpackByte(LOAD_TEXTURE2D(_DecalHTileTexture, posInput.positionSS / 8).r);
#endif
DecalSurfaceData decalSurfaceData;
DECODE_FROM_DBUFFER(DBuffer, decalSurfaceData);
// using alpha compositing https://developer.nvidia.com/gpugems/GPUGems3/gpugems3_ch23.html
if (mask & DBUFFERHTILEBIT_DIFFUSE)
{
surfaceData.baseColor.xyz = surfaceData.baseColor.xyz * decalSurfaceData.baseColor.w + decalSurfaceData.baseColor.xyz;
}
if (mask & DBUFFERHTILEBIT_NORMAL)
{
surfaceData.normalWS.xyz = normalize(surfaceData.normalWS.xyz * decalSurfaceData.normalWS.w + decalSurfaceData.normalWS.xyz);
}
if (mask & DBUFFERHTILEBIT_MASK)
{
#ifdef DECALS_4RT // only smoothness in 3RT mode
surfaceData.metallic = surfaceData.metallic * decalSurfaceData.MAOSBlend.x + decalSurfaceData.mask.x;
surfaceData.ambientOcclusion = surfaceData.ambientOcclusion * decalSurfaceData.MAOSBlend.y + decalSurfaceData.mask.y;
#endif
surfaceData.perceptualSmoothness = surfaceData.perceptualSmoothness * decalSurfaceData.mask.w + decalSurfaceData.mask.z;
}
}
}