光线追踪算法

1.三维点 Point3D类

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace WindowsFormsApp1
{
    class Point3d
    {
        private double _x;
        private double _y;
        private double _z;
        
        public double X { get => _x; set => _x = value; }
        public double Y { get => _y; set => _y = value; }
        public double Z { get => _z; set => _z = value; }

        public Point3d(){
            this.X=0;
            this.Y = 0;
            this.Z = 0;
        }
        public Point3d(double x,double y,double z)
        {
            this.X = x;
            this.Y = y;
            this.Z = z;
        }
        public static Vector3D operator -(Point3d a,Point3d b)
        {
            return new Vector3D(a.X - b.X, a.Y - b.Y, a.Z - b.Z);
        }
        public static Vector3D operator -(Point3d a,Vector3D b)
        {
            return new Vector3D(a.X - b.X, a.Y - b.Y, a.Z - b.Z);
        }
        public static Vector3D operator -(Vector3D a, Point3d b)
        {
            return new Vector3D(a.X - b.X, a.Y - b.Y, a.Z - b.Z);
        }
    }
}

2.Ray光线类

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace WindowsFormsApp1
{
    class Ray
    {
        private Point3d _origin;
        private Vector3D _direction;
       
        public Ray()
        {
            this.Origin = new Point3d();
            this.Direction = new Vector3D();
        }
        public Ray(Point3d origin,Vector3D direction)
        {
            this.Origin = origin;
            this.Direction = direction;
        }

        internal Point3d Origin { get => _origin; set => _origin = value; }
        internal Vector3D Direction { get => _direction; set => _direction = value; }
        public Point3d GetRayAtSp(double t)
        {
            return Origin+ t * Direction;
        }
        public bool isHit(Sphere sphere,out Point3d phit,out Vector3D normal)
        {
            double t;
            Vector3D co = Origin-sphere.Center;
            double a = Direction * Direction;
            double b = 2.0 * (Direction * co);
            double c = co * co - sphere.Radiu * sphere.Radiu;
            double delta = b * b - 4 * a * c;
            if (delta >= 0)
            {
                t=(-b - Math.Sqrt(delta)) / (2 * a);
                if (t < 0)
                {
                    t = (-b + Math.Sqrt(delta)) / (2 * a);
                }
                phit = GetRayAtSp(t);
                Vector3D v = phit - sphere.Center;
                normal = v.GetNormalizeVector();
                return true;
            }
            else
            {
                phit = new Point3d();
                normal = new Vector3D();
                return false;
            }
           
        }
        /*public  SColor ColorRS(Ray r)
        {
            bool k;
            k = r.isHit(new Sphere(new Point3d(0, 0, -1), 0.5),out new Point3d(),out new Vector3D());
            if (k)
            {
                return new SColor(1, 0, 0);
            }
            else {
                Vector3D UnitVec = r.Direction.GetNormalizeVector();
                double t = 0.5 * (UnitVec.Y + 1.0);
                return new SColor((1.0-t)+t*0.5,(1.0-t)+t*0.7,(1.0-t)+t*1);
            }
            /*具体算法 blended_value = (1-t)*start_value + 
            t* end_value,函数里 start_value = Color3D(1.0, 1.0, 1.0), end_value =
             Color3D(0.5, 0.7, 1.0)*/
        }
}

3. 自定义颜色类 Scolor

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace WindowsFormsApp1
{
    class SColor
    {
        private double _r;
        private double _g;
        private double _b;
        public double R
        {
            get
            {
                return _r;
            }
            set
            {
                _r = value;
                if (_r < 0.0)
                {
                    _r = 0.0;
                }
                if (_r > 1.0)
                {
                    _r = 1.0;
                }
            }
        }
        public double G
        {
            get
            {
                return _g;
            }
            set
            {
                _g = value;
                if (_g < 0.0)
                {
                    _g = 0.0;
                }
                if (_g > 1.0)
                {
                    _g = 1.0;
                }
            }
        }
        public double B
        {
            get
            {
                return _b;
            }
            set
            {
                _b = value;
                if (_b < 0.0)
                {
                    _b = 0.0;
                }
                if (_b > 1.0)
                {
                    _b = 1.0;
                }
            }
        }
        public SColor()
        {
            this.R = 0.0;
            this.G = 0.0;
            this.B = 0.0;
        }
        public SColor(double r,double g,double b)
        {
            this.R = r;
            this.G = g;
            this.B = b;
        }
        public static SColor operator *(SColor sc,double k)
        {
            return new SColor(sc.R * k, sc.G * k, sc.B * k);
        }
        public static SColor operator *(double k,SColor sc)
        {
            return new SColor(sc.R * k, sc.G * k, sc.B * k);
        }
        public Color Get255()
        {
            return Color.FromArgb((int) (R * 255), (int) (G * 255), (int) (B * 255));
        }
        public static SColor operator +(SColor s1,SColor s2)
        {
            return new SColor(s1.R + s2.R, s1.G + s2.G, s1.B + s2.B);
        }
    }
}

