which resulted in bias when self intersection is excluded in forward scattering.
Below is a comparison using principled BSDF with emission. NEE and MIS were much brighter.
Pull Request: https://projects.blender.org/blender/blender/pulls/119440
This is a leftover from when there was a global option for transparent
shadows, but since it's now per material this makes no sense anymore.
Solution found by Olivier Maury.
Pull Request: https://projects.blender.org/blender/blender/pulls/117735
While investigating Blender compilation time for windows-arm64, we
identified two compilation units that were taking a long time to compile
(~1h each). This affects windows-x64 builds as well.
Pull Request: https://projects.blender.org/blender/blender/pulls/117534
The pre-4.0 Principled BSDF had a special diffuse BSDF that contained
the roughness value from the node. Since 4.0, the regular Diffuse BSDF is used,
so we need to ignore it when determining the roughness value for baking.
When a mesh light is shadow-linked to something with a specific
shader network it was possible that the emission_sd_storage was
not bit enough for sampling.
The shade_dedicate_light kernel only evaluates emission of either
light or mesh emitter and then resumes the regular path tracer.
There is no need to store closures.
This change makes it so a smaller storage is used, and also
passes flag to the shader evaluation function indicating that
closures are not to be stored.
Pull Request: https://projects.blender.org/blender/blender/pulls/116907
Along with the 4.1 libraries upgrade, we are bumping the clang-format
version from 8-12 to 17. This affects quite a few files.
If not already the case, you may consider pointing your IDE to the
clang-format binary bundled with the Blender precompiled libraries.
Cycles implements the "Taming the Shadow Terminator" paper by Matt Jen-Yuan
Chiang to solve shadow terminator issues when a bump map is applied, as well
as similar approach for the glossy reflection to ensure ray does not get
reflected to inside of the object.
This correction term is applied unconditionally, which makes it harder to have
full control over shading via normals for stylistic reasons.
This change exposes this corrective term as an option called "Bump Map
Correction" which is available in the shader settings next to the
"Transparent Shadows".
The reason to make it per-shader rather than per-object is to allow flexibility
of a control: it is possible that an object has multiple shaders attached to it,
and only some of them used for bump mapping. Another, and possibly stronger
reason to have it per-shader is ease of assets control: shader brings settings
which are needed for its proper behavior. So if material at some point
decides to take over normals, artists would not need to update settings on
every asset which uses that material.
The option is enabled by default, so there is no changes for existing setups.
Pull Request: https://projects.blender.org/blender/blender/pulls/113480
Now that there are different Fresnel types and the reflectance can be tinted,
it is better to sample based on the actually used Fresnel type, instead of
the original Fresnel. This also avoids computing Fresnel multiple times.
Pull Request: https://projects.blender.org/blender/blender/pulls/112158
Previously, the Principled BSDF used the Subsurface input to scale the radius.
When it was zero, it used a diffuse closure, otherwise a subsurface closure.
This sort of scaling input makes sense, but it should be specified in distance
units, rather than a 0..1 factor, so this commit changes the unit and renames
the input to Subsurface Scale.
Additionally, it adds support for mixing diffuse and subsurface components.
This is part of e.g. the OpenPBR spec, and the logic behind it is to support
modeling e.g. dirt or paint on top of skin. Before, materials would be either
fully diffuse (radius=0) or fully subsurface.
For typical materials, this mixing factor will be either zero or one
(just like metallic or transmission), but supporting fractional inputs makes
sense for e.g. smooth transitions at boundaries.
Another change is that there is no separate Subsurface Color anymore - before,
this was mixed with the Base Color using the Subsurface input as the factor,
but this was not really useful since that input was generally very small.
And finally, the handling of how the path enters the material for random walk
subsurface scattering is changed. Before, this always used lambertian (diffuse)
transmission, but this caused some problems, like overly white edges.
Instead, two different methods are now used, depending on the selected mode.
In Fixed Radius mode, the code assumes a simple medium boundary, and performs
refraction into the material using the main Roughness and IOR inputs.
Meanwhile, when not using Fixed Radius, the code assumes a more complex
boundary (as typically found on organic materials, e.g. skin), so the entry
bounce has a 50/50 chance of being either diffuse transmission or refraction
using the separate Subsurface IOR input and a fixed roughness of 1.
Credit for this method goes to Christophe Hery.
Pull Request: https://projects.blender.org/blender/blender/pulls/110989
the motivation was to give closures with low weight a higher pdf to pick
at the first bounce, in case the next interaction has high contribution.
However, there are several issues:
1. this is too much fine-tuned for a specific case, and only works well
when there is a strong contribution after reflection and very little
contribution after the transmission;
2. the logic in `bsdf_microfacet.h` was added when merging reflection
and refraction into a glass closure, since then it doesn't even work
well in the above case when mixed with other closures;
3. The behavior is inconsistent in `bsdf_microfacet_eval()` and
`bsdf_microfacet_sample()`;
4. such cases should be handled by more modern and more general methods
such as path guiding and denoiser;
5. it makes the code flow harder to follow
Delete this trick for now to pick the closures solely based on their
`sample_weight`. Can be added back (with proper fix in
`bsdf_microfacet`) if indeed necessary.
Overall, this commit reworks the component layering in the Principled BSDF
in order to ensure that energy is preserved and conserved.
This includes:
- Implementing support for the OSL `layer()` function
- Implementing albedo estimation for some of the closures for layering purposes
- The specular layer that the Principled BSDF uses has a proper tabulated
albedo lookup, the others are still approximations
- Removing the custom "Principled Diffuse" and replacing it with the classic
lambertian Diffuse, since the layering logic takes care of energy now
- Making the merallic component independent of the IOR
Note that this changes the look of the Principled BSDF noticeably in some
cases, but that's needed, since the cases where it looks different are the
ones that strongly violate energy conservation (mostly grazing reflections
with strong Specular).
Pull Request: https://projects.blender.org/blender/blender/pulls/110864
Previously Glass Fresnel used to get baked into the closure weight,
so the MNEE code could just ignore it.
However, now that it's part of the closure implementation, we need
to account for it in the MNEE throughput calculation as well.
this option was already unselectable in the UI, and is treated as GGX
with zero roughness. Upon building the shader graph, we only convert a
closure to `SHARP` when option Filter Glossy is not used and the
roughness is below certain threshold. The benefit is that we can avoid
calling `bsdf_eval()` or return earlier in some cases, but the thresholds
vary across files.
This patch removes `SHARP` closures altogether, and checks if the
roughness value is below a global threshold `BSDF_ROUGHNESS_THRESH`
after blurring, in which case the flag `SD_BSDF_HAS_EVAL` is not set.
The global threshold is set to be `5e-7f` because threshold smaller than
that seems to have caused problem in the past (c6aa0217ac). Also removes
a bunch of functions, variables and arguments that were only there
because we converted closures under certain conditions.
Pull Request: https://projects.blender.org/blender/blender/pulls/109902
for energy preservation and better compatibility with other renderes. Ref: #108505
Point light now behaves the same as a spherical mesh light with the same overall energy (scaling from emission strength to power is \(4\pi^2R^2\)).
# Cycles
## Comparison
| Mesh Light | This patch | Previous behavior |
| -------- | -------- | -------- |
|  |  |  |
The behavior stays the same when `radius = 0`.
| This patch | Previous behavior |
| -------- | -------- |
|  |  |
No obvious performance change observed.
## Sampling
When shading point lies outside the sphere, sample the spanned solid angle uniformly.
When shading point lies inside the sphere, sample spherical direction uniformly when inside volume or the surface is transmissive, otherwise sample cosine-weighted upper hemisphere.
## Light Tree
When shading point lies outside the sphere, treat as a disk light spanning the same solid angle.
When shading point lies inside the sphere, it behaves like a background light, with estimated outgoing radiance
\[L_o=\int f_aL_i\cos\theta_i\mathrm{d}\omega_i=\int f_a\frac{E}{\pi r^2}\cos\theta_i\mathrm{d}\omega_i\approx f_a \frac{E}{r^2}\],
with \(f_a\) being the BSDF and \(E\) `measure.energy` in `light_tree.cpp`.
The importance calculation for `LIGHT_POINT` is
\[L_o=f_a E\cos\theta_i\frac{\cos\theta}{d^2}\].
Consider `min_importance = 0` because maximal incidence angle is \(\pi\), we could substitute \(d^2\) with \(\frac{r^2}{2}\) so the averaged outgoing radiance is \(f_a \frac{E}{r^2}\).
This only holds for non-transmissive surface, but should be fine to use in volume.
# EEVEE
When shading point lies outside the sphere, the sphere light is equivalent to a disk light spanning the same solid angle. The sine of the new half-angle is the tangent of the previous half-angle.
When shading point lies inside the sphere, integrating over the cosine-weighted hemisphere gives 1.0.
## Comparison with Cycles
The plane is diffuse, the blue sphere has specular component.
| Before | |After ||
|---|--|--|--|
|Cycles|EEVEE|Cycles|EEVEE|
|||||
Pull Request: https://projects.blender.org/blender/blender/pulls/108506
When baking only indirect lighting, light sampling is skipped at the
first bounce. However, light evaluation is still done, so depending
on how the MIS weights end up more or less of the direct lighting
still ends up in the bake.
This is most noticeable with background lighting, but can also be
reproduced with e.g. point lights with a large radius.
Pull Request: https://projects.blender.org/blender/blender/pulls/108955
The problem here was that when direct light contibutions to baking were
disabled, the kernel just skipped all direct lighting evaluation.
However, at secondary bounces, "direct light" would actually end up
being indirect (since there's an extra bounce along the way), but
we're still skipping it.
Therefore, only apply direct lighting skipping at the first bounce.
So far, each closure in Cycles was either diffuse OR glossy OR
transmissive, and its color and contributions were assigned
to the corresponding direct/indirect/color passes.
However, since Glass is a single closure now, that is no longer enough,
since glass has both a glossy and a transmissive component.
Therefore, this commit adds support for splitting contributions from
the Glass closure between the two types.
For 4.0, we might want to also use this for Principled Hair since it
also technically has both types, but that would be a change from
the existing result so it's not part of 3.6 yet.
A couple of mistakes since the light linking commit:
- The +1 got missed in some of the refactors in the branch
- The order of arguments to the shadow path split was wrong
Pull Request: https://projects.blender.org/blender/blender/pulls/108420
The original names were `...update_position()`, but no update in
position is performed in these functions, rather, the entries in
`LightSample` are updated. Also make clear that the functions are used
by MNEE.
After the removal of the Shadow pass this no longer worked. Now it works by
marking the object as a shadow catcher and returning the Shadow Catcher pass.
The result is different than before, since it also takes into account indirect
light now and uses a different method to weight the contribution of lights that
is adaptive to the light strength.