光线追踪算法(计算机图形学)

1.Point3d类

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

namespace RayTracing
{
    public 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.Vector3d类

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

namespace RayTracing
{
    public 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 (double)(a.X * b.X + a.Y * b.Y + a.Z * b.Z);
        }
        public static Vector3d operator *(double a, Vector3d b)
        {
            return new Vector3d(a * b.X, a * b.Y, a * b.Z);
        }
        public static Vector3d operator *(Vector3d b, double a)
        {
            return new Vector3d(a * b.X, a * b.Y, a * 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 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 GetNorVec()
        {
            double d = Magnitude();
            return new Vector3d(X / d, Y / d, Z / d);
        }
    }
}

3.Ray类

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

namespace RayTracing
{
    public class Ray
    {
        private Point3d _origin;
        private Vector3d _direction;

        internal Point3d Origin { get => _origin; set => _origin = value; }
        internal Vector3d Direction { get => _direction; set => _direction = value; }
        public Ray()
        {
            this.Origin = new Point3d();
            this.Direction = new Vector3d();
        }
        public Ray(Point3d pd,Vector3d vt)
        {
            this.Origin = pd;
            this.Direction = vt;
        }
        
    }
}

4.GeometryObject类

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

namespace RayTracing
{
    public abstract class GeometryObject
    {
        private Material _mat = new Material();

        internal Material Mat { get => _mat; set => _mat = value; }
        public abstract bool isHit(Ray ray, ShadeRec rec);
        

        
    }
}

5.Sphere类

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

namespace RayTracing
{
    class Sphere:GeometryObject
    {
        private Point3d _o;
        private double radiu;

        public double Radiu { get => radiu; set => radiu = value; }
        internal Point3d O { get => _o; set => _o = value; }

        public Sphere()
        {
            this.O = new Point3d(0,0,0);
            this.Radiu = 1.0;
        }
        public Sphere(Point3d pd,double r)
        {
            this.O = pd;
            this.Radiu = r;
        }

        public override bool isHit(Ray ray, ShadeRec rec)
        {
            double t;
            Vector3d temp = ray.Origin - O;
            double a = ray.Direction * ray.Direction;
            double b = 2.0 * (ray.Direction * temp);
            double c = temp * temp - Radiu * 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);

                }
                rec.HitT = t;
                rec.HitPoint = ray.Origin + t * ray.Direction;
                Vector3d v = rec.HitPoint - O;
                rec.Normal = v.GetNorVec();
                rec.IsHit = true;
                rec.HitObjMat = Mat;
                return true;

            }
            else
            {
                
                rec.IsHit = false;
                return false;
            }
        }
    }
}

6.Material类

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

namespace RayTracing
{
    public class Material
    {
        private double _ks=0.8;
        private double _kd=0.5;
        private double _ns=50;
        private Scolor _scolor=new Scolor();

        public double Ks { get => _ks; set => _ks = value; }
        public double Kd { get => _kd; set => _kd = value; }
        public double Ns { get => _ns; set => _ns = value; }
        internal Scolor Scolor { get => _scolor; set => _scolor = value; }
        public Material()
        {
            this.Kd = 0;
            this.Ks = 0;
            this.Ns = 0;
            this.Scolor = new Scolor(0, 0, 0);

        }
        
        public Material(double kd,double ks,double ns,Scolor scolor)
        {
            this.Kd = kd;
            this.Ks = ks;
            this.Ns = ns;
            this.Scolor = scolor;
        }
    }
}

7.ShadeRec类

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

namespace RayTracing
{
    public class ShadeRec
    {
        private bool _isHit;
        private Point3d _hitPoint;
        private Vector3d _normal;
        private Material _hitObjMat;
        private double _hitT;

        public bool IsHit { get => _isHit; set => _isHit = value; }
        public double HitT { get => _hitT; set => _hitT = value; }
        internal Point3d HitPoint { get => _hitPoint; set => _hitPoint = value; }
        internal Vector3d Normal { get => _normal; set => _normal = value; }
        internal Material HitObjMat { get => _hitObjMat; set => _hitObjMat = value; }
    }
}

8.Scolor类

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

namespace RayTracing
{
    public 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 *(double k,Scolor sc)
        {
            return new Scolor(k * sc.R,k * sc.G, k * sc.B);
        }
        public static Scolor operator *(Scolor sc, double k)
        {
            return new Scolor(k * sc.R, k * sc.G, k * sc.B);
        }
        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);
        }
    }
}

