### Post by trejkaz on Oct 4, 2022 3:18:09 GMT

Part of the whole sanity checking I've been doing while trying to convert my ray tracer to spectral is, trying to assign proper units to all numeric values. People often say, checking units is a good way to debug a system, because if you find places where the units don't match up, you might be missing something important.

Well, I found something.

The units for a ray are "radiance", in watts per steradian per square metre [per nanometre] - radiance is the same value over any given ray and is certainly the correct unit for the amount of light going down a ray. You can see other places like the PBR book talking about it as well.

The units for a point light, though, are "radiant intensity", which is just watts per steradian [per nanometre] - because point lights have no surface area. PBR book also talks about this.

But then in the material code, the lighting is done somewhat like this:

But, the units for light.intensity are W/sr, and the units for lightIntensity are actually W/sr/m². So you can't actually assign one directly to the other, you need to divide by a length squared term at some point!

In PBR book, this is where they divide by the square of the distance (/R²) from the light. As being further from a light

Conversely, for area lights, they have a constant radiance for the entire light, so when they sample it, they just get the value - no /R² term appears at all for those. Area lights still effectively have inverse squared falloff, but in their implementation, this happens because when they're closer to a light, more of their samples hit the light. So they get it from the statistics alone. With point lights one can't possibly use normal sampling because the sample would never hit the point - so they special-case point lights to sample just once, and the /R² term is in the code for the point light.

In RTC, though, there is currently

Well, I found something.

The units for a ray are "radiance", in watts per steradian per square metre [per nanometre] - radiance is the same value over any given ray and is certainly the correct unit for the amount of light going down a ray. You can see other places like the PBR book talking about it as well.

The units for a point light, though, are "radiant intensity", which is just watts per steradian [per nanometre] - because point lights have no surface area. PBR book also talks about this.

But then in the material code, the lighting is done somewhat like this:

`// Combine the surface color with the light's color/intensity`

val lightIntensity = light.intensity[wavelength]

val effectiveIntensity = surface * lightIntensity

But, the units for light.intensity are W/sr, and the units for lightIntensity are actually W/sr/m². So you can't actually assign one directly to the other, you need to divide by a length squared term at some point!

In PBR book, this is where they divide by the square of the distance (/R²) from the light. As being further from a light

*should*give inverse falloff, this would seem to do the job, but they do acknowledge this as a bit of a hack which is only present because point lights aren't a good physical model in the first place.Conversely, for area lights, they have a constant radiance for the entire light, so when they sample it, they just get the value - no /R² term appears at all for those. Area lights still effectively have inverse squared falloff, but in their implementation, this happens because when they're closer to a light, more of their samples hit the light. So they get it from the statistics alone. With point lights one can't possibly use normal sampling because the sample would never hit the point - so they special-case point lights to sample just once, and the /R² term is in the code for the point light.

In RTC, though, there is currently

*no*inverse falloff for light at all, which might explain some cases I have where two scenes appear to be adding the same amount of total light, but then the camera scaling needed to be set to two wildly different values to get a good result.