示例#1
0
 public Polygon(Polygon s)
 {
     points = new List <int>(s.points);
     host   = s.host;
     DPen   = s.DPen.Clone() as Pen;
     Normal = new PointXYZ(s.Normal);
 }
示例#2
0
        //отражение

        /*
         * Направление отраженного луча определяется по закону:
         * отраженный луч = падающий луч -  2* нормаль к точке попадания луча на сторону  на скалярное произведение падающего луча и нормали
         * из презентации
         */
        public Ray Reflect(PointXYZ hit_point, PointXYZ normal)
        {
            //высчитываем направление отраженного луча
            PointXYZ reflect_dir = End - 2 * normal * PointXYZ.ScalarMul(End, normal);

            return(new Ray(hit_point, hit_point + reflect_dir));
        }
示例#3
0
 public void LineRotateRad(float rang, PointXYZ p1, PointXYZ p2)
 {
     p2          = new PointXYZ(p2.X - p1.X, p2.Y - p1.Y, p2.Z - p1.Z);
     p2          = PointXYZ.normal(p2);
     float[,] mt = GetMatrix();
     ApplyMatrix(RotateAroundLine(mt, p1, p2, rang));
 }
示例#4
0
        //модель освещения
        public PointXYZ Lumiance(PointXYZ hit_point, PointXYZ normal, PointXYZ material_color, float diffuse_coef)
        {
            PointXYZ direction = PointXYZ.normal(point_light - hit_point);// направление луча
            //если угол между нормалью и направлением луча больше 90 градусов,то диффузное  освещение равно 0
            PointXYZ diff = diffuse_coef * color_light * Math.Max(PointXYZ.ScalarMul(normal, direction), 0);

            return(new PointXYZ(diff.X * material_color.X, diff.Y * material_color.Y, diff.Z * material_color.Z));
        }
示例#5
0
 public Surface(Surface m)
 {
     reflection  = m.reflection;
     refraction  = m.refraction;
     environment = m.environment;
     ambient     = m.ambient;
     diffuse     = m.diffuse;
     Color       = new PointXYZ(m.Color);
 }
示例#6
0
        PointXYZ MakeCamera(Polygon side)
        {
            //нормаль стороны комнаты
            PointXYZ normal = Polygon.GetNormal(side);
            // центр стороны комнаты
            PointXYZ center = (ul + ur + dl + dr) / 4;

            return(center + normal * 11);
        }
示例#7
0
        public void ScaleAroundCenter(float xs, float ys, float zs)
        {
            float[,] pnts = GetMatrix();
            PointXYZ p = GetCenter();

            pnts = ApplyOffset(pnts, -p.X, -p.Y, -p.Z);
            pnts = ApplyScale(pnts, xs, ys, zs);
            pnts = ApplyOffset(pnts, p.X, p.Y, p.Z);
            ApplyMatrix(pnts);
        }
示例#8
0
        public static PointXYZ normal(PointXYZ p)
        {
            float z = (float)Math.Sqrt((float)(p.X * p.X + p.Y * p.Y + p.Z * p.Z));

            if (z == 0)
            {
                return(new PointXYZ(p));
            }
            return(new PointXYZ(p.X / z, p.Y / z, p.Z / z));
        }
示例#9
0
 public PointXYZ(PointXYZ p)
 {
     if (p == null)
     {
         return;
     }
     X = p.X;
     Y = p.Y;
     Z = p.Z;
 }
示例#10
0
        public static PointXYZ GetNormal(Polygon S)
        {
            if (S.points.Count() < 3)
            {
                return(new PointXYZ(0, 0, 0));
            }
            PointXYZ U      = S.GetPoint(1) - S.GetPoint(0);
            PointXYZ V      = S.GetPoint(S.points.Count - 1) - S.GetPoint(0);
            PointXYZ normal = U * V;

            return(PointXYZ.normal(normal));
        }
