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 voidForm1_Load(object sender, EventArgs e){}
private voidbutton1_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;// 求tdouble 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 doubleMagnitude(){return Math.Sqrt(X * X + Y * Y + Z * Z);}/// <summary>/// 向量单位化,本向量被改变/// </summary>
public voidNormalize(){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;}}