浏览代码

Use HW trilinear filtering for V-Buffer sampling

/Yibing-Project-2
Evgenii Golubev 7 年前
当前提交
4d0996e2
共有 3 个文件被更改,包括 31 次插入56 次删除
  1. 53
      ScriptableRenderPipeline/Core/ShaderLibrary/VolumeRendering.hlsl
  2. 32
      ScriptableRenderPipeline/HDRenderPipeline/Lighting/Volumetrics/Resources/VolumetricLighting.compute
  3. 2
      ScriptableRenderPipeline/HDRenderPipeline/Sky/AtmosphericScattering/AtmosphericScattering.hlsl

53
ScriptableRenderPipeline/Core/ShaderLibrary/VolumeRendering.hlsl


#include "Random.hlsl"
// Returns linearly interpolated {volumetric radiance, opacity}. The sampler clamps to edge.
float4 SampleInScatteredRadianceAndTransmittance(TEXTURE3D_ARGS(VBufferLighting, linearClampSampler),
float2 positionNDC, float linearDepth,
float2 VBufferScale, float4 VBufferDepthEncodingParams)
// Samples the linearly interpolated V-Buffer.
// If (clampToEdge == false), out-of-bounds loads return 0.
float4 SampleVBuffer(TEXTURE3D_ARGS(VBufferLighting, trilinearSampler), bool clampToEdge,
float2 positionNDC, float linearDepth,
float2 VBufferScale,
float4 VBufferDepthEncodingParams)
// TODO: Add some kind of jitter to the look-up.
// TODO: Also add some kind of animated 3D noise to the sampled result.
// d -= GenerateHashedRandomFloat(asuint(positionNDC)) / (2 * k);
float4 L;
// Unity doesn't support samplers clamping to border, so we have to do it ourselves.
// TODO: add the proper sampler support.
bool isInBounds = Min3(uv.x, uv.y, d) > 0 && Max3(uv.x, uv.y, d) < 1;
[branch] if (d != saturate(d))
[branch] if (clampToEdge || isInBounds)
// We are in front of the near or behind the far plane of the V-buffer.
// The sampler will clamp to edge.
L = SAMPLE_TEXTURE3D_LOD(VBufferLighting, linearClampSampler, float3(uv, d), 0);
}
else
{
// We cannot use hardware trilinear interpolation since the distance between slices is log-encoded.
// Therefore, we perform 2 bilinear taps.
// TODO: test the visual difference in practice.
// The distance between slices is log-encoded.
float s0 = floor(d * k - 0.5);
float s1 = ceil(d * k - 0.5);
float d0 = saturate(s0 * rcp(k) + (0.5 * rcp(k)));

// The sampler will clamp to edge.
// TODO: adjust the texture coordinate and take a single HW trlinear sample.
float4 L0 = SAMPLE_TEXTURE3D_LOD(VBufferLighting, linearClampSampler, float3(uv, d0), 0);
float4 L1 = SAMPLE_TEXTURE3D_LOD(VBufferLighting, linearClampSampler, float3(uv, d1), 0);
// Compute the linear Z-interpolation weight.
float a = saturate((z - z0) / (z1 - z0));
float w = d0 + a * rcp(k);
L = lerp(L0, L1, saturate((z - z0) / (z1 - z0)));
// Adjust the texture coordinate and take a single HW trlinear sample.
return SAMPLE_TEXTURE3D_LOD(VBufferLighting, trilinearSampler, float3(uv, w), 0);
else
{
return 0;
}
}
// Returns linearly interpolated {volumetric radiance, opacity}. The sampler clamps to edge.
float4 SampleInScatteredRadianceAndTransmittance(TEXTURE3D_ARGS(VBufferLighting, trilinearSampler),
float2 positionNDC, float linearDepth,
float2 VBufferScale, float4 VBufferDepthEncodingParams)
{
float4 L = SampleVBuffer(TEXTURE3D_PARAM(VBufferLighting, trilinearSampler), true,
positionNDC, linearDepth, VBufferScale, VBufferDepthEncodingParams);
return float4(L.rgb, 1 - Transmittance(L.a));
}

32
ScriptableRenderPipeline/HDRenderPipeline/Lighting/Volumetrics/Resources/VolumetricLighting.compute


return voxelRadiance;
}
// Samples the linearly interpolated V-Buffer. Out-of-bounds loads return 0.
float4 SampleVBuffer(TEXTURE3D_ARGS(VBufferLighting, trilinearSampler),
float2 positionNDC, float linearDepth,
float2 VBufferScale,
float4 VBufferDepthEncodingParams)
{
int k = VBUFFER_SLICE_COUNT;
float z = linearDepth;
float d = EncodeLogarithmicDepth(z, VBufferDepthEncodingParams);
// Account for the visible area of the V-Buffer.
float2 uv = positionNDC * VBufferScale;
// TODO: Unity doesn't support samplers clamping to border, so we have to do it ourselves.
bool isInBounds = Min3(uv.x, uv.y, d) > 0 && Max3(uv.x, uv.y, d) < 1;
[branch] if (isInBounds)
{
// We use hardware trilinear filtering.
// In theory, this is wrong, since the distance between slices is log-encoded.
// In practice, doing the right thing in a loop is simply too expensive.
// TODO: adjust the texture coordinate and take a single HW trlinear sample.
return SAMPLE_TEXTURE3D_LOD(VBufferLighting, trilinearSampler, float3(uv, d), 0);
}
else
{
return 0;
}
}
// Computes the in-scattered radiance along the ray.
void FillVolumetricLightingBuffer(LightLoopContext context, uint featureFlags,
PositionInputs posInput, Ray ray)

float2 reprojPosNDC = ComputeNormalizedDeviceCoordinates(centerWS, _PrevViewProjMatrix);
float reprojZ = mul(_PrevViewProjMatrix, float4(centerWS, 1)).w;
float4 reprojValue = SampleVBuffer(TEXTURE3D_PARAM(_VBufferLightingHistory, s_trilinear_clamp_sampler),
reprojPosNDC, reprojZ,
false, reprojPosNDC, reprojZ,
_VBufferResolutionAndScale.zw,
_VBufferDepthEncodingParams);

2
ScriptableRenderPipeline/HDRenderPipeline/Sky/AtmosphericScattering/AtmosphericScattering.hlsl


float4 EvaluateAtmosphericScattering(PositionInputs posInput)
{
#ifdef VOLUMETRIC_LIGHTING_ENABLED
return SampleInScatteredRadianceAndTransmittance(TEXTURE3D_PARAM(_VBufferLighting, s_linear_clamp_sampler),
return SampleInScatteredRadianceAndTransmittance(TEXTURE3D_PARAM(_VBufferLighting, s_trilinear_clamp_sampler),
posInput.positionNDC, posInput.linearDepth,
_VBufferResolutionAndScale.zw,
_VBufferDepthEncodingParams);

正在加载...
取消
保存