Thoughts on making Cycles into a spectral renderer

Negative absorption does not represent emission as much as compliments emission. It’s a bit of a mind bender, but in general is the same result as negative RGB values; negatives “push” the resulting complimentary value across from it away from it.

While completely nonsensical in a practical sense, and compositors etc. must keep an eye out for negatives, there are practical and unfortunate reasons how and why they arise, and would indeed exist on reconstructed spectra from camera virtual primaries.

Unsurprisingly, this is part of the gamut mapping nightmare.

I don’t believe this is correct. All negative values are utter nonsense, and are an extreme nightmare in a pipeline. They can arise, but are almost always math anomalies or some horrible hack; negative light / radiometric energy doesn’t exist in our typical experience. Perhaps in some crazy nth dimensional parallel universe model…

Fluorescence is a conversion of energy. That is, certain energy spectra are absorbed and converted to an excitation of other spectra, at a lower energy state. Hence the law of energy conservation is maintained.

As you noted, it is essentially multiplication, and while the Beer Lambert laws and such cover the actual emulation of paint mixture and the weighting, it is indeed multiplication at the most basic level.

100% correct. ACES isn’t a magical unicorn, and with regard to spectral, it’s utterly problematic as a path forward.

The astute observer will recognize this as a pixel management problem, and it already plagues Blender.

There is no one-size-fits all solution here, hence the UI absolutely must be managed. When it isn’t managed, you get into the core issues that are already exceptionally problematic across the board within Blender as it currently exists.

4 Likes

General Flourescence would require more advanced spectral input where you can, for each input wavelength, choose an entire spectrum of output wavelengths (and you’d probably want to satisfy a constant energy condition so as to avoid weirdness)
I suspect that’d be handled by very specific shaders rather than a simple curve input.

And at no point would such spectra feature negative values.

2 Likes

Got it, thanks for the explanation! :slight_smile:

1 Like

I see, kind of like how the “add shader” node works, by multiplying incident light ? (provided it connects to a reflective bsdf and not an emissive one)

Reflection and absorption are sort of the same thing but inverted. More absorption makes stuff darker, more reflection makes it brighter.

The mayor difference is that reflection is a surface effect, so it happens “all at once”, whereas absorption is a volume effect, so it happens gradually.

And Absorption is given in terms of a negative exponent (so roughly, if you have an absorption density 3, incoming light is, by the time it escapes again, multiplied by something like e^(- 3 * L) where L is the penetration depth of a ray into such a material in BU),
whereas Reflection is more direct (stuff is directly and only once multiplied with the reflectance spectrum, at least for the simplest BSDF. The exact details may vary a little bit)

But both of them “multiply” incoming light.

If you have, for a specific wavelength, absorption density of, say, -1, your light will be multiplied by something like e^(-(-1) * L) = e^L instead, effectively going brighter over time.

This is indeed quite similar to if you add multiple reflectance shaders together, or just giving them RGB color values above 1.

If you check out my blackbody spectral explorations above

these directly utilize how absorption works to effectively concentrate colors until only the most prominent parts of the corresponding spectra remain. In effect this is like multiplying each spectrum by itself over and over again.

1 Like

I would love to try out the spectral branch on Ubuntu 20.04. But I am not able to compile it. The master branch of Blender compiles fine for me.

  1. Cloning your repo already throws some errors:
git clone --recursive --single-branch --branch spectral-cycles https://github.com/Smilebags/blender.git

I get asked for my Github credentials to get access to:

  • blender-translations.git
  • blender-addons.git
  • blender-addons-contrib.git
  • blender-dev-tools.git

Cloning these sub-repos fails, probably they are missing in your fork, but I believe that’s not the main issue.

  1. I checkout all the precompiled libraries to a lib subfolder just as for the master branch.

  2. make update fails on the same issues as 1.

  3. make fails at the very end stating

...
[ 98%] Linking CXX static library ../../../lib/libbf_freestyle.a
[ 98%] Built target bf_freestyle
[ 98%] Linking CXX static library ../../../lib/libbf_blenkernel.a
[ 98%] Built target bf_blenkernel
make[1]: *** [Makefile:163: all] Error 2
make: *** [GNUmakefile:304: all] Error 2

Any idea what could cause it, how I could get more details and perhaps make it compile?

@smilebags I can probably set up a nightly linux build on GA if you want.

2 Likes

@LazyDodo might be the one to ask.

My first suggestion is to clone Troy’s repo and try again.

