private double ComputeLighting(Vector point, Vector normal, Vector view, int specular) { var i = 0.0; Vector L = new Vector(); foreach (var light in _scene.Lights) { if (light.Type == LightType.Ambient) { i += light.Intensity; } else { double tMax = 0; if (light.Type == LightType.Point) { L = light.Position.Subtract(point); tMax = 1; } if (light.Type == LightType.Direct) { L = light.Direction.Multiply(-1); tMax = double.PositiveInfinity; } var(shadowPrimitive, _) = ClosestIntersection(point, L, 0.001, tMax); if (shadowPrimitive != null && !shadowPrimitive.LightTransparent) { continue; } var nDotL = normal.DotProduct(L); if (nDotL > 0) { var intensity = light.Intensity * nDotL / (normal.Lenght() * L.Lenght()); i += intensity; } if (specular == -1) { continue; } var R = ReflectRay(L, normal); var rDotV = R.DotProduct(view); if (rDotV > 0) { var tmp = light.Intensity * Math.Pow(rDotV / (R.Lenght() * view.Lenght()), specular); i += tmp; } } } return(i); }
private (double, double) IntersectRaySphere(Vector O, Vector D, Sphere sphere) { var C = sphere.Center; var r = sphere.Radius; var oc = O.Subtract(C); var k1 = D.DotProduct(D); var k2 = 2 * oc.DotProduct(D); var k3 = oc.DotProduct(oc) - r * r; var discr = k2 * k2 - 4 * k1 * k3; if (discr < 0) { return(double.PositiveInfinity, double.PositiveInfinity); } var t1 = (-k2 + Math.Sqrt(discr)) / (2 * k1); var t2 = (-k2 - Math.Sqrt(discr)) / (2 * k1); return(t1, t2); }
private Vector TraceRay(Vector O, Vector D, double tMin, double tMax, int depth) { var(closestPrimitive, closest_t) = ClosestIntersection(O, D, tMin, tMax); if (closestPrimitive == null) { return(Vector.FromColor(_options.BgColor)); } var view = D.Multiply(-1); var P = O.Add(D.Multiply(closest_t)); Vector normal = new Vector(); if (closestPrimitive is Plane plane) { normal = plane.Normal; } if (closestPrimitive is Sphere sphere) { if (sphere.LightTransparent) { return(Vector.FromColor(sphere.Color)); } normal = P.Subtract(sphere.Center); } if (closestPrimitive is Box box) { normal = box.GetNormal(O, D, tMin); } if (closestPrimitive is Surface surface) { normal = surface.GetNormal(O, D, closest_t); } if (closestPrimitive is Torus torus) { normal = torus.GetNormal(O, D, closest_t); } if (closestPrimitive is Disk disk) { normal = disk.GetNormal(); } normal = normal.Multiply(1 / normal.Lenght()); //unit vector if (normal.DotProduct(D) > 0) { normal = normal.Multiply(-1); } var color = closestPrimitive.Color; if (closestPrimitive is Plane) { var x = (int)Math.Round(O.D1 + D.D1 * closest_t) % 2; var z = (int)Math.Round(O.D3 + D.D3 * closest_t) % 2; if (x == z) { color = Color.FromRgb(0, 0, 0); } } var local_color = Vector.FromColor(color) .Multiply(ComputeLighting(P, normal, view, closestPrimitive.Specular)); var r = closestPrimitive.Reflect; if (depth <= 0 || r <= 0) { return(local_color); } var R = ReflectRay(view, normal); var reflectedColor = TraceRay(P, R, 0.001d, double.PositiveInfinity, depth - 1); return(local_color.Multiply(1 - r).Add(reflectedColor.Multiply(r))); }
private Vector ReflectRay(Vector r, Vector normal) { return(normal.Multiply(2 * r.DotProduct(normal)).Subtract(r)); }