浏览代码

Clean up the math of the Disney SSS

/Yibing-Project-2
Evgenii Golubev 7 年前
当前提交
885726ed
共有 2 个文件被更改,包括 27 次插入32 次删除
  1. 17
      ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Resources/SubsurfaceScattering.compute
  2. 42
      ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/SubsurfaceScatteringSettings.cs

17
ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Resources/SubsurfaceScattering.compute


}
}
// Computes the value of the integrand over a disk: (2 * PI * r) * KernelVal().
// N.b.: the returned value is multiplied by 4. It is irrelevant due to weight renormalization.
float3 KernelValCircle(float r, float3 S)
// Computes the value of the integrand in polar coordinates: f(r, s) = r * R(r, s).
// f(r, s) = (Exp[-r * s] + Exp[-r * s / 3]) * (s / (8 * Pi))
// We can drop the constant (s / (8 * Pi)) due to the subsequent weight renormalization.
float3 DisneyProfilePolar(float r, float3 S)
return /* 0.25 * */ S * (expOneThird + expOneThird * expOneThird * expOneThird);
return expOneThird + expOneThird * expOneThird * expOneThird;
// Computes F(r)/P(r), s.t. r = sqrt(xy^2 + z^2).
// Computes f(r, s)/p(r, s), s.t. r = sqrt(xy^2 + z^2).
// Rescaling of the PDF is handled by 'totalWeight'.
float3 ComputeBilateralWeight(float xy2, float z, float mmPerUnit, float3 S, float rcpPdf)
{

#endif
#if SSS_CLAMP_ARTIFACT
return saturate(KernelValCircle(r, S) * rcpPdf);
return saturate(DisneyProfilePolar(r, S) * rcpPdf);
return KernelValCircle(r, S) * rcpPdf;
return DisneyProfilePolar(r, S) * rcpPdf;
#endif
}

float centerRadius = _FilterKernels[profileID][0][iR];
float centerRcpPdf = _FilterKernels[profileID][0][iP];
float3 centerWeight = KernelValCircle(centerRadius, shapeParam) * centerRcpPdf;
float3 centerWeight = DisneyProfilePolar(centerRadius, shapeParam) * centerRcpPdf;
// Accumulate filtered irradiance and bilateral weights (for renormalization).
float3 totalIrradiance = centerWeight * centerIrradiance;

42
ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/SubsurfaceScatteringSettings.cs


// We importance sample the color channel with the widest scattering distance.
float s = Mathf.Min(shapeParam.x, shapeParam.y, shapeParam.z);
// Importance sample the normalized diffusion profile for the computed value of 's'.
// Importance sample the normalized diffuse reflectance profile for the computed value of 's'.
// R(r, s) = s * (Exp[-r * s] + Exp[-r * s / 3]) / (8 * Pi * r)
// PDF(r, s) = s * (Exp[-r * s] + Exp[-r * s / 3]) / 4
// CDF(r, s) = 1 - 1/4 * Exp[-r * s] - 3/4 * Exp[-r * s / 3]
// R[r, phi, s] = s * (Exp[-r * s] + Exp[-r * s / 3]) / (8 * Pi * r)
// PDF[r, phi, s] = r * R[r, phi, s]
// CDF[r, s] = 1 - 1/4 * Exp[-r * s] - 3/4 * Exp[-r * s / 3]
// ------------------------------------------------------------------------------------
// Importance sample the near field kernel.

float r = KernelCdfInverse(p, s);
float r = DisneyProfileCdfInverse(p, s);
filterKernelNearField[i].y = 1f / KernelPdf(r, s);
filterKernelNearField[i].y = 1f / DisneyProfilePdf(r, s);
}
// Importance sample the far field kernel.

float r = KernelCdfInverse(p, s);
float r = DisneyProfileCdfInverse(p, s);
filterKernelFarField[i].y = 1f / KernelPdf(r, s);
filterKernelFarField[i].y = 1f / DisneyProfilePdf(r, s);
}
maxRadius = filterKernelFarField[SssConstants.SSS_N_SAMPLES_FAR_FIELD - 1].x;

}
// <<< Old SSS Model
static float KernelVal(float r, float s)
static float DisneyProfile(float r, float s)
// Computes the value of the integrand over a disk: (2 * PI * r) * KernelVal().
static float KernelValCircle(float r, float s)
static float DisneyProfilePdf(float r, float s)
return 0.25f * s * (Mathf.Exp(-r * s) + Mathf.Exp(-r * s * (1.0f / 3.0f)));
return r * DisneyProfile(r, s);
static float KernelPdf(float r, float s)
{
return KernelValCircle(r, s);
}
static float KernelCdf(float r, float s)
static float DisneyProfileCdf(float r, float s)
static float KernelCdfDerivative1(float r, float s)
static float DisneyProfileCdfDerivative1(float r, float s)
static float KernelCdfDerivative2(float r, float s)
static float DisneyProfileCdfDerivative2(float r, float s)
{
return (-1.0f / 12.0f) * s * s * Mathf.Exp(-r * s) * (3.0f + Mathf.Exp(r * s * (2.0f / 3.0f)));
}

static float KernelCdfInverse(float p, float s)
static float DisneyProfileCdfInverse(float p, float s)
{
// Supply the initial guess.
float r = (Mathf.Pow(10f, p) - 1f) / s;

{
float f0 = KernelCdf(r, s) - p;
float f1 = KernelCdfDerivative1(r, s);
float f2 = KernelCdfDerivative2(r, s);
float f0 = DisneyProfileCdf(r, s) - p;
float f1 = DisneyProfileCdfDerivative1(r, s);
float f2 = DisneyProfileCdfDerivative2(r, s);
float dr = f0 / (f1 * (1f - f0 * f2 / (2f * f1 * f1)));
if (Mathf.Abs(dr) < t)

正在加载...
取消
保存