示例#11
0
 public Form1()
 {
     InitializeComponent();
     cameraPoint       = new PointXYZ();
     ul                = new PointXYZ();
     ur                = new PointXYZ();
     dl                = new PointXYZ();
     dr                = new PointXYZ();
     h                 = pictureBox1.Height;
     w                 = pictureBox1.Width;
     pictureBox1.Image = new Bitmap(w, h);
 }
示例#12
0
        private PointXYZ GetCenter()
        {
            PointXYZ res = new PointXYZ(0, 0, 0);

            foreach (PointXYZ p in Points)
            {
                res.X += p.X;
                res.Y += p.Y;
                res.Z += p.Z;
            }
            res.X /= Points.Count();
            res.Y /= Points.Count();
            res.Z /= Points.Count();
            return(res);
        }
示例#13
0
        Figure MakeRoom()
        {
            Figure room = Figure.CreateCube(10);

            ul = room.Polygons[0].GetPoint(0);
            ur = room.Polygons[0].GetPoint(1);
            dr = room.Polygons[0].GetPoint(2);
            dl = room.Polygons[0].GetPoint(3);

            room.SetPen(new Pen(Color.Gray));
            room.Polygons[0].DPen = new Pen(Color.Green);
            room.Polygons[1].DPen = new Pen(Color.Green);
            room.Polygons[2].DPen = new Pen(Color.GreenYellow);
            room.Polygons[3].DPen = new Pen(Color.GreenYellow);
            room.FigureSurface    = new Surface(0, 0, 0.05f, 0.7f);

            return(room);
        }
示例#14
0
        private static float[,] RotateAroundLine(float[,] transform_matrix, PointXYZ start, PointXYZ dir, float angle)
        {
            float cos_angle = (float)Math.Cos(angle);
            float sin_angle = (float)Math.Sin(angle);
            float val00     = dir.X * dir.X + cos_angle * (1 - dir.X * dir.X);
            float val01     = dir.X * (1 - cos_angle) * dir.Y + dir.Z * sin_angle;
            float val02     = dir.X * (1 - cos_angle) * dir.Z - dir.Y * sin_angle;
            float val10     = dir.X * (1 - cos_angle) * dir.Y - dir.Z * sin_angle;
            float val11     = dir.Y * dir.Y + cos_angle * (1 - dir.Y * dir.Y);
            float val12     = dir.Y * (1 - cos_angle) * dir.Z + dir.X * sin_angle;
            float val20     = dir.X * (1 - cos_angle) * dir.Z + dir.Y * sin_angle;
            float val21     = dir.Y * (1 - cos_angle) * dir.Z - dir.X * sin_angle;
            float val22     = dir.Z * dir.Z + cos_angle * (1 - dir.Z * dir.Z);

            float[,] rotateMatrix = new float[, ] {
                { val00, val01, val02, 0 }, { val10, val11, val12, 0 }, { val20, val21, val22, 0 }, { 0, 0, 0, 1 }
            };
            return(ApplyOffset(MultiplyMatrix(ApplyOffset(transform_matrix, -start.X, -start.Y, -start.Z), rotateMatrix), start.X, start.Y, start.Z));
        }
示例#15
0
        public void RotateArondRad(float rangle, string type)
        {
            float[,] mt = GetMatrix();
            PointXYZ center = GetCenter();

            switch (type)
            {
            case "CX":
                mt = ApplyOffset(mt, -center.X, -center.Y, -center.Z);
                mt = ApplyRotation_X(mt, rangle);
                mt = ApplyOffset(mt, center.X, center.Y, center.Z);
                break;

            case "CY":
                mt = ApplyOffset(mt, -center.X, -center.Y, -center.Z);
                mt = ApplyRotation_Y(mt, rangle);
                mt = ApplyOffset(mt, center.X, center.Y, center.Z);
                break;

            case "CZ":
                mt = ApplyOffset(mt, -center.X, -center.Y, -center.Z);
                mt = ApplyRotation_Z(mt, rangle);
                mt = ApplyOffset(mt, center.X, center.Y, center.Z);
                break;

            case "X":
                mt = ApplyRotation_X(mt, rangle);
                break;

            case "Y":
                mt = ApplyRotation_Y(mt, rangle);
                break;

            case "Z":
                mt = ApplyRotation_Z(mt, rangle);
                break;

            default:
                break;
            }
            ApplyMatrix(mt);
        }
