public override bool HitTest(ref Ray ray, ref HitTestResult result) { Vector eo = Center; eo.Sub(ref ray.Position); double v = Vector.Dot(ref eo, ref ray.Direction); var disc = Radius * Radius - Vector.Dot(ref eo, ref eo) + v * v; if (disc < 0) { return(false); } disc = v - Math.Sqrt(disc); if (disc < 0.001f) { return(false); } result.Shape = this; result.Position = ray.Position + ray.Direction * disc; result.Normal = result.Position - Center; result.Normal.Normalize(); result.Distance = disc; return(true); }
public abstract bool HitTest(ref Ray ray, ref HitTestResult result);
private Color Trace(ref Ray ray, Scene scene, int depth) { HitTestResult hittest = new HitTestResult(); hittest.Distance = double.MaxValue; if (!scene.HitTest(ref ray, ref hittest)) { return(Color.Black); } var d = ray.Direction; var pos = hittest.Distance * ray.Direction + ray.Position; //交点位置 var normal = hittest.Normal; //交点法向量 var cosa = normal * d; //-Cos(入射角) var reflectDir = d - 2 * cosa * normal; //反射方向 Color color; if (cosa < 0) { color = GetNaturalColor(hittest.Shape, ref pos, ref normal, ref reflectDir, scene); } else { color = Color.Black; } if (depth <= 0) { return(color); } depth--; //追踪反射光线 var ray1 = new Ray(pos, reflectDir); var rcolor1 = Trace(ref ray1, scene, depth); rcolor1.Multiply(hittest.Shape.Surface.Reflect(pos)); //追踪折射光线 var n = hittest.Shape.Surface.Refraction(pos);// 折射率 if (n > 0) { if (cosa > 0) { n = 1 / n; } var f = Math.Acos(-cosa); //入射角 var t = Math.Asin(Math.Sqrt(1 - cosa * cosa)); //折射角 //fresnel公式,计算反射比 double s1 = Math.Sin(f - t); double s2 = Math.Sin(f + t); double t1 = Math.Tan(f - t); double t2 = Math.Tan(f + t); var factor = (((s1 * s1) / (s2 * s2) + (t1 * t1) / (t2 * t2)) / 2); if (factor < 1 && factor >= 0) //等于1时发生了全反射 { rcolor1.Multiply(factor); //折射定律矢量形式:n2 * e2 - n1 * e1 = (n2 * cos(t) - n1 * cos(f)) * normal var dir = ((n * Math.Cos(t) - Math.Cos(f)) * normal) * (1 / n); dir.Normalize(); var ray2 = new Ray(pos, dir); var rcolor2 = Trace(ref ray2, scene, depth); rcolor2.Multiply(1 - factor); color.Add(ref rcolor2); } } color.Add(ref rcolor1); return(color); }