// вычисление локальной модели освещения public Point3D shade(Point3D hit_point, Point3D normal, Point3D color_obj, float diffuse_coef) { Point3D dir = point_light - hit_point; dir = Point3D.norm(dir); // направление луча из источника света в точку удара Point3D diff = diffuse_coef * color_light * Math.Max(Point3D.scalar(normal, dir), 0); return(new Point3D(diff.x * color_obj.x, diff.y * color_obj.y, diff.z * color_obj.z)); }
// преломление public Ray refract(Point3D hit_point, Point3D normal, float eta) { Ray res_ray = new Ray(); float sclr = Point3D.scalar(normal, direction); float k = 1 - eta * eta * (1 - sclr * sclr); if (k >= 0) { float cos_theta = (float)Math.Sqrt(k); res_ray.start = new Point3D(hit_point); res_ray.direction = Point3D.norm(eta * direction - (cos_theta + eta * sclr) * normal); return(res_ray); } else { return(null); } }
public bool ray_intersects_triangle(Ray r, Point3D p0, Point3D p1, Point3D p2, out float intersect) { intersect = -1; Point3D edge1 = p1 - p0; Point3D edge2 = p2 - p0; Point3D h = r.direction * edge2; float a = Point3D.scalar(edge1, h); if (a > -EPS && a < EPS) { return(false); // This ray is parallel to this triangle. } float f = 1.0f / a; Point3D s = r.start - p0; float u = f * Point3D.scalar(s, h); if (u < 0 || u > 1) { return(false); } Point3D q = s * edge1; float v = f * Point3D.scalar(r.direction, q); if (v < 0 || u + v > 1) { return(false); } // At this stage we can compute t to find out where the intersection point is on the line. float t = f * Point3D.scalar(edge2, q); if (t > EPS) { intersect = t; return(true); } else // This means that there is a line intersection but not a ray intersection. { return(false); } }
public static bool ray_sphere_intersection(Ray r, Point3D sphere_pos, float sphere_rad, out float t) { Point3D k = r.start - sphere_pos; float b = Point3D.scalar(k, r.direction); float c = Point3D.scalar(k, k) - sphere_rad * sphere_rad; float d = b * b - c; t = 0; if (d >= 0) { float sqrtd = (float)Math.Sqrt(d); float t1 = -b + sqrtd; float t2 = -b - sqrtd; float min_t = Math.Min(t1, t2); float max_t = Math.Max(t1, t2); t = (min_t > EPS) ? min_t : max_t; return(t > EPS); } return(false); }
// отражение public Ray reflect(Point3D hit_point, Point3D normal) { Point3D reflect_dir = direction - 2 * normal * Point3D.scalar(direction, normal); return(new Ray(hit_point, hit_point + reflect_dir)); }
public Point3D RayTrace(Ray r, int iter, float env) { if (iter <= 0) { return(new Point3D(0, 0, 0)); } float t = 0; // позиция точки пересечения луча с фигурой на луче Point3D normal = null; Material m = new Material(); Point3D res_color = new Point3D(0, 0, 0); bool refract_out_of_figure = false; // луч преломления выходит из объекта? foreach (Figure fig in scene) { if (fig.figure_intersection(r, out float intersect, out Point3D n)) { if (intersect < t || t == 0) // нужна ближайшая фигура к точке наблюдения { t = intersect; normal = n; m = new Material(fig.figure_material); } } } if (t == 0) { return(new Point3D(0, 0, 0)); } //если угол между нормалью к поверхности объекта и направлением луча положительный, => угол острый, => луч выходит из объекта в среду if (Point3D.scalar(r.direction, normal) > 0) { normal *= -1; refract_out_of_figure = true; } Point3D hit_point = r.start + r.direction * t; foreach (Light l in lights) { Point3D amb = l.color_light * m.ambient; amb.x = (amb.x * m.clr.x); amb.y = (amb.y * m.clr.y); amb.z = (amb.z * m.clr.z); res_color += amb; // диффузное освещение if (is_visible(l.point_light, hit_point)) { res_color += l.shade(hit_point, normal, m.clr, m.diffuse); } } if (m.reflection > 0) { Ray reflected_ray = r.reflect(hit_point, normal); res_color += m.reflection * RayTrace(reflected_ray, iter - 1, env); } if (m.refraction > 0) { float eta; //коэффициент преломления if (refract_out_of_figure) //луч выходит в среду { eta = m.environment; } else { eta = 1 / m.environment; } Ray refracted_ray = r.refract(hit_point, normal, eta); if (refracted_ray != null) { res_color += m.refraction * RayTrace(refracted_ray, iter - 1, m.environment); } } return(res_color); }