Cloth DFG Approximation

This document explores an analytical approximation of the DFG term in image-based lighting evaluation for a cloth BRDF.

Cloth BRDF

Our cloth BRDF uses an inverse Gaussian NDF based on the work of Ashikhmin. We also use a different, simplified, visibility term – as suggested by Neubelt and Pettineo – and a diffuse component smoothed by the Fresnel. The full BRDF is as follows:

(1-F(v·h))((Subscript[c, diffuse])/π)+((F(v,h)(Subscript[D, ashikhmin])(h))/(4(n·l+n·v-(n·l)(n·v))))

The Ashikhmin distribution itself is defined by:

(Subscript[D, ashikhmin])(v,h,α)=(1/(π(1+4(α^2))))(1+((4exp(((-(cot^2)(Subscript[θ, h]))/(α^2))))/((sin^4)(Subscript[θ, h]))))

Alternatively we can use the “Charlie” distribution proposed by Estevez and Kulla (Sony Imageworks):

(Subscript[D, charlie])(v,h,α)=((((1/α)+2) (sin^(1/α)) (Subscript[θ, h]))/(2 π))

Analytical approximation

To investigate possible approximations we use a reference generated using our tool cmgen. The DFG reference is an RG16F OpenEXR image computed by randomly sampling the hemisphere. Because it was not generated using importance sampling, the reference uses (2^22) samples per data point. The 3D plot of the reference shows that both data channels can be approximated using a dual Gaussian. In practice we use a true Gaussian multiplied by a simple inverse square.

ClearAll["Global`*"]

dfgCloth:=

d0:={0.24, 0.93, 0.1, 0.2};
d1:={2.0, -1.3, 0.4};
dfgClothApprox[roughness_,NoV_]:=Module[
{r},
r=Max[(1-(NoV*d1[[1]]+d1[[2]])^2),d1[[3]]]*(d0[[1]]*2^(-((1.0-roughness-d0[[2]])^2)/(2d0[[3]]^2))+(1-roughness)*d0[[4]]);
{r, r*0.03}
]
Plot3D[{ImageValue[dfgCloth,{x,y}],dfgClothApprox[x/128,y/128]},{x,0,128},{y,0,128},ImageSize->Large,PlotRange->{0,0.5},AxesLabel->{"Roughness","NoV","v"}]

Analytical approximation of the “Charlie” distribution

We follow a similar approach to approximate the “Charlie” distribution. The reference uses the same format and computation method as previously.

dfgClothCharlie:=

d0:={1.0, 0.95, 0.02, 0.0095};
dfgCharlieClothApprox[roughness_,NoV_]:=Module[
{r},
r=Min[18.0,(0.04+1-roughness)^64*(d0[[1]]*2^(-(1.0-NoV -d0[[2]])^2/(2*d0[[3]]^2)))+0.3*(1-roughness+0.2)
*NoV+(1-NoV+0.2)^2*(1-roughness)^8];
{r, r*d0[[3]]}
]
Plot3D[{ImageValue[dfgClothCharlie,{x,y}],dfgCharlieClothApprox[x/128,y/128]},{x,0,128},{y,0,128},ImageSize->Large,PlotRange->{0.0,1.0},AxesLabel->{"Roughness","NoV","v"}]

Validation

The approximation shown above is implemented in cmgen and used to regenerated a reference image. The resulting image is compared below to the analytical approximation to validate the implementation.

approx:=

Plot3D[{ImageValue[approx,{x,y}],ImageValue[dfgCloth,{x,y}]},{x,0,128},{y,0,128},ImageSize->Large,PlotRange->{0,0.5},AxesLabel->{"Roughness","NoV","v"}]

approxCharlie:=

Plot3D[{ImageValue[approxCharlie,{x,y}],ImageValue[dfgClothCharlie,{x,y}]},{x,0,128},{y,0,128},ImageSize->Large,PlotRange->{0,1.0},AxesLabel->{"Roughness","NoV","v"}]