浏览代码

Implement the initial version of SSS LOD

/RenderPassXR_Sandbox
Evgenii Golubev 8 年前
当前提交
dcecf746
共有 3 个文件被更改,包括 85 次插入17 次删除
  1. 86
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Resources/CombineSubsurfaceScattering.shader
  2. 14
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/SubsurfaceScatteringProfile.cs
  3. 2
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/SubsurfaceScatteringProfile.cs.hlsl

86
Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Resources/CombineSubsurfaceScattering.shader


#pragma vertex Vert
#pragma fragment Frag
#define SSS_PASS
#define SSS_PASS 1
#define SSS_DEBUG 0
#define MILLIMETERS_PER_METER 1000
//-------------------------------------------------------------------------------------

float2 samplePosition = posInput.unPositionSS;
float3 sampleIrradiance = LOAD_TEXTURE2D(_IrradianceSource, samplePosition).rgb;
float maxDistancePixels = maxDistance * max(scaledPixPerMm.x, scaledPixPerMm.y);
if (maxDistance * max(scaledPixPerMm.x, scaledPixPerMm.y) < 0.5)
if (maxDistancePixels < 0.5)
#if SSS_DEBUG
return float4(0, 0, 1, 1);
#else
#endif
bool useNearFieldKernel = true; // TODO
// Accumulate filtered irradiance and bilateral weights (for renormalization).
float3 totalIrradiance, totalWeight;
if (useNearFieldKernel)
// Use fewer samples for SS regions smaller than 4x4 pixels.
[branch]
if (maxDistancePixels < 4)
float sampleRcpPdf = _FilterKernelsNearField[profileID][0][1];
#if SSS_DEBUG
return float4(0.5, 0.5, 0, 1);
#endif
float sampleRcpPdf = _FilterKernelsFarField[profileID][0][1];
// Accumulate filtered irradiance and bilateral weights (for renormalization).
float3 totalIrradiance = sampleWeight * sampleIrradiance;
float3 totalWeight = sampleWeight;
totalIrradiance = sampleWeight * sampleIrradiance;
totalWeight = sampleWeight;
[unroll]
for (uint i = 1; i < SSS_N_SAMPLES_FAR_FIELD; i++)
{
// Everything except for the radius is a compile-time constant.
float r = _FilterKernelsFarField[profileID][i][0];
float phi = TWO_PI * Fibonacci2d(i, SSS_N_SAMPLES_FAR_FIELD).y;
float2 pos = r * float2(cos(phi), sin(phi));
samplePosition = posInput.unPositionSS + pos * scaledPixPerMm;
sampleRcpPdf = _FilterKernelsFarField[profileID][i][1];
rawDepth = LOAD_TEXTURE2D(_MainDepthTexture, samplePosition).r;
sampleIrradiance = LOAD_TEXTURE2D(_IrradianceSource, samplePosition).rgb;
[flatten]
if (any(sampleIrradiance) == false)
{
// The irradiance is 0. This could happen for 3 reasons.
// Most likely, the surface fragment does not have an SSS material.
// Alternatively, our sample comes from a region without any geometry.
// Finally, the surface fragment could be completely shadowed.
// Our blur is energy-preserving, so 'sampleWeight' should be set to 0.
// We do not terminate the loop since we want to gather the contribution
// of the remaining samples (e.g. in case of hair covering skin).
continue;
}
// Apply bilateral weighting.
float sampleZ = LinearEyeDepth(rawDepth, _ZBufferParams);
float z = millimPerUnit * sampleZ - (millimPerUnit * centerPosVS.z);
sampleWeight = ComputeBilateralWeight(shapeParam, r, z, rcp(distScale), sampleRcpPdf);
totalIrradiance += sampleWeight * sampleIrradiance;
totalWeight += sampleWeight;
}
}
else
{
#if SSS_DEBUG
return float4(1, 0, 0, 1);
#endif
float sampleRcpPdf = _FilterKernelsNearField[profileID][0][1];
float3 sampleWeight = KernelValCircle(0, shapeParam) * sampleRcpPdf;
totalIrradiance = sampleWeight * sampleIrradiance;
totalWeight = sampleWeight;
// Perform integration over the screen-aligned plane in the view space.
// TODO: it would be more accurate to use the tangent plane in the world space.
[unroll]
for (uint i = 1; i < SSS_N_SAMPLES_NEAR_FIELD; i++)
{

totalIrradiance += sampleWeight * sampleIrradiance;
totalWeight += sampleWeight;
}
return float4(bsdfData.diffuseColor * totalIrradiance / totalWeight, 1);
else
{
return float4(0, 0, 0, 1); // TODO
}
return float4(bsdfData.diffuseColor * totalIrradiance / totalWeight, 1);
}
ENDHLSL
}

14
Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/SubsurfaceScatteringProfile.cs


public const int SSS_N_PROFILES = 8; // Max. number of profiles, including the slot taken by the neutral profile
public const int SSS_NEUTRAL_PROFILE_ID = SSS_N_PROFILES - 1; // Does not result in blurring
public const int SSS_N_SAMPLES_NEAR_FIELD = 55; // Used for extreme close ups; must be a Fibonacci number
public const int SSS_N_SAMPLES_FAR_FIELD = 34; // Used at a regular distance; must be a Fibonacci number
public const int SSS_N_SAMPLES_FAR_FIELD = 21; // Used at a regular distance; must be a Fibonacci number
public const int SSS_TRSM_MODE_NONE = 0;
public const int SSS_TRSM_MODE_THIN = 1;
}

m_ScatteringDistance = m_FilterKernelNearField[SssConstants.SSS_N_SAMPLES_NEAR_FIELD - 1].x;
// TODO: far field.
// Importance sample the far field kernel.
for (int i = 0; i < SssConstants.SSS_N_SAMPLES_FAR_FIELD; i++)
{
float p = i * (1.0f / SssConstants.SSS_N_SAMPLES_FAR_FIELD);
float r = KernelCdfInverse(p, s);
// N.b.: computation of normalized weights, and multiplication by the surface albedo
// of the actual geometry is performed at runtime (in the shader).
m_FilterKernelFarField[i].x = r;
m_FilterKernelFarField[i].y = 1.0f / KernelPdf(r, s);
}
}
public Vector3 shapeParameter

2
Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/SubsurfaceScatteringProfile.cs.hlsl


#define SSS_N_PROFILES (8)
#define SSS_NEUTRAL_PROFILE_ID (7)
#define SSS_N_SAMPLES_NEAR_FIELD (55)
#define SSS_N_SAMPLES_FAR_FIELD (34)
#define SSS_N_SAMPLES_FAR_FIELD (21)
#define SSS_TRSM_MODE_NONE (0)
#define SSS_TRSM_MODE_THIN (1)
正在加载...
取消
保存