public override void trace(Ray r) { double v = r.dir * norm; if (r.is_outside && v > 0 || !r.is_outside && v < 0) { return; } double dist = ((p0 - r.pos) * norm) / v; if (dist > 0 && dist < r.hit_dist) { vect3d hit_pos = r.pos + r.dir * dist; // find barycentric coordinates; double b0 = ((p1 - hit_pos) % (p2 - hit_pos)) * N; double b1 = ((p2 - hit_pos) % (p0 - hit_pos)) * N; double b2 = 1 - b0 - b1; if (b0 >= 0 && b1 >= 0 && b2 >= 0) { r.hit_dist = dist; r.hit_pos = hit_pos; r.hit_tex_coord = t0 * b0 + t1 * b1 + t2 * b2; r.hit_norm = n0 * b0 + n1 * b1 + n2 * b2; r.hit_norm.normalize(); r.hit_object = this; } } }
public static bool rayTriangleIntersect(vect3d ray_pos, vect3d ray_dir, vect3d v0, vect3d v1, vect3d v2, out double dist) { vect3d u = v1 - v0; vect3d v = v2 - v0; vect3d n = u % v; // normal dist = -((ray_pos - v0) * n) / (ray_dir * n); // distance to plane vect3d pos = ray_pos + ray_dir * dist; // point in plane of triangle vect3d w = pos - v0; double uv = u * v; double wv = w * v; double vv = v * v; double wu = w * u; double uu = u * u; double denom = uv * uv - uu * vv; double s = (uv * wv - vv * wu) / denom; double t = (uv * wu - uu * wv) / denom; if (s >= 0 && t >= 0 && s + t <= 1) { return(true); } else { return(false); } }
protected void lightDirectPointSpecNoShadow(Ray r, double specular_coeff, ref vect3d diff_accum, ref vect3d spec_accum) { Ray shadow_ray = new Ray(); shadow_ray.pos = r.hit_pos; foreach (var l in r.scene.lights) { vect3d dir = l.pos - r.hit_pos; double dist2 = 1.0 / dir.length2(); dir *= Math.Sqrt(dist2); // diffuse double incidence_dif = (dir * r.hit_norm); if (incidence_dif > 0) { diff_accum += l.color * incidence_dif * dist2; } // specular highlight vect3d dir_r = r.hit_norm * ((dir * r.hit_norm) * 2) - dir; double incidence_spec = (dir_r * r.hit_norm); if (incidence_spec > 0) { spec_accum += l.color * Math.Pow(incidence_spec, specular_coeff) * dist2; } } }
public Sphere(vect3d pos, double r, Shader shader) { this.shader = shader; this.radius = r; this.radius2 = r * r; this.pos = pos; }
public override void trace(Ray r) { vect3d dst = r.pos - this.pos; double B = dst * r.dir; double C = dst.length2() - this.radius2; double D = B * B - C; if (D > 0) { double dist; double flip_norm = 1; if (r.is_outside) { dist = -B - Math.Sqrt(D); } else { dist = -B + Math.Sqrt(D); flip_norm = -1; } if (dist > 0 && dist < r.hit_dist) { r.hit_dist = dist; r.hit_pos = r.pos + r.dir * dist; r.hit_norm = (r.hit_pos - this.pos) * flip_norm; r.hit_norm.normalize(); r.hit_tex_coord = r.hit_norm; r.hit_object = this; } } }
public override void colorize(Ray r) { vect3d diff_accum = new vect3d(0, 0, 0); vect3d spec_accum = new vect3d(0, 0, 0); lightDirectPointSpec(r, specular_coeff, ref diff_accum, ref spec_accum); r.color = diff_accum.times(diffuse_color) + spec_accum.times(specular_color); }
public static bool rayBoxIntersectPos(vect3d ray_pos, vect3d ray_dir, box3d box, out double dist, out vect3d pos, out int d, out int n) { if (rayBoxIntersectDist(ray_pos, ray_dir, box, out dist, out d, out n)) { pos = ray_pos + ray_dir * dist; return(true); } pos = new vect3d(0); return(false); }
public static vect3d rand_in_sphere() { vect3d p; do { p = new vect3d(rand.NextDouble() * 2 - 1, rand.NextDouble() * 2 - 1, rand.NextDouble() * 2 - 1); } while (p.length2() > 1); return(p); }
public override void trace(Ray r) { vect3d o = r.pos, d = r.dir; double t = Double.MaxValue; double Aq = A * d.x * d.x + D * d.x * d.y + B * d.y * d.y + C * d.z * d.z + d.x * d.z * E + d.y * d.z * F; double Bq = d.x * G + d.y * H + d.z * I + 2 * A * d.x * o.x + D * d.y * o.x + d.z * E * o.x + D * d.x * o.y + 2 * B * d.y * o.y + d.z * F * o.y + 2 * C * d.z * o.z + d.x * E * o.z + d.y * F * o.z; double Cq = J + G * o.x + A * o.x * o.x + H * o.y + D * o.x * o.y + B * o.y * o.y + I * o.z + E * o.x * o.z + F * o.y * o.z + C * o.z * o.z; if (Aq == 0) { if (Bq != 0) { t = -Cq / Bq; } } else { double Dq = Bq * Bq - 4 * Aq * Cq; if (Dq > 0) { if (r.is_outside) { t = (-Bq - Math.Sqrt(Dq)) / (2 * Aq); } else { t = (-Bq + Math.Sqrt(Dq)) / (2 * Aq); } } } if (t > 0 && t < r.hit_dist) { r.hit_dist = t; r.hit_object = this; vect3d p = r.pos + r.dir * t; r.hit_pos = p; r.hit_tex_coord = p; r.hit_norm = new vect3d( 2 * A * p.x + D * p.y + E * p.z + G, 2 * B * p.y + D * p.x + F * p.z + H, 2 * C * p.z + E * p.x + F * p.y + I); r.hit_norm.normalize(); if (r.dir * r.hit_norm > 0) { r.hit_norm *= -1; } } }
public Plane(vect3d p0, vect3d p1, vect3d p2, Shader shader) { this.shader = shader; this.pos = p0; z = (p1 - p0) % (p2 - p0); z.normalize(); x = p2 % z; x.normalize(); y = z % x; }
vect3d norm; // unit normal for getting plane intersection public Triangle(vect3d p0, vect3d p1, vect3d p2, Shader shader) { this.shader = shader; this.p0 = p0; this.p1 = p1; this.p2 = p2; N = (p1 - p0) % (p2 - p0); N /= N * N; norm = N; norm.normalize(); n0 = n1 = n2 = norm; }
protected void lightDirectPointSpec(Ray r, double specular_coeff, ref vect3d diff_accum, ref vect3d spec_accum) { Ray shadow_ray = new Ray(); shadow_ray.pos = r.hit_pos; foreach (var l in r.scene.lights) { vect3d dir = l.pos - r.hit_pos; double dist2 = dir.length2(); double dist2_inv = 1.0 / dist2; dir *= Math.Sqrt(dist2_inv); // calculate incidences to do early reject of shadow ray double incidence_dif = (dir * r.hit_norm); vect3d dir_r = r.hit_norm * ((dir * r.hit_norm) * 2) - dir; double incidence_spec = (dir_r * r.hit_norm); if (incidence_dif < 0 && incidence_spec < 0) { continue; } // shadow ray test shadow_ray.dir = dir; shadow_ray.hit_dist = Double.MaxValue; r.scene.trace(shadow_ray); if (shadow_ray.hit_dist * shadow_ray.hit_dist < dist2) { continue; } // diffuse if (incidence_dif > 0) { diff_accum += l.color * incidence_dif * dist2_inv; } // specular highlight if (incidence_spec > 0) { spec_accum += l.color * Math.Pow(incidence_spec, specular_coeff) * dist2_inv; } } }
public override void colorize(Ray r) { vect3d diff_accum = new vect3d(0, 0, 0); vect3d spec_accum = new vect3d(0, 0, 0); lightDirectPointSpec(r, specular_coeff, ref diff_accum, ref spec_accum); // calculate the polar coordinates vect3d sp; sp.x = -Math.Atan2(r.hit_tex_coord.z, r.hit_tex_coord.x) / (2 * Math.PI); sp.y = -Math.Atan2(Math.Sqrt(r.hit_tex_coord.x * r.hit_tex_coord.x + r.hit_tex_coord.z * r.hit_tex_coord.z), r.hit_tex_coord.y) / (Math.PI); sp.z = 0; vect3d diffuse_color = tex.sample(sp); r.color = diff_accum.times(diffuse_color) + spec_accum.times(specular_color); }
public override vect3d sample(vect3d pos) { // find modulo value (texture wrapping) vect2d p = new vect2d((pos.x % 1) * bmp.Width, ((1 - pos.y) % 1) * bmp.Height); if (p.x < 0) { p.x += bmp.Width; } if (p.y < 0) { p.y += bmp.Height; } // get color out of bmp Color color = bmp.GetPixel((int)p.x, (int)p.y); return(new vect3d(color.R / 255.0, color.G / 255.0, color.B / 255.0)); }
public override void trace(Ray r) { double v = r.dir * z; if (r.is_outside && v > 0 || !r.is_outside && v < 0) { return; } double dist = ((pos - r.pos) * z) / v; if (dist > 0 && dist < r.hit_dist) { r.hit_dist = dist; r.hit_pos = r.pos + r.dir * dist; vect3d rp = r.hit_pos - pos; r.hit_tex_coord = new vect3d(x * rp, y * rp, 0); r.hit_norm = z; r.hit_object = this; } }
public static double dist2_aabb_pt(vect3d mine, vect3d maxe, vect3d pt) { double d2 = 0; for (int i = 0; i < 3; i++) { double d = pt[i] - mine[i]; if (d < 0) { d2 += d * d; continue; } d = pt[i] - maxe[i]; if (d > 0) { d2 += d * d; } } return(d2); }
public override vect3d sample(vect3d pos) { // find modulo value (texture wrapping) vect2d p = new vect2d((pos.x % 1) * bmp.Width, ((1 - pos.y) % 1) * bmp.Height); if (p.x < 0) { p.x += bmp.Width; } if (p.y < 0) { p.y += bmp.Height; } // get color out of bmp int i = (int)p.x, j = (int)p.y; int ip = (i + 1) % bmp.Width, jp = (j + 1) % bmp.Height; double dx = p.x - i, dy = p.y - j; Color color; color = bmp.GetPixel(i, j); vect3d c00 = new vect3d(color.R, color.G, color.B); color = bmp.GetPixel(i, jp); vect3d c01 = new vect3d(color.R, color.G, color.B); color = bmp.GetPixel(ip, j); vect3d c10 = new vect3d(color.R, color.G, color.B); color = bmp.GetPixel(ip, jp); vect3d c11 = new vect3d(color.R, color.G, color.B); // combine samples with lerp return(((1 - dx) * (1 - dy) * c00 + (1 - dx) * dy * c01 + dx * (1 - dy) * c10 + dx * dy * c11) * (1.0 / 255.0)); }
public vect3i(vect3d v) { x = (int)System.Math.Floor(v.x); y = (int)System.Math.Floor(v.y); z = (int)System.Math.Floor(v.z); }
public Bitmap create_image(Scene scene) { Bitmap bmp = new Bitmap(width, height); // get the orientation of the camera matrix4d rotmat = orient.getMatrix(); vect3d rt = new vect3d(rotmat.m[0], rotmat.m[1], rotmat.m[2]); vect3d up = new vect3d(rotmat.m[4], rotmat.m[5], rotmat.m[6]); vect3d fwd = new vect3d(rotmat.m[8], rotmat.m[9], rotmat.m[10]); // convert the orientation to a 3D screen double aspect = (double)width / (double)height; double h = Math.Tan(fov_y * Math.PI / 360.0); up *= -h * 2; rt *= aspect * h * 2; fwd *= -1; // 2D screen conversions vect3d dx = rt / width; vect3d dy = up / height; vect3d corner = fwd - rt * .5 - up * .5; // expose each pixel Ray r = new Ray(); r.scene = scene; double subsample_res = 1.0 / subsamples; for (int j = 0; j < bmp.Height; j++) { for (int i = 0; i < bmp.Width; i++) { vect3d color = new vect3d(0, 0, 0); for (int jj = 0; jj < subsamples; jj++) { for (int ii = 0; ii < subsamples; ii++) { // set ray properties r.pos = this.pos; r.hit_dist = Double.MaxValue; r.color = new vect3d(0, 0, 0); r.hit_object = null; r.dir = corner + dx * (i + (ii + .5 /*Rand.rand.NextDouble()*/) * subsample_res) + dy * (j + (jj + .5 /*Rand.rand.NextDouble()*/) * subsample_res); r.dir.normalize(); // trace the ray scene.trace(r); if (r.hit_object != null) { r.hit_object.shader.colorize(r); color += r.color; } } } color *= subsample_res * subsample_res; // gamma correct the color double brightness = color.length(); color /= Math.Sqrt(brightness); // store the color int red = clamp(color.x); int green = clamp(color.y); int blue = clamp(color.z); bmp.SetPixel(i, j, Color.FromArgb(255, red, green, blue)); } } return(bmp); }
public vect3f(vect3d v) { x = (float)v.x; y = (float)v.y; z = (float)v.z; }
public virtual vect3d sample(vect3d p) { return(new vect3d(1, 1, 1)); }
public static bool rayBoxIntersectDist(vect3d ray_pos, vect3d ray_dir, box3d box, out double dist, out int face_d, out int face_n) { vect3d box_low = box[0]; vect3d box_high = box[1]; dist = 0; double Tnear = -1e30; double Tfar = 1e30; double T1, T2; face_d = -1; face_n = -1; // check bounding box to see if it enters level // this method assumes bounding box is already in coordinate system of the level for (int d = 0; d < 3; d++) { int n_temp = 0; if (ray_dir[d] == 0) { if (ray_pos[d] > box_high[d] || ray_pos[d] < box_low[d]) { return(false); } //int dp = (d + 1) % 3; //int dpp = (d + 2) % 3; //if (ray_pos[dp] > box_high[dp] || ray_pos[dp] < box_low[dp]) // return false; //if (ray_pos[dpp] > box_high[dpp] || ray_pos[dpp] < box_low[dpp]) // return false; } else { T1 = (box_low[d] - ray_pos[d]) / ray_dir[d]; T2 = (box_high[d] - ray_pos[d]) / ray_dir[d]; if (T1 > T2) { //swap(T1, T2); // since T1 intersection should be the nearest double t = T1; T1 = T2; T2 = t; n_temp = (n_temp + 1) % 2; } if (T1 > Tnear) { face_d = d; face_n = n_temp; Tnear = T1; // largest Tnear } if (T2 < Tfar) { Tfar = T2; // smallest Tfar } if (Tnear > Tfar) // box is missed { return(false); } if (Tfar < 0) { return(false); // box is behind ray } } } dist = Tnear; if (dist < 0) { return(false); } return(true); }
public static bool intersect_aabb_tri(vect3d mine, vect3d maxe, vect3d v0, vect3d v1, vect3d v2) { //** use separating axes to determine intersection // create points vect3d[] tri = { v0, v1, v2 }; vect3d[] box_ext = { mine, maxe }; vect3d[] box = new vect3d[8]; for (int i = 0; i < 8; i++) { box[i] = new vect3d((box_ext[i & 1])[0], (box_ext[(i >> 1) & 1])[1], (box_ext[i >> 2])[2]); } // create axes vect3d[] axes = new vect3d[13]; axes[0] = new vect3d(1, 0, 0); axes[1] = new vect3d(0, 1, 0); axes[2] = new vect3d(0, 0, 1); axes[3] = (v1 - v0) % (v2 - v0); for (int i = 0; i < 3; i++) { int ip = (i + 1) % 3; for (int j = 0; j < 3; j++) { axes[4 + i * 3 + j] = axes[j] % ((tri[i]) - (tri[ip])); } } // check overlaps for (int i = 0; i < 13; i++) { // tri extents double tri_min, tri_max; tri_min = tri_max = (tri[0]) * axes[i]; for (int k = 1; k < 3; k++) { double d = (tri[k]) * axes[i]; if (d < tri_min) { tri_min = d; } if (d > tri_max) { tri_max = d; } } // box extents double box_min, box_max; box_min = box_max = box[0] * axes[i]; for (int j = 1; j < 8; j++) { double d = box[j] * axes[i]; if (d < box_min) { box_min = d; } if (d > box_max) { box_max = d; } } // if disjoint, they don't intersect if (box_max < tri_min || tri_max < box_min) { return(false); } } return(true); }