Nabla icon indicating copy to clipboard operation
Nabla copied to clipboard

Schussler et Al. implementation

Open devshgraphicsprogramming opened this issue 3 years ago • 0 comments

Description

Implement the 2nd order scattering with specular tangent microfacet, eq 23

Description of the related problem

Smooth Shading Normals Feasibility study

Implement on a small low poly sphere first, see if we can treat the smooth shading normal as-if it came from a object space normalmap.

vec3 value = brdf_cos_eval(L,V);

const float deviation = dot(shadingNormal,geometricNormal);
if (deviation<THRESHOLD) // THRESHOLD<1.f
{
   vec3 tangentFacet = normalize(shadingNormal-deviation*geometricNormal);
   
   // implement rest of schussler but without overoptimization
}

Remember to implement pre dot(V,geometricNormal)>FLT_MIN and post dot(L,geometricNormal)>FLT_MIN geometrical feasibility checks.

See if it doesn't spoil everything compared to regular smooth shading.

Solution proposal

Optimized visible facet probability calculation

Asserting that the deviation is positive (no backfacing or tangent normals).

// deviation = clamp_dot(shadingNormal,geometricNormal);
// a_p = clamp_dot(dir,shadingNormal)/deviation
// a_t = clamp_dot(dir,tangentFacet)*sqrt(1.f-deviation*deviation)/deviation

// a_p/(a_p+a_t)
float shadingNormal_vpdf(in vec3 dir, in float deviation, in vec3 tangentFacet)
{
   const float cosTheta = clamp_dot(dir,shadingNormal);
   return cosTheta/(cosTheta+clamp_dot(dir,tangentFacet)*sqrt(1.f-deviation*deviation));
}

Is it possible to squeeze something more out of dot(dir,tangentFacet)*sqrt(1.f-deviation*deviation) ? YES Before normalization, the length of tangentFacet is sin(deviationAngle) = sqrt(1.f-deviation*deviation)

float shadingNormal_vpdf(in float cXdotGeomN, in float clampedXdotShadingN, in float GeomNdotShadingN)
{
   assert(GeomNdotShadingN>=0.f);
   assert(XdotGeomN>0.f);
   return clampedXdotShadingN/(clampedXdotShadingN+max(XdotShadingN-GeomNdotShadingN*XdotGeomN,0.f));
}

Let the tangentFacet_vpdf = 1-shadingNormal_vpdf, there's nothing more optimal.

Optimized Masking Function (TODO triple check)

Same assertions as above

// <w_i,w_g>/(a_p+a_t)
float shadingNormal_masking(in float XdotGeomN, in float XdotShadingN, in float GeomNdotShadingN, enum facet)
{
   assert(GeomNdotShadingN>=0.f);
   assert(XdotGeomN>0.f);
   const float d = GeomNdotShadingN*XdotGeomN;
   if (XdotShadingN>d)
      return 1.f/(2.f*XdotShadingN/d-1.f);
   return facet==PERTURBED&&XdotShading>0.f ? 1.f:0.f;
}

Additional context

The 2nd order scattering Schussler BRDF is horribly expensive to evaluate.

Pay attention to Tangent Space in Anisotropic BxDFs

Tangent space needs to change when bump mapped (maybe construct tangent space after normal is perturbed).

Provide upgraded Microfacet Structs

Keep track of dot products of L,V and shading normal with geometrical normal.

Keep track of shading tangent space with reflected (around the schussler facet) V and L.

dot(X_refl,Y) = 2*dot(X,T)*dot(T,Y)-dot(X,Y)

Compute them only when there is enough deviation against geometrical normal and masking function says BRDF evaluation will have non-zero weight.

Make BxDF_cos functions capable of computing the triple evaluation at once

Certain computation can be shared, such as:

  • the V and L dependent factors which can be reused for masking function computation, and differential factors
  • some fresnel calculations

In the case of the Diffuse BRDF*cos, it only needs to be evaluated twice, not 3 times due to viewer invariance.

Figure out how to incorporate the Schussler model into BSDFs

What to do about transmission? Thankfully we can't have double refraction ;)

Material Compiler

Modify OPcode BUMP and its instruction heavily to compute new microfacet caches.

Implement triple choice in importance sampling (might be hard to make it work with the binary jump).

Maybe treat the microfacet scattering evaluations as sub-BxDFs, and associate bitmasks to scattering orders (for skipping evaluation of non-importance sampled BRDFs).

Pay attention to occupancy, no empty loop iterations, figure out how to skip to the next sub-BxDF (instruction stream fast forward loop before the instruction dispatch table?).

Investigate full-sum Quotient+PDF evaluation (less variance) vs stochastic sum (more variance, higher speed) in variants of pick sub BRDF only, pick one BRDF only.