示例#16
0
        public bool TriangleInter(Ray r, PointXYZ p0, PointXYZ p1, PointXYZ p2, out float intersect)
        {
            intersect = -1;
            PointXYZ edge1 = p1 - p0;
            PointXYZ edge2 = p2 - p0;
            PointXYZ h     = r.End * edge2;
            float    a     = PointXYZ.ScalarMul(edge1, h);

            if (a > -0.0001 && a < 0.0001)
            {
                return(false);       // Этот луч параллелен этому треугольнику.
            }
            float    f = 1.0f / a;
            PointXYZ s = r.Start - p0;
            float    u = f * PointXYZ.ScalarMul(s, h);

            if (u < 0 || u > 1)
            {
                return(false);
            }
            PointXYZ q = s * edge1;
            float    v = f * PointXYZ.ScalarMul(r.End, q);

            if (v < 0 || u + v > 1)
            {
                return(false);
            }
            // На этом этапе мы можем вычислить t, чтобы узнать, где находится точка пересечения на линии.
            float t = f * PointXYZ.ScalarMul(edge2, q);

            if (t > 0.0001)
            {
                intersect = t;
                return(true);
            }
            else      //Это означает, что есть пересечение линий, но не пересечение лучей.
            {
                return(false);
            }
        }
示例#17
0
        // пересечение луча с фигурой
        public virtual bool FigureIntersection(Ray r, out float intersect, out PointXYZ normal)
        {
            intersect = 0;
            normal    = null;
            Polygon side = null;

            foreach (Polygon figure_side in Polygons)
            {
                if (figure_side.points.Count == 3)
                {
                    if (TriangleInter(r, figure_side.GetPoint(0), figure_side.GetPoint(1), figure_side.GetPoint(2), out float t) && (intersect == 0 || t < intersect))
                    {
                        intersect = t;
                        side      = figure_side;
                    }
                }

                else if (figure_side.points.Count == 4)
                {
                    if (TriangleInter(r, figure_side.GetPoint(0), figure_side.GetPoint(1), figure_side.GetPoint(3), out float t) && (intersect == 0 || t < intersect))
                    {
                        intersect = t;
                        side      = figure_side;
                    }
                    else if (TriangleInter(r, figure_side.GetPoint(1), figure_side.GetPoint(2), figure_side.GetPoint(3), out t) && (intersect == 0 || t < intersect))
                    {
                        intersect = t;
                        side      = figure_side;
                    }
                }
            }
            if (intersect != 0)
            {
                normal = Polygon.GetNormal(side);
                FigureSurface.Color = new PointXYZ(side.DPen.Color.R / 255f, side.DPen.Color.G / 255f, side.DPen.Color.B / 255f);
                return(true);
            }
            return(false);
        }
示例#18
0
        //преломление
        //все вычисления взяты из презентации
        public Ray Refract(PointXYZ hit_point, PointXYZ normal, float refraction, float refract_coef)
        {
            Ray   res_ray = new Ray();
            float sclr    = PointXYZ.ScalarMul(normal, End);

            /*
             * Если луч падает,то он проходит прямо,не преломляясь
             */
            float n1n2div       = refraction / refract_coef;
            float theta_formula = 1 - n1n2div * n1n2div * (1 - sclr * sclr);

            if (theta_formula >= 0)
            {
                float cos_theta = (float)Math.Sqrt(theta_formula);
                res_ray.Start = new PointXYZ(hit_point);
                res_ray.End   = PointXYZ.normal(End * n1n2div - (cos_theta + n1n2div * sclr) * normal);
                return(res_ray);
            }
            else
            {
                return(null);
            }
        }
