Fix #61042: Cycles: Various Toon BSDF issues
The original bug report was that the Glossy Toon BSDF behaves incorrectly when mixed with other closures. The underlying issue here was that the eval function didn't check whether the reflection angle is inside the valid cone and always returned its PDF, which is very high compared to e.g. the diffuse closure's PDF for small sizes (since the cone is supposed to be quite tight) and therefore breaks MIS mixing. However, while looking into this, I found a number of other issues, and so this commit also contains several other changes to the Toon BSDFs: - The angle that was used to compute the intensity wasn't the actual angle between the vectors. From what I can see, the formula that was used goes back all the way to the initial commit 12 years ago, so this probably was something that happened to work with one particular cone sampling method. Now, however, it caused weird asymmetric highlights, so replace it with the actual angle (which we already compute anyways). - Setting size to zero caused the BSDF to go black, so clamp to 1e-5. - The code was overall a bit repetitive, so I've cleaned it up a bit.
This commit is contained in:
parent
b545770f5c
commit
02a488d0fe
@ -18,15 +18,20 @@ typedef struct ToonBsdf {
|
||||
|
||||
static_assert(sizeof(ShaderClosure) >= sizeof(ToonBsdf), "ToonBsdf is too large!");
|
||||
|
||||
ccl_device_inline int bsdf_toon_setup_common(ccl_private ToonBsdf *bsdf)
|
||||
{
|
||||
bsdf->size = clamp(bsdf->size, 1e-5f, 1.0f) * M_PI_2_F;
|
||||
bsdf->smooth = saturatef(bsdf->smooth) * M_PI_2_F;
|
||||
|
||||
return SD_BSDF | SD_BSDF_HAS_EVAL;
|
||||
}
|
||||
|
||||
/* DIFFUSE TOON */
|
||||
|
||||
ccl_device int bsdf_diffuse_toon_setup(ccl_private ToonBsdf *bsdf)
|
||||
{
|
||||
bsdf->type = CLOSURE_BSDF_DIFFUSE_TOON_ID;
|
||||
bsdf->size = saturatef(bsdf->size);
|
||||
bsdf->smooth = saturatef(bsdf->smooth);
|
||||
|
||||
return SD_BSDF | SD_BSDF_HAS_EVAL;
|
||||
return bsdf_toon_setup_common(bsdf);
|
||||
}
|
||||
|
||||
ccl_device float bsdf_toon_get_intensity(float max_angle, float smooth, float angle)
|
||||
@ -57,19 +62,17 @@ ccl_device Spectrum bsdf_diffuse_toon_eval(ccl_private const ShaderClosure *sc,
|
||||
ccl_private float *pdf)
|
||||
{
|
||||
ccl_private const ToonBsdf *bsdf = (ccl_private const ToonBsdf *)sc;
|
||||
float max_angle = bsdf->size;
|
||||
float smooth = bsdf->smooth;
|
||||
float cosNO = dot(bsdf->N, wo);
|
||||
|
||||
if (cosNO >= 0.0f) {
|
||||
float max_angle = bsdf->size * M_PI_2_F;
|
||||
float smooth = bsdf->smooth * M_PI_2_F;
|
||||
float angle = safe_acosf(fmaxf(cosNO, 0.0f));
|
||||
float sample_angle = bsdf_toon_get_sample_angle(max_angle, smooth);
|
||||
|
||||
float eval = bsdf_toon_get_intensity(max_angle, smooth, angle);
|
||||
|
||||
if (eval > 0.0f) {
|
||||
float sample_angle = bsdf_toon_get_sample_angle(max_angle, smooth);
|
||||
|
||||
*pdf = 0.5f * M_1_PI_F / (1.0f - cosf(sample_angle));
|
||||
if (angle < sample_angle) {
|
||||
float eval = bsdf_toon_get_intensity(max_angle, smooth, angle);
|
||||
*pdf = M_1_2PI_F / one_minus_cos(sample_angle);
|
||||
return make_spectrum(*pdf * eval);
|
||||
}
|
||||
}
|
||||
@ -87,29 +90,22 @@ ccl_device int bsdf_diffuse_toon_sample(ccl_private const ShaderClosure *sc,
|
||||
ccl_private float *pdf)
|
||||
{
|
||||
ccl_private const ToonBsdf *bsdf = (ccl_private const ToonBsdf *)sc;
|
||||
float max_angle = bsdf->size * M_PI_2_F;
|
||||
float smooth = bsdf->smooth * M_PI_2_F;
|
||||
float max_angle = bsdf->size;
|
||||
float smooth = bsdf->smooth;
|
||||
float sample_angle = bsdf_toon_get_sample_angle(max_angle, smooth);
|
||||
float angle = sample_angle * rand.x;
|
||||
|
||||
if (sample_angle > 0.0f) {
|
||||
float unused;
|
||||
*wo = sample_uniform_cone(bsdf->N, one_minus_cos(sample_angle), rand, &unused, pdf);
|
||||
float cosNO;
|
||||
*wo = sample_uniform_cone(bsdf->N, one_minus_cos(sample_angle), rand, &cosNO, pdf);
|
||||
|
||||
if (dot(Ng, *wo) > 0.0f) {
|
||||
*eval = make_spectrum(*pdf * bsdf_toon_get_intensity(max_angle, smooth, angle));
|
||||
}
|
||||
else {
|
||||
*eval = zero_spectrum();
|
||||
*pdf = 0.0f;
|
||||
}
|
||||
}
|
||||
else {
|
||||
*eval = zero_spectrum();
|
||||
*pdf = 0.0f;
|
||||
if (dot(Ng, *wo) > 0.0f) {
|
||||
float angle = acosf(cosNO);
|
||||
*eval = make_spectrum(*pdf * bsdf_toon_get_intensity(max_angle, smooth, angle));
|
||||
return LABEL_REFLECT | LABEL_DIFFUSE;
|
||||
}
|
||||
|
||||
return LABEL_REFLECT | LABEL_DIFFUSE;
|
||||
*pdf = 0.0f;
|
||||
*eval = zero_spectrum();
|
||||
return LABEL_NONE;
|
||||
}
|
||||
|
||||
/* GLOSSY TOON */
|
||||
@ -117,10 +113,7 @@ ccl_device int bsdf_diffuse_toon_sample(ccl_private const ShaderClosure *sc,
|
||||
ccl_device int bsdf_glossy_toon_setup(ccl_private ToonBsdf *bsdf)
|
||||
{
|
||||
bsdf->type = CLOSURE_BSDF_GLOSSY_TOON_ID;
|
||||
bsdf->size = saturatef(bsdf->size);
|
||||
bsdf->smooth = saturatef(bsdf->smooth);
|
||||
|
||||
return SD_BSDF | SD_BSDF_HAS_EVAL;
|
||||
return bsdf_toon_setup_common(bsdf);
|
||||
}
|
||||
|
||||
ccl_device Spectrum bsdf_glossy_toon_eval(ccl_private const ShaderClosure *sc,
|
||||
@ -129,8 +122,8 @@ ccl_device Spectrum bsdf_glossy_toon_eval(ccl_private const ShaderClosure *sc,
|
||||
ccl_private float *pdf)
|
||||
{
|
||||
ccl_private const ToonBsdf *bsdf = (ccl_private const ToonBsdf *)sc;
|
||||
float max_angle = bsdf->size * M_PI_2_F;
|
||||
float smooth = bsdf->smooth * M_PI_2_F;
|
||||
float max_angle = bsdf->size;
|
||||
float smooth = bsdf->smooth;
|
||||
float cosNI = dot(bsdf->N, wi);
|
||||
float cosNO = dot(bsdf->N, wo);
|
||||
|
||||
@ -140,12 +133,13 @@ ccl_device Spectrum bsdf_glossy_toon_eval(ccl_private const ShaderClosure *sc,
|
||||
float cosRO = dot(R, wo);
|
||||
|
||||
float angle = safe_acosf(fmaxf(cosRO, 0.0f));
|
||||
|
||||
float eval = bsdf_toon_get_intensity(max_angle, smooth, angle);
|
||||
float sample_angle = bsdf_toon_get_sample_angle(max_angle, smooth);
|
||||
|
||||
*pdf = 0.5f * M_1_PI_F / (1.0f - cosf(sample_angle));
|
||||
return make_spectrum(*pdf * eval);
|
||||
if (angle < sample_angle) {
|
||||
float eval = bsdf_toon_get_intensity(max_angle, smooth, angle);
|
||||
*pdf = M_1_2PI_F / one_minus_cos(sample_angle);
|
||||
return make_spectrum(*pdf * eval);
|
||||
}
|
||||
}
|
||||
*pdf = 0.0f;
|
||||
return zero_spectrum();
|
||||
@ -160,8 +154,8 @@ ccl_device int bsdf_glossy_toon_sample(ccl_private const ShaderClosure *sc,
|
||||
ccl_private float *pdf)
|
||||
{
|
||||
ccl_private const ToonBsdf *bsdf = (ccl_private const ToonBsdf *)sc;
|
||||
float max_angle = bsdf->size * M_PI_2_F;
|
||||
float smooth = bsdf->smooth * M_PI_2_F;
|
||||
float max_angle = bsdf->size;
|
||||
float smooth = bsdf->smooth;
|
||||
float cosNI = dot(bsdf->N, wi);
|
||||
|
||||
if (cosNI > 0) {
|
||||
@ -169,30 +163,21 @@ ccl_device int bsdf_glossy_toon_sample(ccl_private const ShaderClosure *sc,
|
||||
float3 R = (2 * cosNI) * bsdf->N - wi;
|
||||
|
||||
float sample_angle = bsdf_toon_get_sample_angle(max_angle, smooth);
|
||||
float angle = sample_angle * rand.x;
|
||||
|
||||
float unused;
|
||||
*wo = sample_uniform_cone(R, one_minus_cos(sample_angle), rand, &unused, pdf);
|
||||
float cosRO;
|
||||
*wo = sample_uniform_cone(R, one_minus_cos(sample_angle), rand, &cosRO, pdf);
|
||||
|
||||
if (dot(Ng, *wo) > 0.0f) {
|
||||
float cosNO = dot(bsdf->N, *wo);
|
||||
|
||||
/* make sure the direction we chose is still in the right hemisphere */
|
||||
if (cosNO > 0) {
|
||||
*eval = make_spectrum(*pdf * bsdf_toon_get_intensity(max_angle, smooth, angle));
|
||||
}
|
||||
else {
|
||||
*pdf = 0.0f;
|
||||
*eval = zero_spectrum();
|
||||
}
|
||||
}
|
||||
else {
|
||||
*pdf = 0.0f;
|
||||
*eval = zero_spectrum();
|
||||
/* make sure the direction we chose is still in the right hemisphere */
|
||||
if (dot(Ng, *wo) > 0.0f && dot(bsdf->N, *wo) > 0.0f) {
|
||||
float angle = acosf(cosRO);
|
||||
*eval = make_spectrum(*pdf * bsdf_toon_get_intensity(max_angle, smooth, angle));
|
||||
return LABEL_GLOSSY | LABEL_REFLECT;
|
||||
}
|
||||
}
|
||||
|
||||
return LABEL_GLOSSY | LABEL_REFLECT;
|
||||
*pdf = 0.0f;
|
||||
*eval = zero_spectrum();
|
||||
return LABEL_NONE;
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
Loading…
Reference in New Issue
Block a user