public IntersectionInfo Intersection(Ray r) { Vector3D normal = VectorOperations.VectorProduct(new Vector3D(A, B), new Vector3D(A, C)); normal *= (1 / normal.Length); Vector3D V = new Vector3D(r.Origin.X - A.X, r.Origin.Y - A.Y, r.Origin.Z - A.Z); //определяем пересекает ли луч треугольник double t = -VectorOperations.ScalarProduct(V, normal) / VectorOperations.ScalarProduct(r.Direction, normal); if (t <= epsilon || Double.IsNaN(t) || Double.IsInfinity(t)) { return(null); } Point3D crossPoint = new Point3D(r.Origin.X + r.Direction.X * t, r.Origin.Y + r.Direction.Y * t, r.Origin.Z + r.Direction.Z * t); Vector3D OX = new Vector3D(A, B); Vector3D AC = new Vector3D(A, C); Vector3D AD = new Vector3D(A, crossPoint); Vector3D OY = VectorOperations.VectorProduct(normal, OX); Line3D axis = new Line3D(A, OX); Line3D ordinate = new Line3D(A, OY); double Bx = VectorOperations.Distance(ordinate, B); double By = 0; double Cx = VectorOperations.Distance(ordinate, C) * ((VectorOperations.Cos(OX, AC) < 0)? -1 : 1); double Cy = VectorOperations.Distance(axis, C) * ((VectorOperations.Cos(OY, AC) < 0)? -1 : 1); double Dx = VectorOperations.Distance(ordinate, crossPoint) * ((VectorOperations.Cos(OX, AD) < 0)? -1 : 1); double Dy = VectorOperations.Distance(axis, crossPoint) * ((VectorOperations.Cos(OY, AD) < 0) ? -1 : 1); int s1 = Math.Sign(Bx * Dy - By * Dx); int s2 = Math.Sign((Cx - Bx) * (Dy - By) - (Cy - By) * (Dx - Bx)); int s3 = Math.Sign(-Cx * (Dy - Cy) + Cy * (Dx - Cx)); if (s1 == s2 && s1 == s3 && s2 == s3) { Material m = ownerSurface.MaterialFront; if (VectorOperations.Cos(normal, r.Direction) >= -epsilon && (ownerSurface.MaterialBack != null)) { normal *= (-1); m = ownerSurface.MaterialBack; } return(new IntersectionInfo(crossPoint, normal, m)); } return(null); }
public IntersectionInfo Intersection(Ray r) { Vector3D N = VectorOperations.VectorProduct(new Vector3D(A, B), new Vector3D(A, C)); //нормаль определяет внешнюю и внутреннюю сторону треугольника N *= (1 / N.Length); Vector3D V = new Vector3D(r.Origin.X - A.X, r.Origin.Y - A.Y, r.Origin.Z - A.Z); double t = -VectorOperations.ScalarProduct(V, N) / VectorOperations.ScalarProduct(r.Direction, N); if (t <= epsilon || Double.IsNaN(t) || Double.IsInfinity(t)) { return(null); } Point3D crossPoint = new Point3D(r.Origin.X + r.Direction.X * t, r.Origin.Y + r.Direction.Y * t, r.Origin.Z + r.Direction.Z * t); Vector3D OX = new Vector3D(A, B); Vector3D AC = new Vector3D(A, C); Vector3D AD = new Vector3D(A, crossPoint); Vector3D OY = VectorOperations.VectorProduct(N, OX); Line3D axis = new Line3D(A, OX); Line3D ordinate = new Line3D(A, OY); double Bx = VectorOperations.Distance(ordinate, B); double By = 0; double Cx = VectorOperations.Distance(ordinate, C); if (VectorOperations.Cos(OX, AC) < 0) { Cx *= -1; } double Cy = VectorOperations.Distance(axis, C); if (VectorOperations.Cos(OY, AC) < 0) { Cy *= -1; } double Dx = VectorOperations.Distance(ordinate, crossPoint); if (VectorOperations.Cos(OX, AD) < 0) { Dx *= -1; } double Dy = VectorOperations.Distance(axis, crossPoint); if (VectorOperations.Cos(OY, AD) < 0) { Dy *= -1; } int s1 = Math.Sign(Bx * Dy - By * Dx); int s2 = Math.Sign((Cx - Bx) * (Dy - By) - (Cy - By) * (Dx - Bx)); int s3 = Math.Sign(-Cx * (Dy - Cy) + Cy * (Dx - Cx)); if (s1 == s2 && s1 == s3 && s2 == s3) { Material m = material_front; if (VectorOperations.Cos(N, r.Direction) >= -epsilon && (material_back != null)) { N *= (-1); m = material_back; } return(new IntersectionInfo(crossPoint, N, m)); } return(null); }
internal Color RayTracing(Ray r, int depth) { if (depth > 5) { return(Color.Black); } IntersectionInfo info = GetFirstIntersection(r); if (info == null) //луч не пересекает предмет { return(defaultColor); } double R = 0, G = 0, B = 0; //луч пересекает предмет double IdR = 0, IdG = 0, IdB = 0; double IsR = 0, IsG = 0, IsB = 0; double pFong = info.Material.FongCoeff; // foreach (Light L in lights) { Vector3D V = new Vector3D(info.CrossPoint, L.Position); //направление на источник L V *= (1 / V.Length); if (this.IsVisible(L, info.CrossPoint)) { double distance = VectorOperations.Distance(L.Position, info.CrossPoint); double attenuation = L.Attenuation(distance); if (info.Material.Diffusion > 0) //для предмета задано свойство диффузного отражения { double cos = VectorOperations.Cos(info.Normal, V); if (cos < 0) { cos = 0; } IdR += L.Color.R * cos / attenuation; IdG += L.Color.G * cos / attenuation; IdB += L.Color.B * cos / attenuation; } if (info.Material.Specularity > 0) //для предмета задано свойство зеркального отражения { Vector3D reflected; if (VectorOperations.ReflectedVector(info.Normal, r.Direction, out reflected)) { double cos = VectorOperations.Cos(V, reflected); if (cos < 0) { cos = 0; } IsR += L.Color.R * Math.Pow(cos, pFong) / attenuation; IsG += L.Color.G * Math.Pow(cos, pFong) / attenuation; IsB += L.Color.B * Math.Pow(cos, pFong) / attenuation; } } } } R += info.Material.Diffusion * IdR * info.Material.Color.R / 255; G += info.Material.Diffusion * IdG * info.Material.Color.G / 255; B += info.Material.Diffusion * IdB * info.Material.Color.B / 255; R += info.Material.Specularity * IsR; G += info.Material.Specularity * IsG; B += info.Material.Specularity * IsB; if (info.Material.Reflection > 0) { Vector3D reflected; if (VectorOperations.ReflectedVector(info.Normal, r.Direction, out reflected)) { Ray reflectedRay = new Ray(info.CrossPoint, reflected); Color reflectedColor = this.RayTracing(reflectedRay, depth + 1); R += info.Material.Reflection * reflectedColor.R; G += info.Material.Reflection * reflectedColor.G; B += info.Material.Reflection * reflectedColor.B; } } if (info.Material.Transparency > 0) { double n12 = info.Material.RefractiveIndex; Vector3D refracted; if (VectorOperations.RefractedVector(info.Normal, r.Direction, n12, out refracted)) { Ray refractedRay = new Ray(info.CrossPoint, refracted); Color refractedColor = this.RayTracing(refractedRay, depth + 1); R += info.Material.Transparency * refractedColor.R; G += info.Material.Transparency * refractedColor.G; B += info.Material.Transparency * refractedColor.B; } } R += info.Material.Color.R * Ka; G += info.Material.Color.G * Ka; B += info.Material.Color.B * Ka; return(Color.FromArgb(Math.Min((int)R, 255), Math.Min((int)G, 255), Math.Min((int)B, 255))); }