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

165 行
8.2 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, int mapMask, inout float blend, float lod)
{
float4 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;
}
void ApplyBlendMask(inout float4 dst, inout int matMask, float2 texCoords, int mapMask, float blend, float lod)
{
float4 src = SAMPLE_TEXTURE2D_LOD(_DecalAtlas2D, _trilinear_clamp_sampler_DecalAtlas2D, texCoords, lod);
src.z = src.w;
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 AddDecalContribution(PositionInputs posInput, inout SurfaceData surfaceData, inout float alpha)
{
if(_EnableDBuffer)
{
DecalSurfaceData decalSurfaceData;
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 LIGHTLOOP_TILE_PASS
GetCountAndStart(posInput, LIGHTCATEGORY_DECAL, decalStart, decalCount);
#else
decalCount = _DecalCount;
decalStart = 0;
#endif
float3 positionWS = GetAbsolutePositionWS(posInput.positionWS);
// get world space ddx/ddy for adjacent pixels to be used later in mipmap lod calculation
float3 positionWSDdx = ddx(positionWS);
float3 positionWSDdy = ddy(positionWS);
for (uint i = 0; i < decalCount; i++)
{
DecalData decalData = FetchDecal(decalStart, i);
float3 positionDS = mul(decalData.worldToDecal, float4(positionWS, 1.0)).xyz;
positionDS = positionDS * float3(1.0, -1.0, 1.0) + float3(0.5, 0.0f, 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(decalData.worldToDecal, float4(positionWSDdx, 0.0)).xyz; // transform the derivatives to decal space, any translation is irrelevant
float3 positionDSDdy = mul(decalData.worldToDecal, float4(positionWSDdy, 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 decalBlend = decalData.normalToWorld[0][3];
if((decalData.diffuseScaleBias.x > 0) && (decalData.diffuseScaleBias.y > 0))
{
ApplyBlendDiffuse(DBuffer0, mask, sampleDiffuse, DBUFFERHTILEBIT_DIFFUSE, decalBlend, lodDiffuse);
float albedoContribution = decalData.normalToWorld[1][3];
if (albedoContribution == 0.0f)
{
mask = 0; // diffuse will not get modified
}
alpha = alpha < decalBlend ? decalBlend : alpha; // use decal alpha if it is higher than transparent alpha
}
if ((decalData.normalScaleBias.x > 0) && (decalData.normalScaleBias.y > 0))
{
ApplyBlendNormal(DBuffer1, mask, sampleNormal, DBUFFERHTILEBIT_NORMAL, (float3x3)decalData.normalToWorld, decalBlend, lodNormal);
}
if ((decalData.maskScaleBias.x > 0) && (decalData.maskScaleBias.y > 0))
{
ApplyBlendMask(DBuffer2, mask, sampleMask, DBUFFERHTILEBIT_MASK, decalBlend, lodMask);
}
}
}
#else
mask = UnpackByte(LOAD_TEXTURE2D(_DecalHTileTexture, posInput.positionSS / 8).r);
#endif
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)
{
surfaceData.metallic = surfaceData.metallic * decalSurfaceData.mask.w + decalSurfaceData.mask.x;
surfaceData.ambientOcclusion = surfaceData.ambientOcclusion * decalSurfaceData.mask.w + decalSurfaceData.mask.y;
surfaceData.perceptualSmoothness = surfaceData.perceptualSmoothness * decalSurfaceData.mask.w + decalSurfaceData.mask.z;
}
}
}