ebruneton / precomputed_atmospheric_scattering

This project provides a new implementation of our EGSR 2008 paper "Precomputed Atmospheric Scattering".
BSD 3-Clause "New" or "Revised" License
908 stars 120 forks source link

Exception thrown with GetProfileDensity function #23

Closed LocalStarlight closed 6 years ago

LocalStarlight commented 6 years ago

I'm trying to integrate your code using the main model.h/model.cc sources, but looking to the demo for values to put into the atmosphere parameters as I'm trying to create an Earth atmosphere, but I'm having a problem, and I must be being stupid and misunderstanding something.

The problem is with the widths of the density layers. In the demo scene, these are as follows:

Rayleigh layer: 0.0 Mie layer: 0.0 Ozone layer 1: 25000.0 Ozone layer 2: 0.0

You state in definitions.glsl that, "the width of the last layer is ignored, i.e. it always extend to the top atmosphere boundary." So I presume that's why the Rayleigh, Mie, and second Ozone layers all have a width of zero.

However, the function that uses this width is as follows:

Number GetProfileDensity(IN(DensityProfile) profile, Length altitude) {
  return altitude < profile.layers[0].width ?
      GetLayerDensity(profile.layers[0], altitude) :
      GetLayerDensity(profile.layers[1], altitude);
}

In other words, if the altitude is less than the width of the first layer, then we're in the first layer, otherwise we're in the second layer. But, since altitude is always going to be greater than 0, this function will always try to GetLayerDensity from the second layer. So this is throwing an exception the first time it is hit because it tries to get the density from the second layer of the Rayleigh profile, and there isn't one.

What am I missing / doing wrong here?

It would be easy to fudge this by just putting an arbitrary massive number into the width for all the layers except Ozone layer 1, but that's not what's in the demo code, so I'm confused and concerned I'm missing something.

tobspr commented 6 years ago

I had the same issue. What you are overlooking in the demo code is (a bit counterintuitive):

while (layers.size() < kLayerCount) {
  layers.insert(layers.begin(), DensityProfileLayer());
}

The array size is always 2, and the ray/mie layer only has one layer. So for that case, profile.layers[0].width is zero, and it will always use the second layer. If you would use push_back for example, this would not work.

LocalStarlight commented 6 years ago

Aaah, OK. That makes sense.

I'm porting this into Unreal Engine, and using their data structures so was using their own array structure but not initialising it to be two values.

Thanks!