public MyColor SkyColorAtPointDist(double h0, GeoPolar2d p, double dist, MyColor ground, double nDotL, double ambiantLight) { double theta = GetTheta(p); SkyColorAtPointComputer(h0, dist, out MyDColor attenuation, out MyDColor airColorR, out MyDColor airColorM, out MyDColor directPart); MyColor color = CombineForAerialPrespective(ground, theta, nDotL, ambiantLight, ref attenuation, ref airColorR, ref airColorM, ref directPart); return(color); }
public MyColor SkyColorAtPoint(GeoPolar2d p) { double[] values = new double[3]; for (int k = 0; k < 3; k++) { inters.Value[k].TryGetValue(p.Lat.Radians, p.Lon.Radians, out double o); values[k] = o; } return(Utils.ColorFromDoubleArray(values)); }
/// <param name="turbidity">2.2 is clear sky</param> public Nishita(GeoPolar2d sunPos, double turbidity = 2.2) { //thetaSun = sunPos.Lon.Radians; //phiSun = sunPos.Lat.Radians; thetaSun = sunPos.Lat.Radians; phiSun = sunPos.Lon.Radians; this.mieScale = turbidity / 220; sinThetaSun = Math.Sin(thetaSun); sinPhiSun = Math.Sin(phiSun); cosThetaSun = Math.Cos(thetaSun); cosPhiSun = Math.Cos(phiSun); }
public static double DistBetweenLatLon(GeoPolar2d p1, GeoPolar2d p2) { // haversine, https://www.movable-type.co.uk/scripts/latlong.html var phi1 = p1.Lat.Radians; var phi2 = p2.Lat.Radians; var deltaPhi = p2.Lat.Radians - p1.Lat.Radians; var deltaLam = p2.Lon.Radians - p1.Lon.Radians; var a = Math.Sin(deltaPhi / 2) * Math.Sin(deltaPhi / 2) + Math.Sin(deltaLam / 2) * Math.Sin(deltaLam / 2) * Math.Cos(phi1) * Math.Cos(phi2); var c = 2 * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1 - a)); return(AlphaMeters * c); }
// https://www.movable-type.co.uk/scripts/latlong.html public static GeoPolar2d GetDestFromBearing(GeoPolar2d p1, Angle bearing, double d) { var phi1 = p1.Lat.Radians; var lam1 = p1.Lon.Radians; var brng = bearing.Radians; var R = AlphaMeters; var phi2 = Math.Asin(Math.Sin(phi1) * Math.Cos(d / R) + Math.Cos(phi1) * Math.Sin(d / R) * Math.Cos(brng)); var lam2 = lam1 + Math.Atan2( Math.Sin(brng) * Math.Sin(d / R) * Math.Cos(phi1), Math.Cos(d / R) - Math.Sin(phi1) * Math.Sin(phi2)); return(new GeoPolar2d(Angle.FromRadians(phi2), Angle.FromRadians(lam2))); }
public DirectBitmap RenderLight(Vector3f light, float directLight, float ambientLight, Nishita skyColor) { var ret = new DirectBitmap(Width, Height); MyColor color = new MyColor(); var maxDistSq = DistSq.Select(p => p ?? -1).Max(); double fovRad = Camera.MaxAngleRad - Camera.MinAngleRad; NishitaInterp sc = skyColor == null ? null : new NishitaInterp(skyColor, Camera.HeightOffset, directLight, ambientLight, Math.Sqrt(maxDistSq), GetLatRadFromXIndex(0), GetLatRadFromXIndex(Width - 1), 10, GetLonRadFromYIndex(0), GetLonRadFromYIndex(Height - 1), 10); for (int x = 0; x < Width; x++) { for (int y = 0; y < Height; y++) { var skyPt = new GeoPolar2d( Angle.FromRadians(GetLatRadFromXIndex(x)), Angle.FromRadians(GetLonRadFromYIndex(y))); var index = (Width - 1 - x) + y * Width; var distSq = DistSq[index]; if (!distSq.HasValue) { color = sc?.SkyColorAtPoint(skyPt) ?? View.skyColor; } else { Bmp.GetPixel(Width - 1 - x, y, ref color); ns[index].Normalize(); var dot = Math.Max(0, Vector3f.Dot(ref ns[index], ref light)); if (sc != null) { color = sc.SkyColorAtPointDist(skyPt, Math.Sqrt(distSq.Value), color, dot); } else { var l = dot * directLight + ambientLight; var ndotl = l > 1.0f ? 1.0f : l < 0.0f ? 0.0f : l; color.ScaleSelf(ndotl); } } ret.SetPixel(Width - 1 - x, Height - 1 - y, color); } } return(ret); }
private TwoDInterpolator[] GetInters() { double[] lats = new double[numLat]; for (int x = 0; x < numLat; x++) { lats[x] = latRadMin + (latRadMax - latRadMin) * x / (numLat + -1); } double[] lons = new double[numLon]; for (int y = 0; y < numLon; y++) { lons[y] = lonRadMin + (lonRadMax - lonRadMin) * y / (numLon + -1); } double[][][] values = new double[Utils.ColorToDoubleArray.Length][][]; for (int k = 0; k < values.Length; k++) { values[k] = new double[numLat][]; for (int x = 0; x < numLat; x++) { values[k][x] = new double[numLon]; } } for (int x = 0; x < lats.Length; x++) { for (int y = 0; y < lons.Length; y++) { var skyPt = new GeoPolar2d(Angle.FromRadians(lats[x]), Angle.FromRadians(lons[y])); var color2 = skyColor.SkyColorAtPoint(h0, skyPt); for (int k = 0; k < values.Length; k++) { values[k][x][y] = Utils.ColorToDoubleArray[k](color2); } } } var inters = new TwoDInterpolator[values.Length]; for (int k = 0; k < inters.Length; k++) { inters[k] = new TwoDInterpolator(lats, lons, values[k], intType); } return(inters); }
/// <param name="turbidity">2.2 is clear sky</param> public Preetham(GeoPolar2d sunPos, double turbidity = 2.2) { // Theta is angle from zenith down to sun. // phi is angle around up-axis from south. thetaSun = Math.PI / 2 - sunPos.Lon.Radians; phiSun = Math.PI - sunPos.Lat.Radians; while (phiSun > +Math.PI) { phiSun -= 2 * Math.PI; } while (phiSun < -Math.PI) { phiSun += 2 * Math.PI; } skyParams = new AllSkylightDistCoef(turbidity, thetaSun); }
public MyColor SkyColorAtPoint(GeoPolar2d p) { if (p.Lon.Radians < 0.0) { return(new MyColor()); } // Theta is angle from zenith down to sun. // phi is angle around up-axis from south. var theta = Math.PI / 2 - p.Lon.Radians; var phi = Math.PI - p.Lat.Radians; while (phi > +Math.PI) { phi -= 2 * Math.PI; } while (phi < -Math.PI) { phi += 2 * Math.PI; } var Y = SkyChanelAtPoint(skyParams.Y, theta, phi); var x = SkyChanelAtPoint(skyParams._x, theta, phi); var y = SkyChanelAtPoint(skyParams._y, theta, phi); // Convert from luminance and chromaticity to RGB. var X = Y / y * x; var Z = Y / y * (1 - x - y); var r = +3.241030 * X - 1.537410 * Y - 0.498620 * Z; var g = -0.969242 * X + 1.875960 * Y + 0.041555 * Z; var b = +0.055632 * X - 0.203979 * Y + 1.056980 * Z; double scale = -3.0; r = 1 - Math.Exp(scale * r); g = 1 - Math.Exp(scale * g); b = 1 - Math.Exp(scale * b); var color = new MyColor( (byte)(255 * Math.Max(0.0, Math.Min(1.0, r))), (byte)(255 * Math.Max(0.0, Math.Min(1.0, g))), (byte)(255 * Math.Max(0.0, Math.Min(1.0, b)))); return(color); }
public MyColor SkyColorAtPointDist(GeoPolar2d p, double dist, MyColor ground, double nDotL) { double theta = skyColor.GetTheta(p); MyDColor attenuation = new MyDColor(); MyDColor airColorR = new MyDColor(); MyDColor airColorM = new MyDColor(); MyDColor directPart = new MyDColor(); aerialPers.Value.TryGetValues(dist, ref attenuation, ref airColorR, ref airColorM, ref directPart); MyColor color = Nishita.CombineForAerialPrespective(ground, theta, nDotL, ambientLight, ref attenuation, ref airColorR, ref airColorM, ref directPart); return(color); }
public void RenderToJpeg(string filename) { int width = 1000; int height = 250; MyColor[][] image = new MyColor[width][]; for (int phiI = 0; phiI < width; phiI++) { double phiDeg = phiI * 360.0 / width; image[phiI] = new MyColor[height]; for (int thetaI = 0; thetaI < height; thetaI++) { double thetaDeg = thetaI * 90.0 / height; var p = new GeoPolar2d(Angle.FromDecimalDegrees(phiDeg), Angle.FromDecimalDegrees(thetaDeg)); image[phiI][thetaI] = SkyColorAtPoint(p); } } Utils.WriteImageFile(image, filename, (a) => a, OutputType.JPEG); }
public MyColor SkyColorAtPoint(double h0, GeoPolar2d p) { double thetaPixel = p.Lat.Radians; double phiPixel = p.Lon.Radians; if (Math.Abs(thetaPixel - thetaSun) < Math.PI / 180 && Math.Abs(phiPixel - phiSun) < Math.PI / 180) { return(MyColor.White); } double theta = Utils.AngleBetween(thetaPixel, phiPixel, thetaSun, phiSun); double sinPhi = Math.Sin(phiPixel); if (sinPhi < 0.0) { return(new MyColor()); } double cosPhi = Math.Cos(phiPixel); double sinTheta = Math.Sin(thetaPixel); double cosTheta = Math.Cos(thetaPixel); var intersect = Intersect(h0, sinPhi, H_atmosphere); if (!intersect.HasValue) { return(new MyColor()); } double l_max = intersect.Value; var rayRR = BetaR0[(int)Channel.R] * P_R(theta); var rayRG = BetaR0[(int)Channel.G] * P_R(theta); var rayRB = BetaR0[(int)Channel.B] * P_R(theta); var rayM = mieScale * BetaM0 * P_M(theta); var tot = Integrate(0, l_max - 10, l => ElementLight(rayRR, rayRG, rayRB, rayM, h0, l, sinPhi, cosPhi, sinTheta, cosTheta)); MyColor color = ScaleColor(ref tot); return(color); }
public static GeoPolar2d GetSunPosition(Angle lat, Angle lon, DateTimeOffset curTime) { // From: http://www.powerfromthesun.net/Book/chapter03/chapter03.html // ts is standard time in decimal hours var J = curTime.ToUniversalTime().DayOfYear; var ts = curTime.ToUniversalTime().TimeOfDay.TotalHours; // solar time in radians var omega = Math.PI / 12 * (ts - 12) + lon.Radians + 0.170 / 12 * Math.PI * Math.Sin(4.0 * Math.PI * (J - 80) / 373.0) - 0.129 / 12 * Math.PI * Math.Sin(2.0 * Math.PI * (J - 8) / 355.0); // The solar declination in radians is approximated by var delta = 0.4093 * Math.Sin(2.0 * Math.PI * (J - 81) / 368.0); /* * Local coords * alpha is solar angle above horizon * A is solar azimuthal angle * S_z = sin alpha (upward) * S_e = cos alpha sin A (east pointing) * S_n = cos alpha cos A (north pointing) * * Earth-center coords * S'_m = cos delta cos omega (from center to equator, hits where observer meridian hits equator) * S'_e = cos delta sin omega (eastward on equator) * S'_p = sin delta (north polar) * * Rotate up from polar up to z up * S_z = S'_m cos lat + S'_p sin lat * S_e = S'_e * S_n = S'_p cos lat - S'_m sin lat * * Substituting * sin alpha = cos delta cos omega cos lat + sin delta sin lon * cos alpha sin A = cos delta sin omega * cos alpha cos A = sin delta cos lat - cos delta cos omega sin lon * * So * alpha = asin (cos delta cos omega cos lat + sin delta sin lon) * A = atan2(cos delta sin omega , (sin delta cos lat - cos delta cos omega sin lon)) * */ var alpha = Math.Asin( (Math.Cos(delta) * Math.Cos(omega) * Math.Cos(lat.Radians) + Math.Sin(delta) * Math.Sin(lat.Radians)) ); // Switch to A=0 be south var A = 2 * Math.PI - Math.Atan2( Math.Cos(delta) * Math.Sin(omega), Math.Sin(delta) * Math.Cos(lat.Radians) - Math.Cos(delta) * Math.Cos(omega) * Math.Sin(lat.Radians) ); if (A > 2 * Math.PI) { A -= 2 * Math.PI; } var sunPos = new GeoPolar2d(Angle.FromRadians(A), Angle.FromRadians(alpha)); return(sunPos); }
internal double GetTheta(GeoPolar2d p) { return(Utils.AngleBetween(p.Lat.Radians, p.Lon.Radians, thetaSun, phiSun)); }