Thoughts on making Cycles into a spectral renderer

Awesome work @pembem22 that’s going to be so much easier to use.

Pixelgrip responded to you indirectly over on BlenderArtists, it seems like he knows what he is talking about :grinning_face_with_smiling_eyes: honestly I haven’t looked into the volume behaviour as much as I probably should.

Inversion is always context bound. When folks detach from meaning, it yields nonsense. In most instances, inversion is nonsensical. See what happens when people try inversion on emissions as an example. It’s meatheaded.

Here, the value 1.0 isn’t the meaning. 100% is.

Absorption should be normalized I would think. Inversion, if it must remain, should be applied to normalized meaning.

2ct: Please please please keep close to the physical meaning of things. An absorption coefficient of 1.0 (/m) means that after 1 meter of the material, a fraction exp(-1) of the light remains. This is thereby perfectly normalized. A larger absorption coefficient will make the material less transparent, up to an absorption coefficient of infinity (/m) which means that all light is absorbed as soon as it passes through the dielectric interface into the material. So yes, lots of absorption at green region but none at red and blue will give you a purple see-through material (a white object behind the absorber will look purple because all green has been absorbed)

1 Like

I can’t entirely grasp that explanation I’m afraid.
I’m still not sure what the apparently negative absorption in water is supposed to be. I suspect it’s a very specific type of spectroscopy that’ll yield this result, which will end up having some sort of meaning?

But normally, the absorption of water is always positive:

It happens to get tiny right around the visible spectrum, but it’s none the less positive.

At best I could imagine negative absorption coefficients to somehow be something like log Absorption

I agree. I think it did make sense for the sake of intuition with RGB inputs that are always expected to be within 0 - 1. But now, with spectral inputs, it really is nonsense.

In fact, if anything, a better kind of inversion would be to divide instead of subtract. Of course, that’d mean that you’ll reach infinity for values of 0 but honestly that’s sorta sensible: When the material reflects 0% of the light, it effectively instantly absorbs 100% of it, which is equivalent to infinite absorption.

Either way though, since spectra aren’t bound to RGB, and the resulting intuition is out the window anyway, I think the inversion should indeed fall.

Normalized how? Absorption spectra are given in terms of ray travel distance. Going beyond 1 has a very specific physical meaning. Namely that it absorbs faster than by multiplying the light intensity by 1/e each meter (or what ever unit). There is no sensible way to normalize them. At best I can make it so the tallest peak is always 1 but as long as inversion is in place, that will mean, that at that peak, no absorption at all would take place.
Without inversion, this kind of normalization would be equivalent to adjusting the length units in some arbitrary fashion which you can then undo via the density multiplier, but if your scene happens to have an exact scale, it’d be best to have absorption in specific units (such as meters). Then the density simply becomes interpretable as a scene scale multiplier. Density 0.1 would mean your scene is in a scale such that 1BU = 10cm, Density 10 such that 1 BU = 10m etc.

Yep coming up with the physical meaning of an absorption spectrum is important, I haven’t changed how Cycles works, which I believe is simply just exponential decay at a rate given by the RGB triplet, in Blender units, multiplied by the density.

I’ll do some tests to try to get an intuition for how it works currently, and whether that’s a sensible way to keep it

This loops directly back to my statement that inverting values is largely nonsensical, yet people continue to insist on attempting it in contexts that are utterly nonsensical.

The depth of my understanding on the nuances of absorption beyond pointing out that inversion on “colour stuff” is typically nonsensical, is limited here. I can’t think of a better way of hackishly doing inversions on things that shouldn’t have them beyond suggesting “Stay close to the meaningfulness of the ground truths.”

It just simply won’t be sensible though.
This 1-Spectrum deal effectively means, the scaling point happens around 1 instead of around 0. Stuff is going to be thrown off no matter what.

It might be that going 1-Spectrum is totally the right thing to do. But then that means negative values in the spectrum don’t quite mean what I thought they meant:

1-(1-Spectrum) = Spectrum

If that’s how it works, then actually everything works out fine and negative values are treated correctly as even more absorption rather than negative absorption.
I guess it depends on where the density is being applied:

  • density (1 - (1 - Spectrum)) = density * Spectrum - ok
  • 1 - density (1- Spectrum) = density * Spectrum + (1- density) - wrong
  • 1 - (1 - density * Spectrum) = density * Spectrum - ok

I think it’s not being applied in the middle position though. Probably it happens like in that first option.

Either way though, really, the inversion just simply shouldn’t happen at all. At best it should be a toggle with an attached tooltip.

