c# 画球

主代码

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 Form1_Load(object sender, EventArgs e)
        {
        }

        private void button1_Click(object sender, EventArgs e)
        {
            // 眼睛
            Camera camera = new Camera();
            camera.loc = new Point3D(0, 0, 10);

            // 成像平面
            ViewPlain vp = new ViewPlain();
            vp.topLeftLoc = new Point3D(-4, 3, 0);
            vp.w = 8;
            vp.h = 6;
            vp.wRes = 800;
            vp.hRes = 600;

            // 位图
            Bitmap bmp = new Bitmap(vp.wRes, vp.hRes);

            // 求每一小格的偏移量
            double wStep = vp.w / vp.wRes;
            double hStep = vp.h / vp.hRes;

            // 球体
            Sphere sphere = new Sphere();
            sphere.Center = new Point3D(0, 0, -10);
            sphere.Radius = 3;

            // 在成像平面成像
            for (int i = 0; i < vp.wRes; i++)
            {
                for (int j = 0; j < vp.hRes; j++)
                {
                    Point3D pLoc = new Point3D(vp.topLeftLoc.X + wStep * i,
                        vp.topLeftLoc.Y - hStep * j, 0);

                    Ray ray = new Ray(camera.loc, pLoc - camera.loc);
                    ray.Dir.Normalize();

                    HitRecord hitRecord = ray.isHit(sphere);

                    // 光源的位置
                    Point3D lightLoc = new Point3D(-10, 10, 0);

                    // 光源的颜色
                    Color lightColor = Color.FromArgb(0, 255, 0);

                    if (hitRecord.isHit)
                    {
                        // 光源到交点的向量
                        Vector3D vLight = lightLoc - hitRecord.hitPoint;
                        vLight.Normalize();

                        // 算夹角
                        double d = vLight * hitRecord.normal;

                        if (d < 0)
                        {
                            d = 0;
                        }

                        // 算颜色
                        Color color = Color.FromArgb((int)(d * lightColor.R), (int)(d * lightColor.G), (int)(d * lightColor.B));

                        bmp.SetPixel(i, j, color);
                    }
                    else
                    {
                        bmp.SetPixel(i, j, Color.Gray);
                    }
                }
            }

            pictureBox1.BackgroundImage = bmp;
        }
    }
}




相关类

HitRecord

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

namespace RayTracing
{
    class HitRecord
    {
        public bool isHit;
        public double t;
        public Point3D hitPoint;
        public Vector3D normal;
    }
}

Point3D

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

namespace RayTracing
{
    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()
        {
            x = 0;
            y = 0;
            z = 0;
        }

        public Point3D(double x, double y, double z)
        {
            this.x = x;
            this.y = y;
            this.z = z;
        }

        public Point3D(double a)
        {
            x = a;
            y = a;
            z = a;
        }

        /// <summary>
        /// 点 + 向量
        /// </summary>
        /// <param name="p"></param>
        /// <param name="v"></param>
        /// <returns></returns>
        public static Point3D operator +(Point3D p, Vector3D v)
        {
            return new Point3D(p.X + v.X, p.Y + v.Y, p.Z + v.Z);
        }

        /// <summary>
        /// 两个点之间的减法,得到向量
        /// </summary>
        /// <param name="p1"></param>
        /// <param name="p2"></param>
        /// <returns></returns>
        public static Vector3D operator -(Point3D p1, Point3D p2)
        {
            return new Vector3D(p1.X - p2.X, p1.Y - p2.Y, p1.Z - p2.Z);
        }
    }
}

Ray

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

namespace RayTracing
{
    /// <summary>
    /// 射线
    /// </summary>
    class Ray
    {
        // 字段
        private Point3D org;
        private Vector3D dir;

        // 属性
        internal Point3D Org { get => org; set => org = value; }
        internal Vector3D Dir { get => dir; set => dir = value; }

        // 构造函数
        public Ray()
        {
            Org = new Point3D();
            Dir = new Vector3D();
        }

        public Ray(Point3D org, Vector3D dir)
        {
            this.Org = org;
            this.Dir = dir;
        }

