Beispiel #1
2
static real ChiSquare(creal x, cint df)
{
  real y;

  if( df <= 0 ) return -999;

  if( x <= 0 ) return 0;
  if( x > 1000*df ) return 1;

  if( df > 1000 ) {
    if( x < 2 ) return 0;
    y = 2./(9*df);
    y = (powx(x/df, 1/3.) - (1 - y))/sqrtx(y);
    if( y > 5 ) return 1;
    if( y < -18.8055 ) return 0;
    return Normal(y);
  }

  y = .5*x;

  if( df & 1 ) {
    creal sqrty = sqrtx(y);
    real h = Erf(sqrty);
    count i;

    if( df == 1 ) return h;

    y = sqrty*expx(-y)/.8862269254527579825931;
    for( i = 3; i < df; i += 2 ) {
      h -= y;
      y *= x/i;
    }
    y = h - y;
  }
  else {
    real term = expx(-y), sum = term;
    count i;

    for( i = 1; i < df/2; ++i )
      sum += term *= y/i;
    y = 1 - sum;
  }

  return Max(0., y);
}
Beispiel #2
0
inline hvl_float CalcB1pB2(const HVL_Context *ctx, const hvl_float &a3, const hvl_float &sqrtz)
{
	const hvl_float b1 = ctx->HVL_ONE / (Exp(a3) - ctx->HVL_ONE);
	const hvl_float b2 = ctx->HVL_HALF * (ctx->HVL_ONE + Erf(sqrtz));

	return b1 + b2;
}
Beispiel #3
0
inline double HVL_da3_internal(const HVL_Context *ctx,
			       const hvl_float &a0, const hvl_float &a3,
			       const hvl_float &gauss_base, const hvl_float &b1pb2, const hvl_float &reca3, const hvl_float &sqrtz)
{
	if (a3 == ctx->HVL_ZERO)
		return ToDouble(-ctx->HVL_HALF * a0 * Erf(sqrtz) * gauss_base);

	const hvl_float a3e = Exp(a3);
	const hvl_float nmr = gauss_base * a0 * (-reca3 + (a3e / (Pow(a3e - ctx->HVL_ONE, 2) * b1pb2)));

	return ToDouble(reca3 * nmr / b1pb2);
}
Beispiel #4
0
// Microfacet Utility Functions
static void BeckmannSample11(Float cosThetaI, Float U1, Float U2,
                             Float *slope_x, Float *slope_y) {
    /* Special case (normal incidence) */
    if (cosThetaI > .9999) {
        Float r = std::sqrt(-std::log(1.0f - U1));
        Float sinPhi = std::sin(2 * Pi * U2);
        Float cosPhi = std::cos(2 * Pi * U2);
        *slope_x = r * cosPhi;
        *slope_y = r * sinPhi;
    }

    /* The original inversion routine from the paper contained
       discontinuities, which causes issues for QMC integration
       and techniques like Kelemen-style MLT. The following code
       performs a numerical inversion with better behavior */
    Float sinThetaI =
        std::sqrt(std::max((Float)0, (Float)1 - cosThetaI * cosThetaI));
    Float tanThetaI = sinThetaI / cosThetaI;
    Float cotThetaI = 1 / tanThetaI;

    /* Search interval -- everything is parameterized
       in the Erf() domain */
    Float a = -1, c = Erf(cotThetaI);
    Float sample_x = std::max(U1, (Float)1e-6f);

    /* Start with a good initial guess */
    // Float b = (1-sample_x) * a + sample_x * c;

    /* We can do better (inverse of an approximation computed in
     * Mathematica) */
    Float thetaI = std::acos(cosThetaI);
    Float fit = 1 + thetaI * (-0.876f + thetaI * (0.4265f - 0.0594f * thetaI));
    Float b = c - (1 + c) * std::pow(1 - sample_x, fit);

    /* Normalization factor for the CDF */
    static const Float SQRT_PI_INV = 1.f / std::sqrt(Pi);
    Float normalization =
        1 /
        (1 + c + SQRT_PI_INV * tanThetaI * std::exp(-cotThetaI * cotThetaI));

    int it = 0;
    while (++it < 10) {
        /* Bisection criterion -- the oddly-looking
           Boolean expression are intentional to check
           for NaNs at little additional cost */
        if (!(b >= a && b <= c)) b = 0.5f * (a + c);

        /* Evaluate the CDF and its derivative
           (i.e. the density function) */
        Float invErf = ErfInv(b);
        Float value =
            normalization *
                (1 + b + SQRT_PI_INV * tanThetaI * std::exp(-invErf * invErf)) -
            sample_x;
        Float derivative = normalization * (1 - invErf * tanThetaI);

        if (std::abs(value) < 1e-5f) break;

        /* Update bisection intervals */
        if (value > 0)
            c = b;
        else
            a = b;

        b -= value / derivative;
    }

    /* Now convert back into a slope value */
    *slope_x = ErfInv(b);

    /* Simulate Y component */
    *slope_y = ErfInv(2.0f * std::max(U2, (Float)1e-6f) - 1.0f);

    Assert(!std::isinf(*slope_x));
    Assert(!std::isnan(*slope_x));
    Assert(!std::isinf(*slope_y));
    Assert(!std::isnan(*slope_y));
}
Beispiel #5
0
static inline real Normal(creal x)
{
  return .5*Erf(x/1.414213562373095048801689) + .5;
}