Vector getRefractedRay(float initial_refraction, Spheres *sph, Vector surface_norm, Vector light_ray) { float refraction_index = sph->refraction_index; float n = initial_refraction/refraction_index; Vector refract_ray; //n = .9; //light_ray.x = 0.707107; //light_ray.y = -0.707107; //light_ray.z = 0; //surface_norm.x = 0; //surface_norm.y = 1; //surface_norm.z = 0; float cosTheta1 = vec_dot(surface_norm, vec_scale(light_ray,-1)); float cosTheta2 = sqrt(1.0f-pow(n,2)*(1-(cosTheta1*cosTheta1))); Vector a = vec_scale(light_ray, n); Vector b = vec_scale(surface_norm, n*cosTheta1 - cosTheta2); if(cosTheta1 > 0.0f) { refract_ray = vec_plus(vec_scale(light_ray,n), vec_scale(surface_norm, n*cosTheta1-cosTheta2)); } else { refract_ray = vec_minus(vec_scale(light_ray,n), vec_scale(surface_norm, n*cosTheta1-cosTheta2)); } return refract_ray; }
Vector getReflectedRay(Vector surface_norm, Vector light_ray) { float cosTheta1 = vec_dot(surface_norm, vec_scale(light_ray,-1)); Vector reflect_ray = vec_plus(light_ray, vec_scale(surface_norm, 2*cosTheta1)); return reflect_ray; }
// This function is adapted from geom.cpp in ODE, which // is copyright Russell Smith. // given two line segments A and B with endpoints a1-a2 and b1-b2, return the // points on A and B that are closest to each other (in cp1 and cp2). // in the case of parallel lines where there are multiple solutions, a // solution involving the endpoint of at least one line will be returned. // this will work correctly for zero length lines, e.g. if a1==a2 and/or // b1==b2. // // the algorithm works by applying the voronoi clipping rule to the features // of the line segments. the three features of each line segment are the two // endpoints and the line between them. the voronoi clipping rule states that, // for feature X on line A and feature Y on line B, the closest points PA and // PB between X and Y are globally the closest points if PA is in V(Y) and // PB is in V(X), where V(X) is the voronoi region of X. void line_segment_closest_points(double a1[3], double a2[3], double b1[3], double b2[3], double cp1[3], double cp2[3]) { double la, lb, k, da1, da2, da3, da4, db1, db2, db3, db4, det; double a1a2[3], b1b2[3], a1b1[3], a1b2[3], a2b1[3], a2b2[3], n[3], tmp[3]; // check vertex-vertex features vec_subt(a1a2, a2, a1); vec_subt(b1b2, b2, b1); vec_subt(a1b1, b1, a1); da1 = vec_dot(a1a2, a1b1); db1 = vec_dot(b1b2, a1b1); if ((da1 <= 0) && (db1 >= 0)) { vec_copy(cp1, a1); vec_copy(cp2, b1); return; } vec_subt(a1b2, b2, a1); da2 = vec_dot(a1a2, a1b2); db2 = vec_dot(b1b2,a1b2); if ((da2 <= 0) && (db2 <= 0)) { vec_copy(cp1, a1); vec_copy(cp2, b2); return; } vec_subt(a2b1, b1, a2); da3 = vec_dot(a1a2, a2b1); db3 = vec_dot(b1b2, a2b1); if ((da3 >= 0) && (db3 >= 0)) { vec_copy(cp1, a2); vec_copy(cp2, b1); return; } vec_subt(a2b2, b2, a2); da4 = vec_dot(a1a2, a2b2); db4 = vec_dot(b1b2, a2b2); if ((da4 >= 0) && (db4 <= 0)) { vec_copy(cp1, a2); vec_copy(cp2, b2); return; } // check edge-vertex features. // if one or both of the lines has zero length, we will never get to here, // so we do not have to worry about the following divisions by zero. la = vec_dot(a1a2, a1a2); if ((da1 >= 0) && (da3 <= 0.0)) { k = da1 / la; vsv_mult(tmp, k, a1a2); vec_subt(n, a1b1, tmp); if (vec_dot(b1b2, n) >= 0.0) { vec_plus(cp1, a1, tmp); vec_copy(cp2, b1); return; } } if ((da2 >= 0) && (da4 <= 0)) { k = da2 / la; vsv_mult(tmp, k, a1a2); vec_subt(n, a1b2, tmp); if (vec_dot(b1b2, n) <= 0.0) { vec_plus(cp1, a1, tmp); vec_copy(cp2, b2); return; } } lb = vec_dot(b1b2, b1b2); if ((db1 <= 0) && (db2 >= 0.0)) { k = -db1 / lb; vsv_mult(tmp, k, b1b2); vec_neg(a1b1); vec_subt(n, a1b1, tmp); if (vec_dot(a1a2, n) >= 0.0) { vec_copy(cp1,a1); vec_plus(cp2, b1, tmp); return; } } if ((db3 <= 0.0) && (db4 >= 0.0)) { k = -db3 / lb; vsv_mult(tmp, k, b1b2); vec_neg(a2b1); vec_subt(n, a2b1, tmp); if (vec_dot(a1a2, n) <= 0.0) { vec_copy(cp1,a2); vec_plus(cp2, b1, tmp); return; } } // it must be edge-edge k = vec_dot(a1a2, b1b2); det = la*lb - k*k; if (det <= 0.0) { // this should never happen, but just in case... vec_copy(cp1, a1); vec_copy(cp2, b1); return; } det = 1.0/det; double alpha = (lb*da1 - k*db1) * det; double beta = ( k*da1 - la*db1) * det; vs_mult(a1a2, alpha); vec_plus(cp1, a1, a1a2); vs_mult(b1b2, beta); vec_plus(cp2, b1, b1b2); }
double line_segment_distance(double seg1_a[3], double seg1_b[3], double seg2_a[3], double seg2_b[3]) { double sc, sd, sn, tc, td, tn; double uu, uv, vv, uw, vw, det; double u[3], v[3], w[3]; vec_subt(u, seg1_b, seg1_a); vec_subt(v, seg2_b, seg2_a); vec_subt(w, seg1_a, seg2_a); uu = vec_dot(u, u); uv = vec_dot(u, v); vv = vec_dot(v, v); uw = vec_dot(u, w); vw = vec_dot(v, w); det = uu*vv - sqr(uv); sd = det; td = det; if (det < ALMOST_ZERO) { sn = 0.0; sd = 1.0; tn = vw; td = vv; } else { sn = uv*vw - vv*uw; tn = uu*vw - uv*uw; if (sn < 0.0) { sn = 0.0; tn = vw; td = vv; } else if (sn > sd) { sn = sd; tn = vw + uv; td = vv; } } if (tn < 0.0) { tn = 0.0; if (-uw < 0.0) { sn = 0.0; } else if (-uw > uu) { sn = sd; } else { sn = -uw; sd = uu; } } else if (tn > td) { tn = td; if (uv-uw < 0.0) { sn = 0.0; } else if (uv-uw > uu) { sn = sd; } else { sn = uv-uw; sd = uu; } } sc = (absv(sn) < ALMOST_ZERO ? 0.0 : sn / sd); tc = (absv(tn) < ALMOST_ZERO ? 0.0 : tn / td); vs_mult(u, sc); vs_mult(v, tc); vec_plus(w, w, u); vec_subt(w, w, v); return vec_dot(w, w); }