If you actually want to treat a reflection spectrum as an absorption spectrum, though, the best conversion probably involves going Absoprtion = log(1/Reflection)

The 1/R part I already explained above (0 Reflection is roughly equvialent to infinite absorption, 1 Reflection like 0 absorption)

The log part is essentially because absorptions are in the exponent whereas reflections are linear.

It’s still utter bs, but it’s better-reasoned bs than the 1-Spectrum nonsense.

First thing I’ll point out, the spectrum you feed into a Volume Absorption node is the transmission spectrum.

It doesn’t behave as I would expect though, where a black spectrum would mean no light passes through whatsoever and a white spectrum means all light passes uninterrupted.

It’s probably worth understanding how the node is intended to work, and then discussing whether that is indeed how it works and whether that’s an intuitive and useful method.

transmission spectra depend on the thickness of your material, so that’s a bit odd, but ok. I guess that’s what the density is for.

Apparently to convert from transmittance to absorbance, you’d go -log(transmittance) or equivalently, log(1/transmittance). That’s exactly the formula I put above fwiw. It will, however, give you that spectrum in arbitrary units (to be exact, in units of thickness of the measured material)

It might be interesting to have some spectral conversion tools in Cycles. Plug in a spectrum (reflection, transmission, absorption), and, via two dropdown boxes to choose what kind of input and output you desire, it’ll convert your spectrum accordingly.
There’s also emission and scattering spectra for which I don’t think anything similarly reasonable could be done. (In fact I’m still not quite sure how to exactly interpret a scattering spectrum)

The relevant formulae:

A = Absorbance
T = Transmittance
R = Reflectivity

T = 1 - R = e^-A
R = 1 - T = 1 - e^-A
A = -log(T) = -log(1-R)

One more caveat: I’m not actually sure what basis Cycles works in. Empirically, they’ll often work in base 10 instead of base e. Obviously gotta adjust accordingly. The only thing that changes for the end user is how much to adjust the density to yield desired results.

Oh and also, in the literature you’ll often find A = 2 - log₁₀(T)
That +2 comes from this usually being T in percent.

In other news, dichromatic materials are pretty simple to make

4 Likes

The scattering spectrum can be considered a probability field, or probably with some simple math, the average distance between two scattering events for the wavelength. Again, I’m not sure of the details but that’s what I gathered from the code.

I think these discussions about how Cycles volumes work are somewhat off-topic, at least for now. If the spectral result closely resembles the RGB result in simple cases, it is working as intended.

If desired, we could break off a thread to talk about volume calculations in Cycles in general - I don’t think spectral really introduces anything new here other than making the vagueness of ‘RGB’ ever-more clear.

I’m seeing a lot of developement here which I’m glad of. Thanks to all testers too.
But I have a new rough question now: in the long run I’d like to know if that new Spectrum Curves node will be the only way to set a color for a shader (which would be crazy) or if it’s gonna be used just to achieve particular color effects (crysberillium, fluorescence, and the like). What will we lose feeding a “simple” RGB input? Or a humble :sweat_smile: sRGB jpeg?

Fair, although for ease of use of this branch I think providing such a conversion node as described above at least would be good to have, and I think that part is quite relevant to this branch at least.

Definitely not. Everything that you can do currently will continue to work as you expect; use RGB values in BSDFs, feed sRGB image textures into materials etc etc. The new nodes are purely new things that you can also do to create more physically based effects.

Standard RGB colors are already possible to use. They are automatically upsampled. However, I think the plan is to change the underlying conversion later, which will mean slightly different looks. In the vast majority of cases that won’t mean a whole lot of change though. Stuff where nothing crazy goes on with the spectra, and which isn’t too high-saturation (and in particular in the green range), will not look noticeably different for the most part.

Sorry for dumb question, it was for clearing any doubt

Not at all, it’s a valid concern, everything we’re talking about here is to do with spectra.

I can understand having to think about that day-in and day-out would be tiring! I really want to make Cycles more intuitive and easier to use rather than more complex.

(In the sense that, if you have access to physically based data, you can just plug that into Cycles directly and it’ll work. It’s actually ultimately gonna be rare that you’d want to directly fiddle with spectra. For the most part it’s probably gonna be a sort of physically based material library)

1 Like

As well as being able to use physically based data without fiddling around with it to get it to look right, there are a lot of other ways spectral is more intuitive. Things like coloured lights, extremely bright lights, bounce lighting, surface effects (bubbles, structural pigments) etc etc, the list goes on. All of these things will be more accurate/realistic with less manual work and less complex math than in an RGB renderer.