public static SilverLiningSpectrum operator *(SilverLiningSpectrum s1, SilverLiningSpectrum s2) { SilverLiningSpectrum sOut = new SilverLiningSpectrum(); for (int i = 0; i < NSAMPLES; i++) { sOut.powers[i] = s1.powers[i] * s2.powers[i]; } return(sOut); }
private void ComputeSun (double altitude) { Vector3 sunPos = ephemeris.GetSunPositionHorizon (); sunPos.Normalize (); double cosZenith = sunPos.y; if (lastSunT != T || lastSunZenith != cosZenith) { lastSunT = T; lastSunZenith = cosZenith; lightingChanged = true; double solarAltitude = DEGREES(Math.Asin(sunPos.y)); if (solarAltitude > 1.0) { perezBlend = 0; } else if (solarAltitude < 0) { perezBlend = 1.0f; } else { perezBlend = 1.0f - (float)solarAltitude; } if (cosZenith > 0) { double zenithAngle = Math.Acos (cosZenith); SilverLiningSpectrum solarDirect = new SilverLiningSpectrum (); SilverLiningSpectrum solarScattered = new SilverLiningSpectrum (); sunSpectrum.ApplyAtmosphericTransmittance (zenithAngle, cosZenith, T, altitude, ref solarDirect, ref solarScattered); sunTransmittedLuminance = solarDirect.ToXYZ (); sunScatteredLuminance = solarScattered.ToXYZ (); // Apply sunset color tweaks double alpha = zenithAngle / (PI * 0.5); for (int i = 0; i < boostExp; i++) alpha *= alpha; sunScatteredLuminance.x *= (float)(1.0 + alpha * XBoost); sunScatteredLuminance.y *= (float)(1.0 + alpha * YBoost); sunScatteredLuminance.z *= (float)(1.0 + alpha * ZBoost); } else { // In twilight conditions, we lookup luminance based on experimental results // on cloudless nights. int lower = (int)Math.Floor (solarAltitude); int higher = (int)Math.Ceiling (solarAltitude); float alpha = (float)(solarAltitude - lower); float a = 0; float b = 0; if (lower >= -16 && higher >= -16) { a = twilightLuminance[lower]; b = twilightLuminance[higher]; } // Blend light from sunset const double epsilon = 0.001; SilverLiningSpectrum solarDirect = new SilverLiningSpectrum (); SilverLiningSpectrum solarScattered = new SilverLiningSpectrum (); double zenithAngle = PI * 0.5 - epsilon; sunSpectrum.ApplyAtmosphericTransmittance (zenithAngle, Math.Cos (zenithAngle), T, altitude, ref solarDirect, ref solarScattered); sunTransmittedLuminance = solarDirect.ToXYZ (); sunScatteredLuminance = solarScattered.ToXYZ (); float Y = (1 - alpha) * a + alpha * b; // luminance per lookup table float x = 0.25f; float y = 0.25f; float minDirectional = 0.1f; float X = x * (Y / y); float Z = (1.0f - x - y) * (Y / y); alpha = -(float)solarAltitude / 2.0f; if (alpha > 1.0f) alpha = 1.0f; if (alpha < 0) alpha = 0; alpha = alpha * alpha; sunTransmittedLuminance = sunTransmittedLuminance * Y * minDirectional * alpha + sunTransmittedLuminance * (1.0f - alpha); Vector3 twilight = new Vector3 (X, Y, Z); sunScatteredLuminance = twilight * alpha + sunScatteredLuminance * (1.0f - alpha); // Apply sunset color tweaks sunScatteredLuminance.x *= 1.0f + XBoost; sunScatteredLuminance.y *= 1.0f + YBoost; sunScatteredLuminance.z *= 1.0f + ZBoost; } if (isOvercast) { sunTransmittedLuminance = (sunTransmittedLuminance * (overcastBlend * overcastTransmission)) + (sunTransmittedLuminance * (1.0f - overcastBlend)); sunScatteredLuminance = (sunScatteredLuminance * (overcastBlend * overcastTransmission)) + (sunScatteredLuminance * (1.0f - overcastBlend)); } sunTransmittedLuminance = sunTransmittedLuminance * sunTransmissionScale; sunScatteredLuminance = sunScatteredLuminance * sunScatteredScale; } }
public SilverLiningSky() { sunDistance *= (float)SilverLining.unitScale; moonDistance *= (float)SilverLining.unitScale; H *= (float)SilverLining.unitScale; ephemeris = new SilverLiningEphemeris (); InitTwilightLuminances (); sunSpectrum = new SilverLiningSolarSpectrum (); lunarSpectrum = new SilverLiningLunarSpectrum (); XYZ2RGB = new SilverLiningMatrix3 (3.240479, -0.969256, 0.055648, -1.537150, 1.875992, -0.204043, -0.498535, 0.041556, 1.057311); XYZ2RGB4 = new Matrix4x4 (); XYZ2RGB4[0, 0] = 3.240479f; XYZ2RGB4[0, 1] = -0.969256f; XYZ2RGB4[0, 2] = 0.055648f; XYZ2RGB4[0, 3] = 0.0f; XYZ2RGB4[1, 0] = -1.537150f; XYZ2RGB4[1, 1] = 1.875992f; XYZ2RGB4[1, 2] = -0.204043f; XYZ2RGB4[1, 3] = 0.0f; XYZ2RGB4[2, 0] = -0.498535f; XYZ2RGB4[2, 1] = 0.041556f; XYZ2RGB4[2, 2] = 1.057311f; XYZ2RGB4[2, 3] = 0.0f; XYZ2RGB4[3, 0] = 0.0f; XYZ2RGB4[3, 1] = 0.0f; XYZ2RGB4[3, 2] = 0.0f; XYZ2RGB4[3, 3] = 1.0f; }
public void ApplyAtmosphericTransmittance(double zenithAngle, double cosZenith, double T, double alt, ref SilverLiningSpectrum directIrradiance, ref SilverLiningSpectrum scatteredIrradiance) { double beta = 0.04608 * T - 0.04586; double zenithDeg = DEGREES(zenithAngle); const double modelLimit = 90.0; //93.885 if (zenithDeg < modelLimit) { // SPECTRL2 air mass model double m = 1.0 / (cosZenith + 0.50572 * Math.Pow(96.07995 - zenithDeg, -1.6364)); m *= airMassMultiplier; // Account for high altitude. As you lose atmosphere, less scattering occurs. H *= SilverLining.unitScale; double isothermalEffect = Math.Exp(-(alt / H)); m *= isothermalEffect; // ozone mass double Mo = 1.003454 / Math.Sqrt(cosZenith * cosZenith + 0.006908); const double omega = 0.945; // single scaterring albedo, 0.4 microns const double omegap = 0.095; // Wavelength variation factor const double assym = 0.65; // aerosol assymetry factor double alg = Math.Log(1.0 - assym); 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 < NSAMPLES; i++) { double um = 0.380 + (i * 0.005); // Rayleigh scattering double Tr = Math.Exp(-m / (Math.Pow(um, 4.0) * (115.6406 - (1.3366 / (um * um))))); // Aerosols double a; if (um < 0.5) { a = 1.0274; } else { a = 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] = powers[i] * xmit; // diffuse energy double c2 = powers[i] * To * Tw * Tm * cosZenith * Taa; double c4 = 1.0; if (um <= 0.45) { c4 = Math.Pow((um + 0.55), 1.8); } double rhoa = Twp * Tup * Taap * (0.5 * (1.0 - Trp) + (1.0 - fsp) * Trp * (1.0 - Tasp)); 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] = (dray + daer + drgd) * c4; if (scatteredIrradiance.powers[i] < 0) { scatteredIrradiance.powers[i] = 0; } } } else { for (int i = 0; i < NSAMPLES; i++) { directIrradiance.powers[i] = 0; scatteredIrradiance.powers[i] = 0; } } }
public void ApplyAtmosphericTransmittance(double zenithAngle, double cosZenith, double T, double alt, ref SilverLiningSpectrum directIrradiance, ref SilverLiningSpectrum scatteredIrradiance) { double beta = 0.04608 * T - 0.04586; double zenithDeg = DEGREES(zenithAngle); const double modelLimit = 90.0; //93.885 if (zenithDeg < modelLimit) { // SPECTRL2 air mass model double m = 1.0 / (cosZenith + 0.50572 * Math.Pow(96.07995 - zenithDeg, -1.6364)); m *= airMassMultiplier; // Account for high altitude. As you lose atmosphere, less scattering occurs. H *= SilverLining.unitScale; double isothermalEffect = Math.Exp(-(alt / H)); m *= isothermalEffect; // ozone mass double Mo = 1.003454 / Math.Sqrt ( cosZenith * cosZenith + 0.006908 ); const double omega = 0.945; // single scaterring albedo, 0.4 microns const double omegap = 0.095; // Wavelength variation factor const double assym = 0.65; // aerosol assymetry factor double alg = Math.Log(1.0 - assym); 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 < NSAMPLES; i++) { double um = 0.380 + (i * 0.005); // Rayleigh scattering double Tr = Math.Exp(-m / (Math.Pow(um, 4.0) * (115.6406 - (1.3366 / (um * um))))); // Aerosols double a; if (um < 0.5) { a = 1.0274; } else { a = 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] = powers[i] * xmit; // diffuse energy double c2 = powers[i] * To * Tw * Tm * cosZenith * Taa; double c4 = 1.0; if (um <= 0.45) { c4 = Math.Pow( (um + 0.55), 1.8); } double rhoa = Twp * Tup * Taap * (0.5 * (1.0 - Trp) + (1.0 - fsp) * Trp * (1.0 - Tasp) ); 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] = (dray + daer + drgd) * c4; if (scatteredIrradiance.powers[i] < 0) scatteredIrradiance.powers[i] = 0; } } else { for (int i = 0; i < NSAMPLES; i++) { directIrradiance.powers[i] = 0; scatteredIrradiance.powers[i] = 0; } } }
public static SilverLiningSpectrum operator * (SilverLiningSpectrum s1, SilverLiningSpectrum s2) { SilverLiningSpectrum sOut = new SilverLiningSpectrum(); for (int i = 0; i < NSAMPLES; i++) { sOut.powers[i] = s1.powers[i] * s2.powers[i]; } return sOut; }