Пример #1
0
        // Multiplies two Spectrums together, by multiplying the spectral powers at each wavelength sample.
        //static Spectrum Multiply(Spectrum a, Spectrum s)
        //{
        //  Spectrum result = new Spectrum();
        //  for (int i = 0; i < NumberOfSamples; i++)
        //  {
        //    result.Powers[i] = a.Powers[i] * s.Powers[i];
        //  }
        //  return result;
        //}
        ///// <summary>
        ///// Multiplies the <see cref="Spectrum"/> by a scalar.
        ///// </summary>
        ///// <param name="s">The scalar.</param>
        //public void Multiply(float s)
        //{
        //  for (int i = 0; i < NumberOfSamples; i++)
        //    Powers[i] = Powers[i] * s;
        //}
        /// <summary>
        /// Computes direct and indirect light information when this spectrum passes through the earth's
        /// atmosphere.
        /// </summary>
        /// <param name="zenithAngle">
        /// The angle between the zenith and the direction of the light source emitting the simulated 
        /// spectrum in radian.
        /// </param>
        /// <param name="turbidity">
        /// The simulated atmospheric turbidity in the range [1.8, 20.0]. A turbidity of 2 describes a 
        /// clear day whereas a turbidity of 20 represents thick haze. A commonly used value is 2.2.
        /// </param>
        /// <param name="altitude">The simulated altitude in meters above mean sea level.</param>
        /// <param name="directIrradiance">
        /// Output: The spectral energy directly from the light source that survives transmission 
        /// through the atmosphere.
        /// </param>
        /// <param name="scatteredIrradiance">
        /// Output: The spectral energy scattered by the atmosphere, which makes up "skylight" (ambient
        /// light from the sky).
        /// </param>
        /// <remarks>
        /// <para>
        /// This method simulates the passage of this spectrum through earth's atmosphere, employing the
        /// National Renewable Energy Lab's "Bird model". Two new spectra, representing the direct and
        /// scattered irradiance resulting from passage through the atmosphere, are returned.
        /// </para>
        /// <para>
        /// If the light source is below the horizon, this model returns 0. Thus, it cannot be used to
        /// compute twilight.
        /// </para>
        /// </remarks>
        public void ApplyAtmosphericTransmittance(double zenithAngle, double turbidity, double altitude,
            Spectrum directIrradiance, Spectrum scatteredIrradiance)
        {
            //  For more info, see the reference in the notes of this class.

              double[] Ao =
              {
            0, 0, 0, 0,                                                           // 380 - 395
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.003,                                  // 400 - 450
            0.004, 0.006, 0.007, 0.009, 0.011, 0.014, 0.017, 0.021, 0.025, 0.03,  // 455 - 500
            0.035, 0.04, 0.044, 0.048, 0.055, 0.063, 0.071, 0.075, 0.08, 0.085,   // 505 - 550
            0.091, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.119, 0.12,         // 555 - 600
            0.12, 0.12, 0.10, 0.09, 0.09, 0.085, 0.08, 0.075, 0.07, 0.07,         // 605 - 650
            0.065, 0.06, 0.055, 0.05, 0.045, 0.04, 0.035, 0.028, 0.25, 0.023,     // 655 - 700
            0.02, 0.018, 0.016, 0.012, 0.012, 0.012, 0.012, 0.01, 0.01, 0.01,     // 705 - 750
            0.008, 0.007, 0.006, 0.005, 0.003, 0
              };

              double[] Au =
              {
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 380 - 500
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0,                                               // 505 - 550
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0,                                               // 550 - 600
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0,                                               // 605 - 650
            0, 0, 0, 0, 0, 0, 0, 0.15, 0, 0,                                            // 655 - 700
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0,                                               // 705 - 750
            0, 4.0, 0, 0, 0, 0,                                                         // 755 - 780
              };

              double[] Aw =
              {
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 380 - 500
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0,                                               // 505 - 550
            0, 0, 0, 0, 0, 0, 0, 0.075, 0, 0,                                           // 550  -600
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0,                                               // 605 - 650
            0, 0, 0, 0, 0, 0, 0, 0.016, 0.015, 0.014,                                   // 655 - 700
            0.013, 0.0125, 1.8, 2.3, 2.5, 2.3, 1.8, 0.061, 0.003, 0.0008,               // 705 - 750
            0.0001, 0.00001, 0.00001, 0.0001, 0.0003, 0.0006,                           // 755 - 780
              };

              double beta = 0.04608 * turbidity - 0.04586;
              double cosZenith = Math.Cos(zenithAngle);
              double zenithDeg = MathHelper.ToDegrees(zenithAngle);

              const double modelLimit = 90.0; //93.885
              if (zenithDeg < modelLimit)
              {
            // NREL air mass model
            //double m = 1.0 / (cosZenith + 0.15 * pow(93.885 - zenithDeg, -1.253));

            // International Comet Quarterly air mass model
            //double m = 1.0 / (cosZenith + 0.025 * exp(-11 * cosZenith));

            // SPECTRL2 air mass model (also adopted by CIE)
            double m = 1.0 / (cosZenith + 0.50572 * Math.Pow(93.885 - zenithDeg, -1.6364));

            // Account for high altitude. As you lose atmosphere, less scattering occurs.
            const double H = 8435.0; // pressure scale height
            double isothermalEffect = Math.Exp(-(altitude / H));
            m *= isothermalEffect;

            // ozone mass
            const double O3 = 0.35; // ozone amount, atm-cm
            double Mo = 1.003454 / Math.Sqrt(cosZenith * cosZenith + 0.006908);

            const double W = 2.5;         // precipitable water vapor (cm)
            const double omega = 0.945;   // single scattering albedo, 0.4 microns
            const double omegap = 0.095;  // Wavelength variation factor
            const double asym = 0.65;     // aerosol asymmetry factor

            double alg = Math.Log(1.0 - asym);
            double afs = alg * (1.459 + alg * (0.1595 + alg * 0.4129));
            double bfs = alg * (0.0783 + alg * (-0.3824 - alg * 0.5874));
            double fsp = 1.0 - 0.5 * Math.Exp((afs + bfs / 1.8) / 1.8);
            double fs = 1.0 - 0.5 * Math.Exp((afs + bfs * cosZenith) * cosZenith);

            for (int i = 0; i < NumberOfSamples; i++)
            {
              double um = 0.380 + (i * 0.005);

              // Rayleigh scattering
              double Tr = Math.Exp(-m / (Math.Pow(um, 4.0) * (115.6406 - (1.335 / (um * um)))));

              // Aerosols
              double a = um < 0.5 ? 1.0274 : 1.2060;
              double c1 = beta * Math.Pow(2.0 * um, -a);
              double Ta = Math.Exp(-c1 * m);

              // Water vapor
              double aWM = Aw[i] * W * m;
              double Tw = Math.Exp(-0.2385 * aWM / Math.Pow(1.0 + 20.07 * aWM, 0.45));

              // Ozone
              double To = Math.Exp(-Ao[i] * O3 * Mo);

              // Mixed gas is only important in infrared
              double Tm = Math.Exp((-1.41 * Au[i] * m) / Math.Pow(1.0 + 118.3 * Au[i] * m, 0.45));

              // Aerosol scattering
              double logUmOver4 = Math.Log(um / 0.4);
              double omegl = omega * Math.Exp(-omegap * logUmOver4 * logUmOver4);
              double Tas = Math.Exp(-omegl * c1 * m);

              // Aerosol absorptance
              double Taa = Math.Exp((omegl - 1.0) * c1 * m);

              // Primed Rayleigh scattering (m = 1.8)
              double Trp = Math.Exp(-1.8 / (um * um * um * um) * (115.6406 - 1.3366 / (um * um)));

              // Primed water vapor scattering
              double Twp = Math.Exp(-0.4293 * Aw[i] * W / Math.Pow((1.0 + 36.126 * Aw[i] * W), 0.45));

              // Mixed gas
              double Tup = Math.Exp(-2.538 * Au[i] / Math.Pow((1.0 + 212.94 * Au[i]), 0.45));

              // Primed aerosol scattering
              double Tasp = Math.Exp(-omegl * c1 * 1.8);

              // Primed aerosol absorptance
              double Taap = Math.Exp((omegl - 1.0) * c1 * 1.8);

              // Direct energy
              double xmit = Tr * Ta * Tw * To * Tm;

              directIrradiance.Powers[i] = (float)(Powers[i] * xmit);

              // diffuse energy
              double c2 = To * Tw * cosZenith * Taa;
              double c4 = 1.0;
              if (um <= 0.45)
              {
            c4 = Math.Pow((um + 0.55), 1.8);
              }

              double rhoa = Tup * Twp * Taap * (0.5 * (1.0 - Trp) + (1.0 - fsp) * Trp * (1.0 - Tasp));
              const double rho = 0.3; // ground albedo. Set less for ocean, more for snow.
              double dray = c2 * (1.0 - Math.Pow(Tr, 0.95)) / 2.0;
              double daer = c2 * Math.Pow(Tr, 1.5) * (1.0 - Tas) * fs;
              double drgd = (directIrradiance.Powers[i] * cosZenith + dray + daer) * rho * rhoa / (1.0 - rho * rhoa);

              scatteredIrradiance.Powers[i] = (float)(Powers[i] * (dray + daer + drgd) * c4);
              if (scatteredIrradiance.Powers[i] < 0)
            scatteredIrradiance.Powers[i] = 0;
            }
              }
              else
              {
            for (int i = 0; i < NumberOfSamples; i++)
            {
              directIrradiance.Powers[i] = 0;
              scatteredIrradiance.Powers[i] = 0;
            }
              }
        }