示例#19
0
        public PointXYZ RTAlgotithm(Ray r, int iter, float env)
        {
            if (iter <= 0)
            {
                return(new PointXYZ(0, 0, 0));
            }
            float intersectionRayFigure = 0;// позиция точки пересечения луча с фигурой на луче
            //нормаль стороны фигуры,с которой пересекся луч
            PointXYZ normal    = null;
            Surface  surface   = new Surface();
            PointXYZ res_color = new PointXYZ(0, 0, 0);

            bool isFigureRefrat = false;

            foreach (var f in figuresList)
            {
                if (f.FigureIntersection(r, out float intersect, out PointXYZ norm))
                {
                    if (intersect < intersectionRayFigure || intersectionRayFigure == 0)// нужна ближайшая фигура к точке наблюдения
                    {
                        intersectionRayFigure = intersect;
                        normal  = norm;
                        surface = new Surface(f.FigureSurface);
                    }
                }
            }

            if (intersectionRayFigure == 0)    //если не пересекается с фигурой
            {
                return(new PointXYZ(0, 0, 0)); //Луч уходит в свободное пространство .Возвращаем значение по умолчанию
            }
            //угол между направление луча и нормалью стороны острый
            //определяем из какой среды в какую
            //http://edu.glavsprav.ru/info/zakon-prelomleniya-sveta/
            if (PointXYZ.ScalarMul(r.End, normal) > 0)
            {
                normal        *= -1;
                isFigureRefrat = true;
            }


            //Точка пересечения луча с фигурой
            PointXYZ hit_point = r.Start + r.End * intersectionRayFigure;

            /*В точке пересечения луча с объектом строится три вторичных
             * луча – один в направлении отражения (1), второй – в направлении
             * источника света (2), третий в направлении преломления
             * прозрачной поверхностью (3).
             */

            //цвет коэффициент принятия фонового освещения
            PointXYZ lightk = raySource.color_light * surface.ambient;

            lightk.X   = (lightk.X * surface.Color.X);
            lightk.Y   = (lightk.Y * surface.Color.Y);
            lightk.Z   = (lightk.Z * surface.Color.Z);
            res_color += lightk;

            //диффузное освещение
            //если точка пересечения луча с объектом видна из источника света
            float raydist = (raySource.point_light - hit_point).Distance(); //координаты источника света луча
            Ray   tmp_r   = new Ray(hit_point, raySource.point_light);

            foreach (Figure fig in figuresList)
            {
                if (fig.FigureIntersection(tmp_r, out float t, out PointXYZ n))
                {
                    if (t < raydist || t > 0.0001)
                    {
                        res_color += raySource.Lumiance(hit_point, normal, surface.Color, surface.diffuse);
                    }
                }
            }



            /*Для отраженного луча
             * проверяется возможность
             * пересечения с другими
             * объектами сцены.
             *
             *  Если пересечений нет, то
             *  интенсивность и цвет
             *  отраженного луча равна
             *  интенсивности и цвету фона.
             *
             *  Если пересечение есть, то в
             *  новой точке снова строится
             *  три типа лучей – теневые,
             *  отражения и преломления.
             */
            if (surface.reflection > 0)
            {
                Ray refray = r.Reflect(hit_point, normal);
                res_color += surface.reflection * RTAlgotithm(refray, iter - 1, env);
            }


            //расчет коэфициентов преломления
            if (surface.refraction > 0)
            {
                //взависимости от того,из какой среды в какую,будет меняться коэффициент приломления
                float refractk;
                if (isFigureRefrat)
                {
                    refractk = surface.environment;
                }
                else
                {
                    refractk = 1 / surface.environment;
                }

                Ray refracted_ray = r.Refract(hit_point, normal, surface.refraction, refractk);//создаем приломленный луч

                /*
                 * Как и в предыдущем случае,
                 * проверяется пересечение вновь
                 * построенного луча с объектами,
                 * и, если они есть, в новой точке
                 * строятся три луча, если нет – используется интенсивность и
                 * цвет фона.
                 */
                if (refracted_ray != null)
                {
                    res_color += surface.refraction * RTAlgotithm(refracted_ray, iter - 1, surface.environment);
                }
            }
            return(res_color);
        }