9.LightResourse类

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

namespace RayTracing
{
    class LightResourse
    {
        private double _Ka;
        private Point3d _Location;
        private Scolor _LightColor;

        public double Ka { get => _Ka; set => _Ka = value; }
        internal Point3d Location { get => _Location; set => _Location = value; }
        public Scolor LightColor { get => _LightColor; set => _LightColor = value; }

        public LightResourse()
        {
            this.Ka= 0;
            this.Location = new Point3d();
            this.LightColor = new Scolor();
        }
        public LightResourse(double ka,Point3d Location,Scolor SC)
        {
            this.Ka = ka;
            this.Location = Location;
            this.LightColor = SC;
        }
    }
}

10.World类

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

namespace RayTracing
{
    public class World
    {
        private List<GeometryObject> _ListObj = new List<GeometryObject> ();
        public void AddGeoObj(GeometryObject Gto)
        {
            _ListObj.Add(Gto);
        }
        public void Build()
        {


            for (double i = 0; i < 14; i += 2)
            {
                Sphere sphere = new Sphere(new Point3d(i - 7 + 1, 0, -20), 1);
                Material mat = new Material(0.6, 0.8, 60, new Scolor(i / 14, 1 - i / 14, i / 14));
                sphere.Mat = mat;
                AddGeoObj(sphere);
            }


        }
     
        public ShadeRec HitAll(Ray ray)
        {
            ShadeRec srNearest= null;
            ShadeRec sr=new ShadeRec();
            double Mint = 1e8;
            for(int i = 0; i < _ListObj.Count; i++)
            {
               if(_ListObj[i].isHit(ray, sr) && (sr.HitT<Mint) )
                {
                    srNearest = sr;
                    Mint = sr.HitT;

                }
                
            }
            return srNearest;
        }

        public List<GeometryObject> ListObj { get => _ListObj; set => _ListObj = value; }
        
        
    }
}

11.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 RayTracing
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button2_Click(object sender, EventArgs e)
        {
            int hor = 2000;
            int ver = 1000;
            double resx = 4.0 / hor;
            double rexy = 2.0 / ver;

            //观察点
            Point3d eye = new Point3d(0, 0, 5);
            World world = new World();
            world.ListObj.Clear();
            world.Build();
            //光源
            LightResourse lightRes = new LightResourse(0.3, new Point3d(-1, 2, -1), new Scolor(1, 0, 0));
            //环境光源 
            LightResourse envirLight=new LightResourse(0.3,new Point3d(),new Scolor(1, 1, 1));          
            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);
                    ShadeRec SR = world.HitAll(ray);
                    
                    double LN,RV;
                    if (SR != null) {

                        Material Mat = SR.HitObjMat;
                        Vector3d Ln = (lightRes.Location - SR.HitPoint).GetNorVec();                       
                        //计算R:反射的单位矢量
                        Vector3d Rn = (2.0 * (SR.Normal * Ln) * SR.Normal - Ln).GetNorVec();
                        Vector3d v = (eye - SR.HitPoint).GetNorVec();

                        LN = Ln * SR.Normal;
                        RV = Rn * v;
                        if (LN < 0)
                        {
                            LN = 0;
                        }
                        if (RV < 0)
                        {
                            RV = 0;
                        }
                        Scolor sco1 = envirLight.LightColor * envirLight.Ka;
                        Scolor sco2 = lightRes.LightColor * Mat.Kd * LN;
                        Scolor sco3 = lightRes.LightColor * Mat.Ks * Math.Pow(RV, Mat.Ns);
                        //漫反射+环境光+phone
                        Scolor idiffuse = sco1 + sco2 + sco3;
                  
                        btm.SetPixel(i, j, idiffuse.Get255());
                    }                 
                    else
                    {
                        btm.SetPixel(i, j, Color.FromArgb(i/10,j/10,(i+j)/30));
                    }               

                }
            }
            pictureBox1.BackgroundImage = btm;
        }

        private void trackBar1_Scroll(object sender, EventArgs e)
        {

        }
    }
}

效果:

 

在加阴影的时候出现了BUG如图

 

小球只渲染出一半

原因:

 

 这行代码要写在for循环里面

效果:

 

 

 

 

 

posted on 2020-03-21 16:45  二进制dd  阅读(579)  评论(0编辑  收藏  举报

导航