Пример #2
0
        // Multiplies two Spectrums together, by multiplying the spectral powers at each wavelength sample.
        //static Spectrum Multiply(Spectrum a, Spectrum s)
        //{
        //  Spectrum result = new Spectrum();

        //  for (int i = 0; i < NumberOfSamples; i++)
        //  {
        //    result.Powers[i] = a.Powers[i] * s.Powers[i];
        //  }

        //  return result;
        //}


        ///// <summary>
        ///// Multiplies the <see cref="Spectrum"/> by a scalar.
        ///// </summary>
        ///// <param name="s">The scalar.</param>
        //public void Multiply(float s)
        //{
        //  for (int i = 0; i < NumberOfSamples; i++)
        //    Powers[i] = Powers[i] * s;
        //}


        /// <summary>
        /// Computes direct and indirect light information when this spectrum passes through the earth's
        /// atmosphere.
        /// </summary>
        /// <param name="zenithAngle">
        /// The angle between the zenith and the direction of the light source emitting the simulated
        /// spectrum in radian.
        /// </param>
        /// <param name="turbidity">
        /// The simulated atmospheric turbidity in the range [1.8, 20.0]. A turbidity of 2 describes a
        /// clear day whereas a turbidity of 20 represents thick haze. A commonly used value is 2.2.
        /// </param>
        /// <param name="altitude">The simulated altitude in meters above mean sea level.</param>
        /// <param name="directIrradiance">
        /// Output: The spectral energy directly from the light source that survives transmission
        /// through the atmosphere.
        /// </param>
        /// <param name="scatteredIrradiance">
        /// Output: The spectral energy scattered by the atmosphere, which makes up "skylight" (ambient
        /// light from the sky).
        /// </param>
        /// <remarks>
        /// <para>
        /// This method simulates the passage of this spectrum through earth's atmosphere, employing the
        /// National Renewable Energy Lab's "Bird model". Two new spectra, representing the direct and
        /// scattered irradiance resulting from passage through the atmosphere, are returned.
        /// </para>
        /// <para>
        /// If the light source is below the horizon, this model returns 0. Thus, it cannot be used to
        /// compute twilight.
        /// </para>
        /// </remarks>
        public void ApplyAtmosphericTransmittance(double zenithAngle, double turbidity, double altitude,
                                                  Spectrum directIrradiance, Spectrum scatteredIrradiance)
        {
            //  For more info, see the reference in the notes of this class.

            double[] Ao =
            {
                0,         0,     0,     0,                                              // 380 - 395
                0,         0,     0,     0,     0,     0,     0,     0,     0, 0, 0.003, // 400 - 450
                0.004, 0.006, 0.007, 0.009, 0.011, 0.014, 0.017, 0.021, 0.025,0.03, // 455 - 500
                0.035,  0.04, 0.044, 0.048, 0.055, 0.063, 0.071, 0.075,  0.08,0.085, // 505 - 550
                0.091,  0.12,  0.12,  0.12,  0.12,  0.12,  0.12,  0.12, 0.119,0.12, // 555 - 600
                0.12,   0.12,  0.10,  0.09,  0.09, 0.085,  0.08, 0.075,  0.07,0.07, // 605 - 650
                0.065,  0.06, 0.055,  0.05, 0.045,  0.04, 0.035, 0.028,  0.25,0.023, // 655 - 700
                0.02,  0.018, 0.016, 0.012, 0.012, 0.012, 0.012,  0.01,  0.01,0.01, // 705 - 750
                0.008, 0.007, 0.006, 0.005, 0.003, 0
            };

            double[] Au =
            {
                0,   0, 0, 0, 0, 0, 0,    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 380 - 500
                0,   0, 0, 0, 0, 0, 0,    0, 0, 0,                                              // 505 - 550
                0,   0, 0, 0, 0, 0, 0,    0, 0, 0,                                              // 550 - 600
                0,   0, 0, 0, 0, 0, 0,    0, 0, 0,                                              // 605 - 650
                0,   0, 0, 0, 0, 0, 0, 0.15, 0, 0,                                              // 655 - 700
                0,   0, 0, 0, 0, 0, 0,    0, 0, 0,                                              // 705 - 750
                0, 4.0, 0, 0, 0, 0,                                                             // 755 - 780
            };

            double[] Aw =
            {
                0,            0,       0,      0,      0,   0,   0,     0,     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 380 - 500
                0,            0,       0,      0,      0,   0,   0,     0,     0, 0,                                              // 505 - 550
                0,            0,       0,      0,      0,   0,   0, 0.075,     0, 0,                                              // 550  -600
                0,            0,       0,      0,      0,   0,   0,     0,     0, 0,                                              // 605 - 650
                0,            0,       0,      0,      0,   0,   0, 0.016, 0.015,0.014, // 655 - 700
                0.013,   0.0125,     1.8,    2.3,    2.5, 2.3, 1.8, 0.061, 0.003,0.0008, // 705 - 750
                0.0001, 0.00001, 0.00001, 0.0001, 0.0003,0.0006,                    // 755 - 780
            };

            double beta      = 0.04608 * turbidity - 0.04586;
            double cosZenith = Math.Cos(zenithAngle);
            double zenithDeg = MathHelper.ToDegrees(zenithAngle);

            const double modelLimit = 90.0; //93.885

            if (zenithDeg < modelLimit)
            {
                // NREL air mass model
                //double m = 1.0 / (cosZenith + 0.15 * pow(93.885 - zenithDeg, -1.253));

                // International Comet Quarterly air mass model
                //double m = 1.0 / (cosZenith + 0.025 * exp(-11 * cosZenith));

                // SPECTRL2 air mass model (also adopted by CIE)
                double m = 1.0 / (cosZenith + 0.50572 * Math.Pow(93.885 - zenithDeg, -1.6364));

                // Account for high altitude. As you lose atmosphere, less scattering occurs.
                const double H = 8435.0; // pressure scale height
                double       isothermalEffect = Math.Exp(-(altitude / H));
                m *= isothermalEffect;

                // ozone mass
                const double O3 = 0.35; // ozone amount, atm-cm
                double       Mo = 1.003454 / Math.Sqrt(cosZenith * cosZenith + 0.006908);

                const double W      = 2.5;   // precipitable water vapor (cm)
                const double omega  = 0.945; // single scattering albedo, 0.4 microns
                const double omegap = 0.095; // Wavelength variation factor
                const double asym   = 0.65;  // aerosol asymmetry factor

                double alg = Math.Log(1.0 - asym);
                double afs = alg * (1.459 + alg * (0.1595 + alg * 0.4129));
                double bfs = alg * (0.0783 + alg * (-0.3824 - alg * 0.5874));
                double fsp = 1.0 - 0.5 * Math.Exp((afs + bfs / 1.8) / 1.8);
                double fs  = 1.0 - 0.5 * Math.Exp((afs + bfs * cosZenith) * cosZenith);

                for (int i = 0; i < NumberOfSamples; i++)
                {
                    double um = 0.380 + (i * 0.005);

                    // Rayleigh scattering
                    double Tr = Math.Exp(-m / (Math.Pow(um, 4.0) * (115.6406 - (1.335 / (um * um)))));

                    // Aerosols
                    double a  = um < 0.5 ? 1.0274 : 1.2060;
                    double c1 = beta * Math.Pow(2.0 * um, -a);
                    double Ta = Math.Exp(-c1 * m);

                    // Water vapor
                    double aWM = Aw[i] * W * m;
                    double Tw  = Math.Exp(-0.2385 * aWM / Math.Pow(1.0 + 20.07 * aWM, 0.45));

                    // Ozone
                    double To = Math.Exp(-Ao[i] * O3 * Mo);

                    // Mixed gas is only important in infrared
                    double Tm = Math.Exp((-1.41 * Au[i] * m) / Math.Pow(1.0 + 118.3 * Au[i] * m, 0.45));

                    // Aerosol scattering
                    double logUmOver4 = Math.Log(um / 0.4);
                    double omegl      = omega * Math.Exp(-omegap * logUmOver4 * logUmOver4);
                    double Tas        = Math.Exp(-omegl * c1 * m);

                    // Aerosol absorptance
                    double Taa = Math.Exp((omegl - 1.0) * c1 * m);

                    // Primed Rayleigh scattering (m = 1.8)
                    double Trp = Math.Exp(-1.8 / (um * um * um * um) * (115.6406 - 1.3366 / (um * um)));

                    // Primed water vapor scattering
                    double Twp = Math.Exp(-0.4293 * Aw[i] * W / Math.Pow((1.0 + 36.126 * Aw[i] * W), 0.45));

                    // Mixed gas
                    double Tup = Math.Exp(-2.538 * Au[i] / Math.Pow((1.0 + 212.94 * Au[i]), 0.45));

                    // Primed aerosol scattering
                    double Tasp = Math.Exp(-omegl * c1 * 1.8);

                    // Primed aerosol absorptance
                    double Taap = Math.Exp((omegl - 1.0) * c1 * 1.8);

                    // Direct energy
                    double xmit = Tr * Ta * Tw * To * Tm;

                    directIrradiance.Powers[i] = (float)(Powers[i] * xmit);

                    // diffuse energy
                    double c2 = To * Tw * cosZenith * Taa;
                    double c4 = 1.0;
                    if (um <= 0.45)
                    {
                        c4 = Math.Pow((um + 0.55), 1.8);
                    }

                    double       rhoa = Tup * Twp * Taap * (0.5 * (1.0 - Trp) + (1.0 - fsp) * Trp * (1.0 - Tasp));
                    const double rho  = 0.3; // ground albedo. Set less for ocean, more for snow.
                    double       dray = c2 * (1.0 - Math.Pow(Tr, 0.95)) / 2.0;
                    double       daer = c2 * Math.Pow(Tr, 1.5) * (1.0 - Tas) * fs;
                    double       drgd = (directIrradiance.Powers[i] * cosZenith + dray + daer) * rho * rhoa / (1.0 - rho * rhoa);

                    scatteredIrradiance.Powers[i] = (float)(Powers[i] * (dray + daer + drgd) * c4);
                    if (scatteredIrradiance.Powers[i] < 0)
                    {
                        scatteredIrradiance.Powers[i] = 0;
                    }
                }
            }
            else
            {
                for (int i = 0; i < NumberOfSamples; i++)
                {
                    directIrradiance.Powers[i]    = 0;
                    scatteredIrradiance.Powers[i] = 0;
                }
            }
        }