示例#20
0
 public Ray(Ray r)
 {
     Start = r.Start;
     End   = r.End;
 }
示例#21
0
 public void CalculateSideNormal()
 {
     Normal = GetNormal(this);
 }
示例#22
0
 public static float ScalarMul(PointXYZ p1, PointXYZ p2)
 {
     return(p1.X * p2.X + p1.Y * p2.Y + p1.Z * p2.Z);
 }
示例#23
0
        private void button1_Click(object sender, EventArgs e)
        {
            Figure room = MakeRoom();

            cameraPoint = MakeCamera(room.Polygons[0]);
            figuresList.Add(room);

            raySource = new Lamp(new PointXYZ(0f, 2f, 4.9f), new PointXYZ(1f, 1f, 1f));

            AddBigCube();
            AddLittleCube();

            /*
             * Учитывая разницу между размером комнаты и экранным отображение приводим координаты к пикселям
             */
            pixels       = new PointXYZ[w, h];
            pixels_color = new Color[w, h];
            PointXYZ step_up   = (ur - ul) / (w - 1); //отношение ширины комнаты к ширине экрана
            PointXYZ step_down = (dr - dl) / (w - 1); //отношение высоты комнаты к высоте экрана
            PointXYZ up        = new PointXYZ(ul);
            PointXYZ down      = new PointXYZ(dl);

            for (int i = 0; i < w; ++i)
            {
                PointXYZ step_y = (up - down) / (h - 1);
                PointXYZ d      = new PointXYZ(down);
                for (int j = 0; j < h; ++j)
                {
                    pixels[i, j] = d;
                    d           += step_y;
                }
                up   += step_up;
                down += step_down;
            }

            /*
             * Количество первичных лучей также известно – это общее
             * количество пикселей видового окна
             */
            for (int i = 0; i < w; ++i)
            {
                for (int j = 0; j < h; ++j)
                {
                    Ray r = new Ray(cameraPoint, pixels[i, j]);
                    r.Start = new PointXYZ(pixels[i, j]);
                    PointXYZ color = RTAlgotithm(r, 10, 1);//луч,кол-во итераций,коэфф
                    if (color.X > 1.0f || color.Y > 1.0f || color.Z > 1.0f)
                    {
                        color = PointXYZ.normal(color);
                    }
                    pixels_color[i, j] = Color.FromArgb((int)(255 * color.X), (int)(255 * color.Y), (int)(255 * color.Z));
                }
            }


            for (int i = 0; i < w; ++i)
            {
                for (int j = 0; j < h; ++j)
                {
                    (pictureBox1.Image as Bitmap).SetPixel(i, j, pixels_color[i, j]);
                }
                pictureBox1.Invalidate();
            }
        }
示例#24
0
 public Ray(PointXYZ st, PointXYZ end)
 {
     Start = new PointXYZ(st);
     End   = PointXYZ.normal(end - st);
 }
示例#25
0
 public Lamp(PointXYZ p, PointXYZ c)
 {
     point_light = new PointXYZ(p);
     color_light = new PointXYZ(c);
 }
示例#26
0
 public void LineRotate(float ang, PointXYZ p1, PointXYZ p2)
 {
     ang = ang * (float)Math.PI / 180;
     LineRotateRad(ang, p1, p2);
 }