It's not used right now, but in the future I want shaders to be
able to vary over time and have motion blur. This serves as a
nice little reminder by putting it in the API.
The main change is that SurfaceClosures now have the hero
wavelength baked into them. Since surface closures come from
surface intersections, and intersections are always specific to
a ray or path, and rays/paths have a fixed wavelength, it doesn't
make sense for the surface closure to constantly be converting
from a more general color representation to spectral samples
whenever its used.
This is also nice because it keeps surface closures removed from
any particular representation of color. All color space handling
etc. can be kept inside the shaders.
The SAH split would happily repeatedly split on the same axis
as long as the surface area was reduced as much as splitting
on the other axes. This resulted in sliver-like bounding boxes
for some scenes, which is terrible for the light tree.
The SAH splitting code now accounts for the diagonal of the
bounding box, favoring smaller ones. This seems to work well,
fixing the issue without introducing any apparent performance
regressions.
The previous commit dealt with triangles self-shadowing. This
commit deals with avoiding intersections with _other_ objects
very near a triangle ending up being erroneously shadowed by
it.
This turned out to be a rather interesting one. The water-tight
ray/triangle intersection algorithm, while very accurate for
finding if there is an intersection with a line segment, is
not as remarkably accurate for determining if that intersection
is within the interval of the ray.
This is because of the coordinate transformation it does
depending on ray direction: for triangles laying flat on one of
the axis planes near zero, that near-zero coordinate can get
transformed to a much less accurate space for testing. In fact,
generally speaking, beause of the coordinate transform, you can
only rely on the test being as accurate as the least accurate
axis.
The ray-origin offset code was doing offsets based on the
assumption that the error on the major axes are independent, but
as this triangle intersection algorithm shows, you can't actually
depend on that being the case. So rather than handling triangle
intersection as a special case, I've changed the intersection
position error to be a single float, representing the maximum
possible error on any axis. This should be robust for any
geometry type added in the future, and also solves the immediate
issue in a correct way.
Might move this into the main source base at some point, but
I'm not totally sure about the correctness of the table yet, so
would like to generate it for now.
Turns out going higher arity makes a huge positive difference
is sampling quality. Currently have 32-arity set as the default,
as it seems to be worth it for the better sampling.
For some reason the ulp incrementing is unreliable when starting
at zero. It creates subnormal numbers, and that seems to be an
issue somewhere in the pipeline, ultimately leading to weird
render artifacts. Not entirely sure why.
This fixes it by avoiding subnormal numbers in the final offset
ray origin. Left a note suggesting investigating in more detail
at some point.
Very small triangles were being missed because of the
not-so-robust ray-triangle intersection algorithm I was using.
Switched to the algorithm from the paper "Watertight
Ray/Triangle Intersection" by Woop et al. Happily, the new
algorithm doesn't seem to measurably slow down renders at all.
They are now generated by a build.rs script from nothing but the
colorspace's primaries, which makes it super easy to add more
colorspaces. So easy that I added three more: ACES AP0, ACES AP1
and Rec.2020.
This lays the foundation for supporting output to different
colorspaces.
All scene data collection is now done in a single sweep of frame
changing. Previous commits were already working towards this, and
but now it's done. Yay!
Over-all, switching to this approach gives huge speed boosts on
large scenes with animation, rigs, dependencies, etc. For such
scenes, frame changing is very expensive.