1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
|
//
// 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
|