[wgsl error]: 'fwidth' must only be called from uniform control flow
While transpiling glsl shaders to wgsl tint throws this error and fails.
error: 'fwidth' must only be called from uniform control flow
The error is from use of derivatives in a loop that might not have a uniform flow.
I think the root cause might be mx_subsurface_bsdf where mx_subsurface_scattering_approx based on the closureType.
Here is the function:
vec3 mx_subsurface_scattering_approx(vec3 N, vec3 L, vec3 P, vec3 albedo, vec3 mfp)
{
float curvature = length(fwidth(N)) / length(fwidth(P));
float radius = 1.0 / max(curvature, 0.01);
return albedo * mx_integrate_burley_diffusion(N, L, radius, mfp) / vec3(M_PI);
}
and loop
for (int activeLightIndex = 0; activeLightIndex < numLights; ++activeLightIndex)
...
mx_subsurface_bsdf(mx_subsurface_bsdf(closureData, subsurface, coat_affected_subsurface_color_out, subsurface_radius_scaled_out, subsurface_anisotropy, normal, subsurface_bsdf_out);
BSDF selected_subsurface_bsdf_out = BSDF(vec3(0.0),vec3(1.0));
...
Probably a suitable workaround would be to split mx_subsurface_bsdf?
One simple fix is to move the curvature computation outside the function
float curvature = length(fwidth(N)) / length(fwidth(P));
if (closureData.closureType == CLOSURE_TYPE_REFLECTION)
{
vec3 sss = mx_subsurface_scattering_approx(N, L, P, color, radius, curvature);
float NdotL = clamp(dot(N, L), M_FLOAT_EPS, 1.0);
float visibleOcclusion = 1.0 - NdotL * (1.0 - occlusion);
bsdf.response = sss * visibleOcclusion * weight;
}
Are there performance concerns introducing two length() calls (aka square root) for the indirect case where they aren't necessary? I know recently there have been a number of different conversations about render time performance. Maybe there's a way to stage this so it only affects WGSL? Or maybe the performance is less of a concern here...
I'm wondering if we need mx_subsurface_scattering in Web. Is there a use for this?