Пример #1
0
        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);
        }
Пример #2
0
        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));
        }
Пример #3
0
        /// <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);
        }
Пример #4
0
        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);
        }
Пример #5
0
        // 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)));
        }
Пример #6
0
            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);
            }
Пример #7
0
        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);
        }
Пример #8
0
        /// <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);
        }
Пример #9
0
        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);
        }
Пример #10
0
        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);
        }
Пример #11
0
        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);
        }
Пример #12
0
        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);
        }
Пример #13
0
        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);
        }
Пример #14
0
 internal double GetTheta(GeoPolar2d p)
 {
     return(Utils.AngleBetween(p.Lat.Radians, p.Lon.Radians, thetaSun, phiSun));
 }