public void TransformToPlane(Plane newPlane) { double eps = 1e-7; if (!PipeDataUtil.Equals(Vec.Dot(newPlane.Z, Plane.Z), 1, eps)) { throw new InvalidOperationException("Cannot transform arc to a new plane"); } if (Vec.Difference(newPlane.Origin, Plane.Origin).Length > eps) { throw new InvalidOperationException("The origins of the planes do not match"); } double angle = Vec.AngleBetween(Plane.X, newPlane.X); if (angle < eps) { return; } if (Vec.Dot(Vec.Cross(Plane.X, newPlane.X), Plane.Z) < 0) { angle *= -1; } Plane = new Plane(Plane.Origin, Plane.X.RotateAbout(Plane.Z, angle), Plane.Y.RotateAbout(Plane.Z, angle)); StartAngle -= angle; EndAngle -= angle; }
public static Vec[] RenderEntry() { int w = 256; int h = 256; int samps = 25; // # samples var tmp1 = new Vec(50, 52, 295.6); var tmp2 = new Vec(0, -0.042612, -1).Norm(); Ray cam = new Ray(ref tmp1, ref tmp2); // cam pos, dir Vec cx = new Vec(w * .5135 / h, 0, 0); Vec cy = (cx.Cross(ref cam.d)).Norm().Mul(.5135); Vec[] c = new Vec[w * h]; //#pragma omp parallel for schedule(dynamic, 1) // OpenMP // Loop over image rows for (int y = 0; y < h; y++) { //fprintf(stderr,"\rRendering (%d spp) %5.2f%%",samps*4,100.*y/(h-1)); RandomLCG rand = new RandomLCG((uint)y); // Loop cols for (ushort x = 0; x < w; x++) { // 2x2 subpixel rows for (int sy = 0; sy < 2; sy++) { int i = (h - y - 1) * w + x; // 2x2 subpixel cols for (int sx = 0; sx < 2; sx++) { Vec r = Vec_Zero; for (int s = 0; s < samps; s++) { double r1 = 2 * rand.NextNumber(); double r2 = 2 * rand.NextNumber(); double dx = r1 < 1 ? MathSqrt(r1) - 1 : 1 - MathSqrt(2 - r1); double dy = r2 < 1 ? MathSqrt(r2) - 1 : 1 - MathSqrt(2 - r2); var tmp3 = cy.Mul(((sy + .5 + dy) / 2 + y) / h - .5); Vec d = cx.Mul(((sx + .5 + dx) / 2 + x) / w - .5).Add( ref tmp3).Add(ref cam.d); var tmp4 = d.Mul(140); var tmp5 = cam.o.Add(ref tmp4); var tmp6 = d.Norm(); var tmp7 = new Ray(ref tmp5, ref tmp6); var tmp8 = radiance(ref tmp7, 0, ref rand).Mul(1.0 / samps); r = r.Add(ref tmp8); } var tmp9 = new Vec(clamp(r.x), clamp(r.y), clamp(r.z)).Mul(.25); c[i] = c[i].Add(ref tmp9); } } } } return(c); }
public static double ComputeUnscaledFormFactor( this Polygon3d polygon, V3d p, V3d n, double eps = 1e-6) { var vc = polygon.PointCount; V3d[] cpa = new V3d[vc + 1]; var cc = 0; var pb = polygon[0] - p; var hb = Vec.Dot(pb, n); bool hbp = hb > eps, hbn = hb < -eps; if (hb >= -eps) { cpa[cc++] = pb; } var p0 = pb; var h0 = hb; var h0p = hbp; var h0n = hbn; for (int vi = 1; vi < vc; vi++) { var p1 = polygon[vi] - p; var h1 = Vec.Dot(p1, n); bool h1p = h1 > eps, h1n = h1 < -eps; if (h0p && h1n || h0n && h1p) { cpa[cc++] = p0 + (p1 - p0) * (h0 / (h0 - h1)); } if (h1 >= -eps) { cpa[cc++] = p1; } p0 = p1; h0 = h1; h0p = h1p; h0n = h1n; } if (h0p && hbn || h0n && hbp) { cpa[cc++] = p0 + (pb - p0) * (h0 / (h0 - hb)); } var cpr = cpa.Map(cc, v => v.Length); var cv = Vec.Cross(cpa[0], cpa[cc - 1]); double ff = Vec.Dot(n, cv) * Fun.AcosClamped(Vec.Dot(cpa[0], cpa[cc - 1]) / (cpr[0] * cpr[cc - 1])) / cv.Length; for (int ci = 0; ci < cc - 1; ci++) { cv = Vec.Cross(cpa[ci + 1], cpa[ci]); ff += Vec.Dot(n, cv) * Fun.AcosClamped(Vec.Dot(cpa[ci + 1], cpa[ci]) / (cpr[ci + 1] * cpr[ci])) / cv.Length; } return(ff); }
/// <summary> /// Computes from a <see cref="V3f"/> point (origin) and /// a <see cref="V3f"/> normal the transformation matrix /// and its inverse. /// </summary> /// <param name="origin">The point which will become the new origin.</param> /// <param name="normal">The normal vector of the new ground plane.</param> /// <param name="local2global">A <see cref="M44f"/>The trafo from local to global system.</param> /// <param name="global2local">A <see cref="M44f"/>The trafofrom global to local system.</param> public static void NormalFrame(V3f origin, V3f normal, out M44f local2global, out M44f global2local ) { V3f min; float x = Fun.Abs(normal.X); float y = Fun.Abs(normal.Y); float z = Fun.Abs(normal.Z); if (x < y) { if (x < z) { min = V3f.XAxis; } else { min = V3f.ZAxis; } } else { if (y < z) { min = V3f.YAxis; } else { min = V3f.ZAxis; } } V3f xVec = Vec.Cross(normal, min); xVec.Normalize(); // this is now guaranteed to be normal to the input normal V3f yVec = Vec.Cross(normal, xVec); yVec.Normalize(); V3f zVec = normal; zVec.Normalize(); local2global = new M44f(xVec.X, yVec.X, zVec.X, origin.X, xVec.Y, yVec.Y, zVec.Y, origin.Y, xVec.Z, yVec.Z, zVec.Z, origin.Z, 0, 0, 0, 1); M44f mat = new M44f(xVec.X, xVec.Y, xVec.Z, 0, yVec.X, yVec.Y, yVec.Z, 0, zVec.X, zVec.Y, zVec.Z, 0, 0, 0, 0, 1); var shift = M44f.Translation(-origin); global2local = mat * shift; }
/// <summary> /// Computes from a <see cref="V3d"/> point (origin) and /// a <see cref="V3d"/> normal the transformation matrix /// and its inverse. /// </summary> /// <param name="origin">The point which will become the new origin.</param> /// <param name="normal">The normal vector of the new ground plane.</param> /// <param name="local2global">A <see cref="M44d"/>The trafo from local to global system.</param> /// <param name="global2local">A <see cref="M44d"/>The trafofrom global to local system.</param> public static void NormalFrame(V3d origin, V3d normal, out M44d local2global, out M44d global2local ) { V3d min; double x = Fun.Abs(normal.X); double y = Fun.Abs(normal.Y); double z = Fun.Abs(normal.Z); if (x < y) { if (x < z) { min = V3d.XAxis; } else { min = V3d.ZAxis; } } else { if (y < z) { min = V3d.YAxis; } else { min = V3d.ZAxis; } } V3d xVec = Vec.Cross(normal, min); xVec.Normalize(); // this is now guaranteed to be normal to the input normal V3d yVec = Vec.Cross(normal, xVec); yVec.Normalize(); V3d zVec = normal; zVec.Normalize(); local2global = new M44d(xVec.X, yVec.X, zVec.X, origin.X, xVec.Y, yVec.Y, zVec.Y, origin.Y, xVec.Z, yVec.Z, zVec.Z, origin.Z, 0, 0, 0, 1); M44d mat = new M44d(xVec.X, xVec.Y, xVec.Z, 0, yVec.X, yVec.Y, yVec.Z, 0, zVec.X, zVec.Y, zVec.Z, 0, 0, 0, 0, 1); var shift = M44d.Translation(-origin); global2local = mat * shift; }
/// <summary> /// Computes from a <see cref="V__x3t__"/> point (origin) and /// a <see cref="V__x3t__"/> normal the transformation matrix /// and its inverse. /// </summary> /// <param name="origin">The point which will become the new origin.</param> /// <param name="normal">The normal vector of the new ground plane.</param> /// <param name="local2global">A <see cref="M4__x4t__"/>The trafo from local to global system.</param> /// <param name="global2local">A <see cref="M4__x4t__"/>The trafofrom global to local system.</param> public static void NormalFrame(V__x3t__ origin, V__x3t__ normal, out M4__x4t__ local2global, out M4__x4t__ global2local ) { V__x3t__ min; __ft__ x = Fun.Abs(normal.X); __ft__ y = Fun.Abs(normal.Y); __ft__ z = Fun.Abs(normal.Z); if (x < y) { if (x < z) { min = V__x3t__.XAxis; } else { min = V__x3t__.ZAxis; } } else { if (y < z) { min = V__x3t__.YAxis; } else { min = V__x3t__.ZAxis; } } V__x3t__ xVec = Vec.Cross(normal, min); xVec.Normalize(); // this is now guaranteed to be normal to the input normal V__x3t__ yVec = Vec.Cross(normal, xVec); yVec.Normalize(); V__x3t__ zVec = normal; zVec.Normalize(); local2global = new M4__x4t__(xVec.X, yVec.X, zVec.X, origin.X, xVec.Y, yVec.Y, zVec.Y, origin.Y, xVec.Z, yVec.Z, zVec.Z, origin.Z, 0, 0, 0, 1); M4__x4t__ mat = new M4__x4t__(xVec.X, xVec.Y, xVec.Z, 0, yVec.X, yVec.Y, yVec.Z, 0, zVec.X, zVec.Y, zVec.Z, 0, 0, 0, 0, 1); var shift = M4__x4t__.Translation(-origin); global2local = mat * shift; }
public void Cross() { var p1 = new Vec(1, 2, 3); Assert.AreEqual(Math.Sqrt(96), p1.CrossMagnitude(new Vec(3, 2, 1))); Assert.AreEqual(96, p1.CrossSquareMagnitude(new Vec(3, 2, 1))); Assert.AreEqual(new Vec(-4, 8, -4), p1.Crossed(new Vec(3, 2, 1))); p1.Cross(new Vec(3, 2, 1)); Assert.AreEqual(new Vec(-4, 8, -4), p1); }
// https://stackoverflow.com/questions/1171849/finding-quaternion-representing-the-rotation-from-one-vector-to-another public static Rot3f HalfWayVec(V3f from, V3f into) { if (from.Dot(into).ApproximateEquals(-1)) { return(new Rot3f(0, from.AxisAlignedNormal())); } else { V3f half = Vec.Normalized(from + into); QuaternionF q = new QuaternionF(Vec.Dot(from, half), Vec.Cross(from, half)); return(new Rot3f(q.Normalized)); } }
// https://stackoverflow.com/questions/1171849/finding-quaternion-representing-the-rotation-from-one-vector-to-another public static __rot3t__ HalfWayVec(__v3t__ from, __v3t__ into) { if (from.Dot(into).ApproximateEquals(-1)) { return(new __rot3t__(0, from.AxisAlignedNormal())); } else { __v3t__ half = Vec.Normalized(from + into); __quatt__ q = new __quatt__(Vec.Dot(from, half), Vec.Cross(from, half)); return(new __rot3t__(q.Normalized)); } }
public static __rot3t__ HalfWayQuat(__v3t__ from, __v3t__ into) { var d = Vec.Dot(from, into); if (d.ApproximateEquals(-1)) { return(new __rot3t__(0, from.AxisAlignedNormal())); } else { __quatt__ q = new __quatt__(d + 1, Vec.Cross(from, into)); return(new __rot3t__(q.Normalized)); } }
public static Rot3f HalfWayQuat(V3f from, V3f into) { var d = Vec.Dot(from, into); if (d.ApproximateEquals(-1)) { return(new Rot3f(0, from.AxisAlignedNormal())); } else { QuaternionF q = new QuaternionF(d + 1, Vec.Cross(from, into)); return(new Rot3f(q.Normalized)); } }
public static Rot3f Original(V3f from, V3f into) { var angle = from.AngleBetween(into); if (angle < 1e-6f) { return(Rot3f.Identity); } else if (Constant.PiF - angle < 1e-6f) { return(new Rot3f(0, from.AxisAlignedNormal())); } else { V3f axis = Vec.Cross(from, into).Normalized; return(Rot3f.Rotation(axis, angle)); } }
/// <summary> /// Computes from a <see cref="V__x3t__"/> normal the transformation matrix /// from the local coordinate system where the normal is the z-axis to /// the global coordinate system. /// </summary> /// <param name="normal">The normal vector of the new ground plane.</param> public static M3__x3t__ NormalFrameLocal2Global(V__x3t__ normal) { V__x3t__ min; double x = Fun.Abs(normal.X); double y = Fun.Abs(normal.Y); double z = Fun.Abs(normal.Z); if (x < y) { if (x < z) { min = V__x3t__.XAxis; } else { min = V__x3t__.ZAxis; } } else { if (y < z) { min = V__x3t__.YAxis; } else { min = V__x3t__.ZAxis; } } var xVec = Vec.Cross(normal, min); xVec.Normalize(); // this is now guaranteed to be normal to the input normal var yVec = Vec.Cross(normal, xVec); yVec.Normalize(); var zVec = normal; zVec.Normalize(); return(new M3__x3t__(xVec.X, yVec.X, zVec.X, xVec.Y, yVec.Y, zVec.Y, xVec.Z, yVec.Z, zVec.Z)); }
public static __rot3t__ Original(__v3t__ from, __v3t__ into) { var angle = from.AngleBetween(into); //# var rotIntoEps = isDouble ? "1e-15" : "1e-6f"; if (angle < __rotIntoEps__) { return(__rot3t__.Identity); } else if (__pi__ - angle < __rotIntoEps__) { return(new __rot3t__(0, from.AxisAlignedNormal())); } else { __v3t__ axis = Vec.Cross(from, into).Normalized; return(__rot3t__.Rotation(axis, angle)); } }
public Arc(Vec startPt, Vec endPt, Vec ptOnArc) { Vec midPt1 = Vec.Multiply(Vec.Sum(endPt, ptOnArc), 0.5); Vec midPt2 = Vec.Multiply(Vec.Sum(startPt, ptOnArc), 0.5); Vec seg1 = Vec.Difference(ptOnArc, startPt); Vec seg2 = Vec.Difference(endPt, ptOnArc); Vec planeZ = Vec.Cross(seg1, seg2); Vec rad1 = Vec.Cross(planeZ, seg1); Vec rad2 = Vec.Cross(planeZ, seg2); Vec center = Vec.IntersectLines(midPt1, rad1, midPt2, rad2); Vec planeX = Vec.Difference(startPt, center); Vec planeY = Vec.Cross(planeZ, planeX); _plane = new Plane(center, planeX, planeY, planeZ); _radius = Vec.Difference(center, startPt).Length; _startAngle = 0; _endAngle = 2 * Vec.AngleBetween(rad1, rad2); }
public void ValueType_Vec() { var p1 = new Vec(1, 0, 0); var p2 = new Vec(0, 1, 0); Assert.IsFalse(p1.IsEqual(p2, 0.99, 0.1)); Assert.IsTrue(p1.IsEqual(p2, 1.01, 0.1)); Assert.IsTrue(p1.IsEqual(p2, 0.99, Math.PI / 2)); Assert.IsTrue(p1.IsNormal(p2, 0.1)); Assert.IsFalse(p1.IsOpposite(p2, 0.1)); Assert.IsTrue(p1.IsOpposite(p2, Math.PI / 2)); Assert.IsFalse(p1.IsParallel(p2, 0.1)); Assert.IsTrue(p1.IsParallel(p2, Math.PI / 2)); p1 = new Vec(1, 2, 3); p2 = new Vec(4, 5, 6); Assert.AreEqual(14, p1.SquareMagnitude()); Assert.AreEqual(Math.Sqrt(14), p1.Magnitude()); p2 = p1; p2.Add(new Vec(1, 2, 3)); Assert.AreEqual(new Vec(2, 4, 6), p2); Assert.AreEqual(new Vec(2, 4, 6), p1.Added(new Vec(1, 2, 3))); p2 = new Vec(1, 2, 3); p2.Subtract(new Vec(3, 2, 1)); Assert.AreEqual(new Vec(-2, 0, 2), p2); Assert.AreEqual(new Vec(-2, 0, 2), p1.Subtracted(new Vec(3, 2, 1))); p2 = new Vec(1, 2, 3); p2.Cross(new Vec(3, 2, 1)); Assert.AreEqual(new Vec(-4, 8, -4), p2); Assert.AreEqual(new Vec(-4, 8, -4), p1.Crossed(new Vec(3, 2, 1))); Assert.AreEqual(Math.Sqrt(96), p1.CrossMagnitude(new Vec(3, 2, 1))); Assert.AreEqual(96, p1.CrossSquareMagnitude(new Vec(3, 2, 1))); p2 = new Vec(1, 2, 3); p2.CrossCross(new Vec(1, 2, 3), new Vec(4, 5, 6)); Assert.AreEqual(new Vec(-24, -6, 12), p2); Assert.AreEqual(new Vec(-24, -6, 12), p1.CrossCrossed(new Vec(1, 2, 3), new Vec(4, 5, 6))); p2 = new Vec(1, 2, 3); p2.Divide(2); Assert.AreEqual(new Vec(0.5, 1, 1.5), p2); Assert.AreEqual(new Vec(0.5, 1, 1.5), p1.Divided(2)); Assert.AreEqual(14, p1.Dot(new Vec(1, 2, 3))); Assert.AreEqual(0, p1.DotCross(new Vec(4, 5, 6), new Vec(4, 5, 6))); p2 = new Vec(1, 2, 3); p2.Multiply(2); Assert.AreEqual(new Vec(2, 4, 6), p2); Assert.AreEqual(new Vec(2, 4, 6), p1.Multiplied(2)); p2 = new Vec(1, 2, 3); p2.Scale(2); Assert.AreEqual(new Vec(2, 4, 6), p2); Assert.AreEqual(new Vec(2, 4, 6), p1.Scaled(2)); p2 = new Vec(1, 2, 3); p2.Normalize(); Assert.IsTrue(p2.IsEqual(new Vec(0.26726, 0.53452, 0.80178), 0.00001, 0.00001)); Assert.IsTrue(p1.Normalized().IsEqual(new Vec(0.26726, 0.53452, 0.80178), 0.00001, 0.00001)); p2 = new Vec(1, 2, 3); p2.Reverse(); Assert.AreEqual(new Vec(-1, -2, -3), p2); Assert.AreEqual(new Vec(-1, -2, -3), p1.Reversed()); p2.SetLinearForm(new Vec(1, 2, 3), new Vec(4, 5, 6)); Assert.AreEqual(new Vec(5, 7, 9), p2); p2.SetLinearForm(2, new Vec(1, 2, 3), new Vec(4, 5, 6)); Assert.AreEqual(new Vec(6, 9, 12), p2); p2.SetLinearForm(2, new Vec(1, 2, 3), 3, new Vec(4, 5, 6)); Assert.AreEqual(new Vec(14, 19, 24), p2); p2.SetLinearForm(2, new Vec(1, 2, 3), 3, new Vec(4, 5, 6), new Vec(7, 8, 9)); Assert.AreEqual(new Vec(21, 27, 33), p2); p2.SetLinearForm(2, new Vec(1, 2, 3), 3, new Vec(4, 5, 6), 4, new Vec(7, 8, 9)); Assert.AreEqual(new Vec(42, 51, 60), p2); p2.SetLinearForm(2, new Vec(1, 2, 3), 3, new Vec(4, 5, 6), 4, new Vec(7, 8, 9), new Vec(10, 11, 12)); Assert.AreEqual(new Vec(52, 62, 72), p2); p2 = new Vec(2, 0, 0); p2.Mirror(new Vec(0, 1, 0)); Assert.AreEqual(new Vec(-2, 0, 0), p2); Assert.AreEqual(new Vec(2, 0, 0), p2.Mirrored(new Vec(0, 1, 0))); var m2 = new Ax1(new Pnt(-1, 2, -3), new Dir(-1, 0, 0)); p2 = new Vec(2, 1, 3); Assert.AreEqual(new Vec(2, -1, -3), p2.Mirrored(m2)); p2.Mirror(m2); Assert.AreEqual(new Vec(2, -1, -3), p2); var a2 = new Ax2(new Pnt(-1, 2, -3), new Dir(-1, 0, 0)); p2 = new Vec(2, 1, 3); Assert.AreEqual("-2,1,3", p2.Mirrored(a2).ToString()); p2.Mirror(a2); Assert.AreEqual("-2,1,3", p2.ToString()); p2 = new Vec(2, 1, 3); Assert.IsTrue(new Vec(2, 3, -1).IsEqual(p2.Rotated(m2, Math.PI / 2), 0.0001, 0.0001)); p2.Rotate(m2, Math.PI / 2); Assert.IsTrue(new Vec(2, 3, -1).IsEqual(p2, 0.0001, 0.0001)); //TestContext.WriteLine(string.Format(CultureInfo.InvariantCulture, "{0},{1},{2}", gp2.x, gp2.y, gp2.z)); Trsf t1 = new Trsf(); t1.SetRotation(Ax1.OZ, Math.PI / 2); p2 = new Vec(4, 5, 6); Assert.AreEqual("-5,4,6", p2.Transformed(t1).ToString()); p2.Transform(t1); Assert.AreEqual("-5,4,6", p2.ToString()); }
/// <summary> /// Creates a plane from 3 independent points. /// A normalized normal vector is computed and stored. /// </summary> public Plane3d(V3d p0, V3d p1, V3d p2) { Normal = Vec.Cross(p1 - p0, p2 - p0).Normalized; Distance = Vec.Dot(Normal, p0); }
public static unsafe Vec radiance(ref Ray r, int depth, ref RandomLCG rand) { double t; // distance to intersection Sphere *obj = intersect(ref r, out t); if (obj == null) { return(Vec_Zero); // if miss, return black } else { int newDepth = depth + 1; bool isMaxDepth = newDepth > 100; // Russian roulette for path termination bool isUseRR = newDepth > 5; bool isRR = isUseRR && rand.NextNumber() < obj->maxC; if (isMaxDepth || (isUseRR && !isRR)) { return(obj->e); } else { Vec f = (isUseRR && isRR) ? obj->cc : obj->c; var tmp1 = r.d.Mul(t); Vec x = r.o.Add(ref tmp1); Vec n = (x.Sub(ref obj->p)).Norm(); Vec nl = n.Dot(ref r.d) < 0 ? n : n.Mul(-1); if (obj->refl == MatType.DIFF) { // Ideal DIFFUSE reflection double r1 = 2 * M_PI * rand.NextNumber(); double r2 = rand.NextNumber(); double r2s = MathSqrt(r2); Vec w = nl; Vec wo = w.x <-0.1 || w.x> 0.1 ? Vec_YAxis : Vec_XAxis; Vec u = (wo.Cross(ref w)).Norm(); Vec v = w.Cross(ref u); var tmp2 = v.Mul(MathSin(r1)).Mul(r2s); var tmp3 = w.Mul(MathSqrt(1 - r2)); Vec d = (u.Mul(MathCos(r1)).Mul(r2s).Add(ref tmp2).Add(ref tmp3)).Norm(); var tmp4 = new Ray(ref x, ref d); var tmp5 = radiance(ref tmp4, newDepth, ref rand); var tmp6 = f.Mul(ref tmp5); return(obj->e.Add(ref tmp6)); } else if (obj->refl == MatType.SPEC) // Ideal SPECULAR reflection { var tmp8 = n.Mul(2 * (n.Dot(ref r.d))); var tmp9 = r.d.Sub(ref tmp8); var tmp7 = new Ray(ref x, ref tmp9); var tmp10 = radiance(ref tmp7, newDepth, ref rand); var tmp11 = f.Mul(ref tmp10); return(obj->e.Add(ref tmp11)); } else { // Ideal dielectric REFRACTION var tmp100 = n.Mul(2 * (n.Dot(ref r.d))); var tmp101 = r.d.Sub(ref tmp100); Ray reflRay = new Ray(ref x, ref tmp101); bool into = n.Dot(ref nl) > 0; // Ray from outside going in? double nc = 1; double nt = 1.5; double nnt = into ? nc / nt : nt / nc; double ddn = r.d.Dot(ref nl); double cos2t = 1 - nnt * nnt * (1 - ddn * ddn); if (cos2t < 0) // Total internal reflection { var tmp12 = radiance(ref reflRay, newDepth, ref rand); var tmp13 = f.Mul(ref tmp12); return(obj->e.Add(ref tmp13)); } else { var tmp14 = n.Mul((into ? 1 : -1) * (ddn * nnt + MathSqrt(cos2t))); Vec tdir = (r.d.Mul(nnt).Sub(ref tmp14)).Norm(); double a = nt - nc; double b = nt + nc; double R0 = (a * a) / (b * b); double c = 1 - (into ? -ddn : tdir.Dot(ref n)); double Re = R0 + (1 - R0) * c * c * c * c * c; double Tr = 1 - Re; double P = .25 + .5 * Re; double RP = Re / P; double TP = Tr / (1 - P); Vec result; if (newDepth > 2) { // Russian roulette and splitting for selecting reflection and/or refraction if (rand.NextNumber() < P) { result = radiance(ref reflRay, newDepth, ref rand).Mul(RP); } else { var tmp15 = new Ray(ref x, ref tdir); result = radiance(ref tmp15, newDepth, ref rand).Mul(TP); } } else { var tmp16 = new Ray(ref x, ref tdir); var tmp17 = radiance(ref tmp16, newDepth, ref rand).Mul(Tr); result = radiance(ref reflRay, newDepth, ref rand).Mul(Re).Add(ref tmp17); } var tmp18 = f.Mul(ref result); return(obj->e.Add(ref tmp18)); } } } } }