If you are willing to, I think the community would greatly appreciate it! (And I would too). I heard you just started Linux builds recently. How are you doing them? In a virtual machine?

How are you doing them? In a virtual machine?

WSL on windows 10 with centos7 loaded.

My first suggestion is to clone Troy’s repo and try again.

yeah troy has the modules mirrored as well should clear that issue up nicely.

I’m impressed with the direction WSL is going. Nice. Well if it isn’t an inconvenience for you, I would love to be able to say there’s a Linux build available too.

i’ll get that setup, may not be today though.

2 Likes

Not a problem at all. I appreciate it, thank you.

Thanks for the answers, I will try Troy’s repo right away. @LazyDodo that would be awesome!

Really great to see some major progress happening here!

Just trying it out and I know UI is early but the curves confused me for a moment because the light energy is going from right to left ie. low energry infrared at x1 and high energy uv at x-1.
I realised it’s ordered by wavelength which is a valid way to do it, just seems off to me for some reason.


Doing a quick google images search, i see about 50/50 on which order to show it, probably a dicussion to be had there.

Wavelength is more intuitive than energy for the purposes of a renderer. Just compare here:

image

This is the blackbody radiation spectrum of a 5777K blackbody emitter (roughly equivalent to the sun) according to wavelength (on the left) and energy/frequency (they are equivalent, on the right)

By frequency, it looks like the most intense portion of the light for this distribution is in the infrared.
However by perception, it is, in fact, in the green part.

1 Like

In most colour-sciencey plots you will typically see the plot along x in ascending order. In terms of spectra, lower x to the left, corresponding to shorter wavelengths, with longer wavelengths on the right.

This is certainly a reasonable and sane approach as it overlaps with how general UI curves work, and extends forward well with further plotting, graphs, and other UI subjects where the origin zero point typically is anchored in the lower left of a plot.

My first suggestion is to clone Troy’s repo and try again.

@LazyDodo Didn’t work either. There are no missing repos now, but the compilation crashes with the same error. Since I do it all inside of an LXD container, I will try with a CentOS image instead.

Actually i’m having issues on both windows and linux currently,

  • the gpu kernels are unhappy about float8
  • msvc2017 is not liking any of the new AVX2 intrinsics (2019 does like them though, so i’ll switch that over)
  • and linux is having an unhappy time about float8 as well
In file included from /mnt/e/builds/src_spectral_linux/intern/cycles/render/../util/util_types.h:30:0,
                 from /mnt/e/builds/src_spectral_linux/intern/cycles/render/../util/util_aligned_malloc.h:20,
                 from /mnt/e/builds/src_spectral_linux/intern/cycles/render/../util/util_array.h:23,
                 from /mnt/e/builds/src_spectral_linux/intern/cycles/render/../graph/node_type.h:20,
                 from /mnt/e/builds/src_spectral_linux/intern/cycles/render/../graph/node.h:19,
                 from /mnt/e/builds/src_spectral_linux/intern/cycles/render/../render/nodes.h:20,
                 from /mnt/e/builds/src_spectral_linux/intern/cycles/render/nodes.cpp:17:
/mnt/e/builds/src_spectral_linux/intern/cycles/render/../util/util_defines.h:121:13: error: cannot convert ‘ccl::SpectralColor* {aka ccl::float8*}’ to ‘ccl::float3*’ in assignment
       __tmp = (type *)NULL; \
             ^
/mnt/e/builds/src_spectral_linux/intern/cycles/render/../graph/node_type.h:171:5: note: in expansion of macro ‘CHECK_TYPE’
     CHECK_TYPE(((T *)1)->name, datatype); \
     ^~~~~~~~~~
/mnt/e/builds/src_spectral_linux/intern/cycles/render/../graph/node_type.h:311:3: note: in expansion of macro ‘SOCKET_DEFINE’
   SOCKET_DEFINE(name, \
   ^~~~~~~~~~~~~
/mnt/e/builds/src_spectral_linux/intern/cycles/render/nodes.cpp:3500:3: note: in expansion of macro ‘SOCKET_IN_SPECTRAL’
   SOCKET_IN_SPECTRAL(color, "Color", make_spectral_color(0.8f));
   ^~~~~~~~~~~~~~~~~~

also there’s like a billion new warnings about alignment, think this branch needs a little bit of polishing…

1 Like

One of those materials that in response to interaction with light spectra release/emit more light spectra?

I’m led to think of phenomena such as phosphorescence, photoluminescence etc. Fluorescence.