        /// <summary>
        /// 判断是否与球体相交
        /// </summary>
        /// <param name="sphere"></param>
        /// <returns></returns>
        public HitRecord isHit(Sphere sphere)
        {
            // 计算delta
            Vector3D oc = Org - sphere.Center;
            double a = dir * dir;
            double b = 2.0 * (dir * oc);
            double c = oc * oc - sphere.Radius * sphere.Radius;
            double delta = b * b - 4.0 * a * c;

            HitRecord hitRecord = new HitRecord();
            
            // 有交点
            if (delta > 0)
            {
                hitRecord.isHit = true;

                // 求t
                double t = (-b - Math.Sqrt(delta)) / (2.0 * a);

                if (t < 0)
                {
                    t = (-b + Math.Sqrt(delta)) / (2.0 * a);
                }

                hitRecord.t = t;

                // 求交点
                hitRecord.hitPoint = GetPoint(t);
                // 求法线
                hitRecord.normal = sphere.GetNormalVector(hitRecord.hitPoint);
                hitRecord.normal.Normalize();
            } 
            else
            {
                hitRecord.isHit = false;
            }

            return hitRecord;
        }

        /// <summary>
        /// 依据参数t的值,得到射线上某点
        /// </summary>
        /// <param name="t"></param>
        /// <returns></returns>
        public Point3D GetPoint(double t)
        {
            return org + t * dir;
        }


    }
}

Sphere

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

namespace RayTracing
{
    class Sphere
    {
        private Point3D center;
        private double radius;

        public double Radius { get => radius; set => radius = value; }
        internal Point3D Center { get => center; set => center = value; }

        public Sphere(double radius, Point3D center)
        {
            Radius = radius;
            Center = center;
        }
        public Sphere()
        {
            center = new Point3D();
            radius = 1.0;
        }

        /// <summary>
        /// 获得球面某点的法线向量
        /// </summary>
        /// <param name="p"></param>
        /// <returns></returns>
        public Vector3D GetNormalVector(Point3D p)
        {
            Vector3D v = p - Center;

            // 单位化,简化后续计算
            v.Normalize();

            return v;
        }
    }
}

Vector

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

namespace RayTracing
{
    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()
        {
            x = 1;
            y = 0;
            z = 0;
        }

        public Vector3D(double x, double y, double z)
        {
            this.x = x;
            this.y = y;
            this.z = z;
        }

        public Vector3D(double a)
        {
            x = a;
            y = a;
            z = a;
        }

        /// <summary>
        /// 点乘
        /// </summary>
        /// <param name="v1"></param>
        /// <param name="v2"></param>
        /// <returns></returns>
        public static Double operator*(Vector3D v1, Vector3D v2)
        {
            return v1.X * v2.X + v1.Y * v2.Y + v1.Z * v2.Z;
        }

        /// <summary>
        /// 数*向量
        /// </summary>
        /// <param name="d"></param>
        /// <param name="v"></param>
        /// <returns></returns>
        public static Vector3D operator*(double d, Vector3D v)
        {
            return new Vector3D(d * v.X, d * v.Y, d * v.Z);
        }

        /// <summary>
        /// 向量*数
        /// </summary>
        /// <param name="v"></param>
        /// <param name="d"></param>
        /// <returns></returns>
        public static Vector3D operator*(Vector3D v, double d)
        {
            return new Vector3D(d * v.X, d * v.Y, d * v.Z);
        }

        /// <summary>
        /// 向量加法
        /// </summary>
        /// <param name="v1"></param>
        /// <param name="v2"></param>
        /// <returns></returns>
        public static Vector3D operator +(Vector3D v1, Vector3D v2)
        {
            return new Vector3D(v1.X + v2.X, v1.Y + v2.Y, v1.Z + v2.Z);
        }

        /// <summary>
        /// 向量减法
        /// </summary>
        /// <param name="v1"></param>
        /// <param name="v2"></param>
        /// <returns></returns>
        public static Vector3D operator -(Vector3D v1, Vector3D v2)
        {
            return new Vector3D(v1.X - v2.X, v1.Y - v2.Y, v1.Z - v2.Z);
        }

        /// <summary>
        /// 向量的模
        /// </summary>
        /// <returns></returns> 模
        public double Magnitude()
        {
            return Math.Sqrt(X * X + Y * Y + Z * Z);
        }

        /// <summary>
        /// 向量单位化,本向量被改变
        /// </summary>
        public void Normalize()
        {
            double d = Magnitude();
            X = X / d;
            Y = Y / d;
            Z = Z / d;
        }

        /// <summary>
        /// 返回本向量的归一化向量,本向量不变
        /// </summary>
        /// <returns></returns> 单位化后的向量
        public Vector3D GetNormalizeVector()
        {
            double d = Magnitude();
            return new Vector3D(X/d, Y/d, Z/d);
        }
    }
}

viewPlain

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

namespace RayTracing
{
    class ViewPlain
    {
       public Point3D topLeftLoc;
       public double w;
       public double h;
       public int wRes;
       public int hRes;
    }
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值