Based on the "Stochastic ray tracing of transparent 3D Gaussians" paper
by Xin Sun et. al. The basic idea: perform stochastic intersection with
the Gaussian splat based on its transparency.
Gaussian splats are implemented as a dedicated primitive type, but it
shares the same layout for position and radius as points, so a lot of
existing functions (positions, attributes, etc) work for both points
and splats.
For the Embree and hardware intersection it is implemented as a custom
primitive type.
The choice of using bounding spheres mainly comes from a balance between
performance and memory usage. More ideal would be to use OBB, but it is
not supported for custom primitive types in Embree and GPU HW-RT on all
backends.
There is a known limitation that comes from the fact that the datasets
are trained in sRGB space and Cycles work in Linear space: areas with
low opacity and high radiance render noticeably differently from the
ground-truth implementation.
Ref #159470
Pull Request: https://projects.blender.org/blender/blender/pulls/163103
This appears to have been caused by invalid use of assert() instead of
kernel_assert() in the kernel. I don't think it's actually hitting that
assert, but maybe it generated an unsupported instruction or something
along those lines?
The one that caused the actual problem is in svm/convert.h. I changed
more instances that are currently CPU only but risk becoming enabled on
the CPU with future code changes.
Thanks to Sahar A. Kashi for finding this.
Pull Request: https://projects.blender.org/blender/blender/pulls/163970
The implements internal support in Cycles for fallback values when an
attribute or image texture is missing in a shader node. It is not yet
exposed in Blender shader nodes.
This is useful to provide an appropriate default value when a shader is
used across objects with different attributes, or when UDIMs don't cover
the entire UV space.
Pull Request: https://projects.blender.org/blender/blender/pulls/162785
This adds the Integer Math node to shader nodes. It's the same node that
can already be used in Geometry Nodes and the Compositor.
While creating the regression test, I noticed that the integer math
implementation was a bit broken:
* The integer modulo (`%`) operator on the GPU is undefined for negative
divisors (the added regression test showed that the behavior is not
consistent across platforms).
* Use integer power function instead of using float implementation with
casts.
The MaterialX implementation is omitted for now. I didn't look into it
in detail yet but for the Boolean Math node (#162798) it seemed like
some more work is needed there to support this type.
Pull Request: https://projects.blender.org/blender/blender/pulls/163805
This adds the Boolean Math node to shader nodes. It's the same node that
can already be used in Geometry Nodes and the Compositor.
This also fixes the conversion from other types to boolean values so that
it it consistent across different node tree types. Cycles doesn't have
native support for booleans currently (it encodes them in integers), so
for now this conversion is entirely handled in the inliner.
The MaterialX implementation is omitted for now because it seems to need
more work to properly integrate booleans (right now it appears to ignore
all links going from a float to a boolean socket for example).
Pull Request: https://projects.blender.org/blender/blender/pulls/162798
In Cycles we previously assumed that the IOR inversion, when hitting a
surface from the backside, for dielectric closures
(e.g., generalized_schlick, microfacet, refract, etc.) is done by the
user in the OSL code. While experimenting with the OSL code generated
by MaterialX and by looking at the example OSL shaders of the OSL
testrender it shows that OSL assumes that this inversion is done
implicitly, inside the closures. This change matches Cycles IOR
inversion behavior with the one expected by MaterialX and OSL
testrender.
Pull Request: https://projects.blender.org/blender/blender/pulls/162634
From the comment, this flag was added to suppress allocation warnings on
macOS < 10.14. With the minimum deployment target now being set to 13.0
with !163627, remove this now unused flag. Confirmed to not re-introduce
warnings locally.
Pull Request: https://projects.blender.org/blender/blender/pulls/163669
The main goal is to bring a bit of structure to the use of quaternions
in the Cycles kernel.
Prior to this change there was no dedicated quaternion type and float4
was used instead, and quaternions are stored as (x, y, z, w) matching
naming between the quaternion and float4 fields. However, Blender uses
(w, x, y, z) quaternion order for attributes, which is different from
what Cycles uses. Without dedicated type this either leads to different
quaternion orders depending whether it comes from attribute, or makes
it intrinsically not possible to use implicit sharing.
This change introduces Cycles Quaternion type which is compatible with
Blender attribute math::Quaternion in both layout and alignment, making
it possible to benefit from implicit sharing and use a nice structure
in the kernel.
This change does not modify the existing quaternion usage in the kernel
which is currently used for transform decomposition and interpolation.
There is currently no SIMD for the Quaternion type, which allows to
avoid any special alignment requirement and share attributes with
Blender, but performance might not be ideal.
This attribute type will be used for representing gaussian splat
rotation.
The attribute access and interpolation matches behavior prior to this
change. Added some basic tests for quaternion attribute access for RGB
and alpha, mesh and volume attributes.
Ref #159470
Pull Request: https://projects.blender.org/blender/blender/pulls/163342
According to OpenPBR spec v1.1.1 Eq. (9), the correct layering for a
coated substrate is
$$f_\mathrm{layer} = f_\mathrm{coat} + T_\mathrm{coat}(1 - E_\mathrm{coat})f_\mathrm{sub}.$$
For fractional coat weight, we apply Eq. (14), and it becomes
$$
\begin{aligned}
f_\mathrm{weighted-layer}&=(1-w_\mathrm{coat})f_\mathrm{sub}+w_\mathrm{coat}f_\mathrm{layer}\\
&=(1-w_\mathrm{coat})f_\mathrm{sub}+w_\mathrm{coat}(f_\mathrm{coat} + T_\mathrm{coat}(1 - E_\mathrm{coat})f_\mathrm{sub})\\
&=w_\mathrm{coat}f_\mathrm{coat}+(1-w_\mathrm{coat}(1-T_\mathrm{coat}(1-E_\mathrm{coat})))f_\mathrm{sub}
\end{aligned}
$$
Here, \(E_\mathrm{coat}\) does not contain the coat weight nor the
overall weight of the coated closure \(w_\mathrm{layer}\), but our
current way of using `bsdf_albedo()` contains both weight, after which
we apply \(T_\mathrm{coat}\), which is wrong.
To fix this issue, we allow RGB weight for the layer operation, and
directly return a albedo of
$$
A_\mathrm{coat} = w_\mathrm{layer}w_\mathrm{coat}(1-T_\mathrm{coat}(1-E_\mathrm{coat}))
$$
Thus, when we apply the layer operation, we get
$$
\begin{aligned}
&w_\mathrm{layer}\mathrm{layer}(S_\mathrm{sub},S_\mathrm{coat},w_\mathrm{coat})\\
=&w_\mathrm{layer}(1-w_\mathrm{coat})S_\mathrm{sub}+w_\mathrm{layer}w_\mathrm{coat}\mathrm{layer}(S_\mathrm{sub},S_\mathrm{coat})\\
=&w_\mathrm{layer}(1-w_\mathrm{coat})S_\mathrm{sub}+w_\mathrm{layer}w_\mathrm{coat}S_\mathrm{coat} + (w_\mathrm{layer}w_\mathrm{coat}-A_\mathrm{coat})S_\mathrm{sub}\\
=&w_\mathrm{layer}w_\mathrm{coat}S_\mathrm{coat}+(w_\mathrm{layer}-A_\mathrm{coat})S_\mathrm{sub},
\end{aligned}
$$
Which matches the equation for \(f_\mathrm{weighted-layer}\).
A modification to the sheen BSDF was needed to make it not tint the sub
layers.
Pull Request: https://projects.blender.org/blender/blender/pulls/162471
Also use the MaterialX-compatible `sheen_bsdf()` internally for the old
`sheen()` OSL closure, as they are essentially the same.
Should remove `sheen()` in 6.0
Dispersion is defined by two parameters:
Abbe Number and Dispersion Scale.
This corresponds to OpenPBR v1.1.1
Pull Request: https://projects.blender.org/blender/blender/pulls/162041
Note: dispersion is temporarily disabled when using MNEE (shadow caustics) on oneAPI, due to a compiler bug. Waiting for a fix from the oneAPI side.

Co-authored-by: Sebastian Herholz <sebastian.herholz@gmail.com>
This adds a new simple node which retrieves the X, Y or Z component of a vector
by index. This is simpler and more efficient than using workarounds like using a
Separate XYZ with an Index Switch node.
The original motivation for this node came from #149091 where we wanted to
support this using expressions (`vector[i]`).
Co-authored-by: Tibo Stans <stanstibo@gmail.com>
We are running out of bits. Split the original `ShaderDataFlag` into
`ShaderRuntimeFlag`, which is determined by closures in the shader and
set up during rendering, and `ShaderDataFlag`, which is the same for the
whole shader graph and hence determined during shader compilation
The size of `ShaderData` did not change due to padding
Pull Request: https://projects.blender.org/blender/blender/pulls/161856
Store positions as separate arrays again. This appears to give better
memory access patterns or layout. This was a regression from fc9917352b
and 0baa98866c.
This is a relatively simple change, rerouting the position attribute to
dedicated arrays, still including motion steps in the same array. The rest
of the refactor is preserved.
Pull Request: https://projects.blender.org/blender/blender/pulls/160110
The order of closures was different between the two, which causes
different stochastic picking of BSDFs to sample. Other nodes yield
the same closure order.
This eliminates some differences between tests that seemed like
they may have been related to #159879 but weren't.
The geo nodes implementations of the `mix`, `addition`, `multiplication`
and `subtraction` color mix modes are both faster and have better
numerical properties than the ones we use in Cycles, OSL and EEVEE.
This PR ports the geo nodes implementations of those color mix modes
to Cycles, OSL and EEVEE.
Additionally, the SVM mix function implementation is templatized and
a new function called "endvalue_preserving_mix" is added for the
alternative variant of linear interpolation.
Pull Request: https://projects.blender.org/blender/blender/pulls/158022
Removing the legacy scaling by 1/(4pi) of the radius scale for the randomwalk
subsurface scattering mode.
Adjusting the default subsurface radius from 0.05 to 0.005 to keep similar
default behavior.
Updating test cases for Cycles and EEVEE.
Removing the legacy scaling by 1/(4pi) of the radius scale for the randomwalk
subsurface scattering mode.
Adjusting the default subsurface radius from 0.05 to 0.005 to keep similar
default behavior.
Updating test cases for Cycles and EEVEE.
Motion is now part of the position attribute. On the kernel side, a
combined position + radius attribute is now stored, replacing the
previous motion only attribute.
Legacy motion attributes are now removed.
Pull Request: https://projects.blender.org/blender/blender/pulls/158728
Motion is now part of the position attribute. On the kernel side, this
position is now stored as an attribute as well, replacing the previous
motion only attribute.
Pull Request: https://projects.blender.org/blender/blender/pulls/158728
The issue this change aims to solve is the fact that we are out of bits
in the PathRayFlag. There is a TODO in the code about the fact that we
might need a flag to record primary scatter for volumes. Additionally,
there are plans to introduce visibility flags for the raycast node
rays.
The choice of the underlying type for the PathRayVisibilityFlag keeps
the raycast visibility in mind.
There is now a dedicated type alias to pass visiiblity around in the
kernel. Currently it is 32 bit, keeping in mind possibility of shift
introduced by the shadow catcher. It is possible to limit it to 16,
but then we'd be limited to only 8 visibility bits (which would be
fine until we introduce other flag after the raycast visibility).
Although, it is not really clear it will brings an actual performance
improvement.
The main path state is using 16 to store path visibility, as per the
underlying type of the PathRayVisibilityFlag. It is possible to limit
it to 8 bit to keep state size small until even more ray visibility
bits be needed in the future (the unaligned node bit is not used by the
path visibility).
The shadow path state also needs path visibility to check which path
type it deals with.
Ref !157822
Currently matches the `uint` that is used everywhere. Intended to
be used everywhere in the kernel and in the host where visibility
is passed around.
It might become a narrower type in the future if visibility fits
into 8 bits (it could become uint16_t then, to have space for the
shadow catcher shifts).
Should be no functional changes,
Ref !157822
- Thin glass:
An infinitesimally thin sheet of dielectric, approximated by a reflected
lobe and a trasmitted lobe, the respective weights of both lobes are
analytically computed by summing up infinite geometric series that
account for internal reflections.
- Thin subsurface:
An infinitesimally thin sheet of dense scattering material, approximated
by a diffuse lobe and a translucent lobe, the respective weights of both
lobes are given by subsurface anisotropy, with specifies the relative
amount of backward and forward scattering.
Co-authored-by: Jesse Yurkovich <jesse.y@gmail.com>
Pull Request: https://projects.blender.org/blender/blender/pulls/157469
This PR adds a Scene Time node to the shader editor.
The goal is for parity with the Compositor and Geometry Nodes.
As recommended by Bretch, this also adds a SceneAttributes class owned
by Scene since there wasn't a good data structure to store scene data
in.
Co-authored-by: Brecht Van Lommel <brecht@blender.org>
Co-authored-by: Clément Foucault <foucault.clem@gmail.com>
Pull Request: https://projects.blender.org/blender/blender/pulls/156850
The required free functions for closure allocation changed, only a
single allocation function needs to be defined now.
This is needed to fix the failing tests after the 5.2 libraries update.
Pull Request: https://projects.blender.org/blender/blender/pulls/158507
Either use no spaces (common for disabled arguments) `/*arg*/`
or spaces `/* Regular comment. */`
Cleanup lop-sided comments such as `/* X*/` or `/*X */`.
Also use doxy-sections for bmesh_structure.hh,
the ad-hoc section comments had become outdated.
Ref !158467
On the user side it is implemented using extensible socket declaration:
user now can add sockets to access attributes. It is done in the node
settings panel: adding attribute creates input and output socket. The
input socket is a string that denotes attribute to sample, and output
socket provides access to the value of the attribute. A little caveat
is that Color attribute create 2 sockets: one for color, and another
for alpha. This is because color in shader nodes is RGB.
Cycles SVM implementation is based on the existing NODE_ATTR SVM node:
Raycast generates a set of these nodes and uses existing attribute
evaluation on the hit_sd.
Cycles OSL implementation required a bit of trickery to make it fit
the AOT type of shader compilation. The node_raycast() shader outputs
attributes as arrays, and there are extra converter shaders compiled
dynamically to convert those arrays to individual values that could be
addressed by the nodes that use those attribute sockets. There is a
limitation: there could be only up to 32 or each of the float, alpha,
or color/vector attributes.
There is also a mechanism now in Cycles for shaders to request global
attributes. Without this Cycles will optimize all attributes that are
not used by a specific geometry, making it quite tedious to setup in a
way that raycast could still access those attributes. Without such
mechanism user would have need to add attribute nodes to every shader
and mix it in with some low non-zero weight to the output so that it
does not get optimized out. The implementation is not really ideal as
it might lead to situation when attributes are requested by unused
shaders, but it is the best we can do without more global refactor.
EEVEE implementation returns 0 for the attributes. It is quite tricky
to implement attribute sampling, so for now it is Cycles-only feature.
Ref #155590
Pull Request: https://projects.blender.org/blender/blender/pulls/157344
There is no need to call `getattribute` a second time for the factor,
it's the same as the average of the color.
Calling it twice gave different results due to stochastic sampling using
the next random number.
Another difference is that OSL only evaluates other inputs when density
is non-zero, an optimization that is not easy to do in SVM. That is not
solved by this change.
Ref #157554
Pull Request: https://projects.blender.org/blender/blender/pulls/157641
Caused by 4d6c7718c5.
Under certain conditions it is possible that the offset logic in the
AttributeTableBuilder::add() assigns offset of -1. This value just
happens to match ATTR_STD_NOT_FOUND, leading to false-positive check
that attribute is not found (for example, svm_node_attr_init() that
checks desc.offset != ATTR_STD_NOT_FOUND.
The simplest solution is to tweak the value of the ATTR_STD_NOT_FOUND
to make it very big negative value.
There is now an utility function to check whether AttributeDescriptor
points to an attribute that is found, to help possibly tweaking this
check in the future, and to make code a bit more semantically clear.
Pull Request: https://projects.blender.org/blender/blender/pulls/157410