123 lines
3.4 KiB
C++
123 lines
3.4 KiB
C++
//
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
|
// Copyright (c) Contributors to the OpenEXR Project.
|
|
//
|
|
|
|
#include "PxDeepUtils.h"
|
|
|
|
namespace PxDeep
|
|
{
|
|
|
|
//-*****************************************************************************
|
|
// Density/Viz/DZ calculations are always performed in double precision.
|
|
// We try to leave them alone as much as possible, but the logarithm can get
|
|
// weird for very very small numbers. The "isfinite" call basically rules
|
|
// out NaN and Infinity results, though it doesn't bother with subnormal
|
|
// numbers, since the error case we're worried about is log being too big.
|
|
// viz = exp( -dz * density )
|
|
// log( viz ) = -dz * density
|
|
// density = -log( viz ) / dz
|
|
double
|
|
DensityFromVizDz (double i_viz, double i_dz)
|
|
{
|
|
assert (i_viz >= 0.0);
|
|
assert (i_viz <= 1.0);
|
|
assert (i_dz >= 0.0);
|
|
|
|
if (i_viz >= 1.0)
|
|
{
|
|
// There's no attenuation at all, so there's no density!
|
|
return 0.0;
|
|
}
|
|
else if (i_viz <= 0.0)
|
|
{
|
|
// There's total attenuation, so we use our max density.
|
|
return PXDU_DENSITY_OF_VIZ_0;
|
|
}
|
|
else if (i_dz <= 0.0)
|
|
{
|
|
// There's no depth, and viz is greater than zero,
|
|
// so we assume the density is as high as possible
|
|
return PXDU_DENSITY_OF_VIZ_0;
|
|
}
|
|
else
|
|
{
|
|
double d = -log (i_viz) / i_dz;
|
|
if (!isfinite (d)) { return PXDU_DENSITY_OF_VIZ_0; }
|
|
else { return d; }
|
|
}
|
|
}
|
|
|
|
//-*****************************************************************************
|
|
// We can often treat "density times dz" as a single quantity without
|
|
// separating it.
|
|
// viz = exp( -densityTimesDz )
|
|
// log( viz ) = -densityTimesDz
|
|
// densityTimesDz = -log( viz )
|
|
double
|
|
DensityTimesDzFromViz (double i_viz)
|
|
{
|
|
assert (i_viz >= 0.0);
|
|
assert (i_viz <= 1.0);
|
|
|
|
if (i_viz >= 1.0)
|
|
{
|
|
// There's no attenuation at all, so there's no density!
|
|
return 0.0;
|
|
}
|
|
else if (i_viz <= 0.0)
|
|
{
|
|
// There's total attenuation, so we use our max density.
|
|
return PXDU_DENSITY_OF_VIZ_0 * PXDU_DZ_OF_VIZ_0;
|
|
}
|
|
else
|
|
{
|
|
double d = -log (i_viz);
|
|
if (!isfinite (d)) { return PXDU_DENSITY_OF_VIZ_0 * PXDU_DZ_OF_VIZ_0; }
|
|
else { return d; }
|
|
}
|
|
}
|
|
|
|
//-*****************************************************************************
|
|
// viz = exp( -dz * density )
|
|
// log( viz ) = -dz * density
|
|
// dz = -log( viz ) / density
|
|
// Note that this is basically the same as the computation above.
|
|
double
|
|
DzFromVizDensity (double i_viz, double i_density)
|
|
{
|
|
assert (i_viz >= 0.0);
|
|
assert (i_viz <= 1.0);
|
|
assert (i_density >= 0.0);
|
|
|
|
if (i_viz >= 1.0)
|
|
{
|
|
// There's no attenuation, so there's no depth.
|
|
return 0.0;
|
|
}
|
|
else if (i_viz <= 0.0)
|
|
{
|
|
// There's total attenuation, so we use the smallest depth
|
|
// for our max density.
|
|
return PXDU_DZ_OF_VIZ_0;
|
|
}
|
|
else if (i_density <= 0.0)
|
|
{
|
|
// Hmmm. There's no density, but there is some attenuation,
|
|
// which basically implies an infinite depth.
|
|
// We'll use the minimum density.
|
|
// This whole part is hacky at best.
|
|
double dz = -log (i_viz) / PXDU_MIN_NON_ZERO_DENSITY;
|
|
if (!isfinite (dz)) { return PXDU_MAX_DZ; }
|
|
else { return dz; }
|
|
}
|
|
else
|
|
{
|
|
double dz = -log (i_viz) / i_density;
|
|
if (!isfinite (dz)) { return PXDU_MAX_DZ; }
|
|
else { return dz; }
|
|
}
|
|
}
|
|
|
|
} // End namespace PxDeep
|