4.球类Sphere

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace WindowsFormsApp1
{
    class Sphere
    {
        private Point3d _center;
        private double _radiu;

        public double Radiu { get => _radiu; set => _radiu = value; }
        internal Point3d Center { get => _center; set => _center = value; }
        public Sphere()
        {
            this.Center = new Point3d(0, 0,0);
            this.Radiu = 1;
        }
        public Sphere(Point3d center,double radiu)
        {
            this.Center = center;
            this.Radiu = radiu;
        }
    }
}

  5.向量类Vector3D

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace WindowsFormsApp1
{
    class Vector3D
    {
        
        private double _x;
        private double _y;
        private double _z;

        public double X { get => _x; set => _x = value; }
        public double Y { get => _y; set => _y = value; }
        public double Z { get => _z; set => _z = value; }

        public Vector3D()
        {
            this.X = 0;
            this.Y = 0;
            this.Z = 0;
        }
        public Vector3D(double x, double y, double z)
        {
            this.X = x;
            this.Y = y;
            this.Z = z;
        }
        public static double operator *(Vector3D a,Vector3D b)
        {
        return a.X * b.X + a.Y * b.Y + a.Z * b.Z;
        }
        public static Vector3D operator *(double number,Vector3D vec)
        {
            return new Vector3D(number * vec.X, number * vec.Y, number * vec.Z);
        }
        public static Vector3D operator *(Vector3D vec,double number)
        {
            return new Vector3D(number * vec.X, number * vec.Y, number * vec.Z);
        }
        public static Vector3D operator +(Vector3D vec1,Vector3D vec2)
        {
            return new Vector3D(vec1.X + vec2.X, vec1.Y + vec2.Y, vec1.Z + vec2.Z);
        }
        public static Point3d  operator +(Point3d a,Vector3D b)
        {
            return new Point3d(a.X + b.X, a.Y + b.Y, a.Z + b.Z);
        }
        public static Vector3D operator -(Vector3D vec1, Vector3D vec2)
        {
            return new Vector3D(vec1.X - vec2.X, vec1.Y - vec2.Y, vec1.Z - vec2.Z);
        }
        public double Magnitude()
        {
            return Math.Sqrt(X * X + Y * Y + Z * Z);
        }
        public void Normalize()
        {
            double d = Magnitude();
            X = X / d;
            Y = Y / d;
            Z = Z / d;
        }
        public Vector3D GetNormalizeVector()
        {
            double d = Magnitude();
            return new Vector3D(X / d, Y / d, Z / d);
        }
    }
}

  FORM1:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsFormsApp1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        
        private void button2_Click(object sender, EventArgs e)
        {
            /*Ray primaryRay = new Ray();
            primaryRay.Origin = new Point3d(10, 20, 20);
            primaryRay.Direction = new Vector3D(0, 0, -1);
            
            Ray shadowray = new Ray(new Point3d(10, 20, 20), new Vector3D(0, 0, -1));

            Point3d hitpoint = new Point3d(10, 20, 20);
            Vector3D dir = new Vector3D(0, 0, -1);
            Ray reflectray = new Ray(hitpoint, dir);
            double d = primaryRay.Direction * dir;
            Point3d a = new Point3d(2, 1, 1);
            Vector3D b = new Vector3D(1, 1, 1);
            Vector3D c = a - b;*/
            int hor = 2000;
            int ver = 1000;
            double resx = 4.0/hor;
            double rexy= 2.0/ ver;
            /*double mag = ray1.Direction.Magnitude();
            Vector3D normalvec = ray1.Direction.GetNormalizeVector();*/

            //观察点
            Point3d eye = new Point3d(0, 0, 0);
            //光源
            Point3d light = new Point3d(-1, 2, -1);
            SColor Id = new SColor(1, 1, 1);
            double kd = 0.8;
            //环境光源
            SColor Ia = new SColor(1, 1, 1);
            double ka = 0.2;

            //球体
            Sphere sp = new Sphere(new Point3d(0, 0, -2), 0.8);
            Bitmap btm = new Bitmap(hor, ver);
           

            for (int i = 0; i < hor; i++)
            {
                for(int j = 0; j < ver; j++)
                {
                    //成像平面上的点
                    Point3d p = new Point3d(-2 + i * resx, 1 - j * rexy, -1);
                    Vector3D dir =p-eye;
                    Ray ray = new Ray(eye, dir);

                    Point3d phit;
                    Vector3D normal;

                    bool isHit = ray.isHit(sp, out phit, out normal);                 
                    
                    Vector3D L = light - phit;
                    Vector3D Ln= L.GetNormalizeVector();
                    //漫反射
                    SColor idiffuse = Id * kd * (Ln * normal) + Ia * ka;
                    if (isHit)
                    {
                        
                        btm.SetPixel(i, j, idiffuse.Get255());
                    }
                    else
                    {
                        btm.SetPixel(i, j, Color.Black);
                    }
                    pictureBox1.BackgroundImage = btm;
                    
                }
            }

            /*Ray ray1 = new Ray(new Point3d(1, -2, -1), new Vector3D(1, 2, 4));
            Sphere sp = new Sphere(new Point3d(3, 0, 5), 3.0);
            bool isHit=ray1.isHit(sp);*/

            /*int nx = 200;
            int ny = 100;
            Bitmap bitmap= new Bitmap(nx, ny);
            Point3d lowerLeftConor = new Point3d(-2, 1, 1);
            Vector3D horizontal = new Vector3D(4, 0, 0);
            Vector3D vertical = new Vector3D(0, 2, 0);
            Point3d origin = new Point3d(0, 0, 0);
            for(int i = 0; i < nx; i++)
            {
                for(int j = ny - 1 ; j >= 0; j--)
                {
                    double u = i / nx;
                    double v = j / ny;
                    Ray r = new Ray(origin, lowerLeftConor + u * horizontal + v * vertical);
                    SColor clr = r.ColorRS(r);
                    int ir= (int)(255.99 * clr.R);
                    int ig = (int)(255.99 * clr.G);
                    int ib = (int)(255.99 * clr.B);
                    bitmap.SetPixel(i, j, Color.FromArgb(ir, ig, ib));
                    pictureBox1.BackgroundImage = bitmap;
                    pictureBox1.BackgroundImageLayout = ImageLayout.Stretch;

                }
            }
            */

        }
    }
}

  效果

猜你喜欢

转载自www.cnblogs.com/jcahsy/p/12540089.html