public void Draw(int startWidth, int endWidth, int startHeight, int endHeight, int height, int width, ref byte[] rgbValues) { for (int j = startHeight; j < endHeight; j++) { for (int i = startWidth; i < endWidth; i++) { double x = (2 * (i + 0.5) / width - 1) * Math.Tan(field / 2) * width / height; double y = -(2 * (j + 0.5) / height - 1) * Math.Tan(field / 2); Ray beam = new Ray(new Point(0, 0, 0), new Point(x, y, 1)); SetPixel(i, j, ref rgbValues, width, ColorHandler.VectorToColor(TraceRay(beam, 0))); } } }
private Vector TraceRay(Ray beam, int depth) { Vector result = new Vector(0.2, 0.7, 0.8); double diffuseIntensity = 0; double specularIntensity = 0; Material material = new Material(); Vector normal = new Vector(0, 0, 0); Point litSpot = new Point(0, 0, 0); /*Возвращаем фоновый цвет, если на пути луча нет объекта*/ if (depth >= maxDepth || !ShapeMet(beam, ref litSpot, ref normal, ref material, out var shape)) { return(result); } else { result = material.Pattern.ColorFromPoint(shape.Translate(litSpot)); } Material tmpMaterial = new Material(); Vector shadowNormal = new Vector(0, 0, 0); Vector reflectColor = new Vector(0, 0, 0); if (material.Albedo[2] != 0) //Проверка объекта на зеркальность { Point reflectSpot = new Point(litSpot.X, litSpot.Y, litSpot.Z); Vector reflectDir = Reflect(beam.Direction, normal); /*Сдвиг освещенной точки вдоль нормали, чтобы избежать повторного пересечения с тем же объектом*/ Offset(reflectSpot, reflectDir, normal); Ray reflect = new Ray(reflectSpot, reflectDir); reflectColor = TraceRay(reflect, depth + 1); } Vector refractColor = new Vector(0, 0, 0); if (material.Albedo[3] != 0) //Проверка объекта на прозрачность { Vector refractDir = Refract(beam.Direction, normal, material.RefractiveIndex); if (refractDir.Length != 0) { Point refractSpot = new Point(litSpot.X, litSpot.Y, litSpot.Z); /*Сдвиг освещенной точки вдоль нормали, чтобы избежать повторного пересечения с тем же объектом*/ Offset(refractSpot, refractDir, normal); Ray refract = new Ray(refractSpot, refractDir); refractColor = TraceRay(refract, depth + 1); } } Vector illuminationColor = new Vector(0, 0, 0); foreach (var light in lights) { Vector lightColor = new Vector(1, 1, 1); double intensity = light.Intensity; Vector lightDir = new Vector(litSpot, light.Position).Normalize(); Point shadowSpot = new Point(litSpot.X, litSpot.Y, litSpot.Z); Offset(shadowSpot, lightDir, normal); // Сдвиг освещенной точки вдоль нормали, чтобы избежать повторного пересечения с тем же объектом Ray shadowRay = new Ray(shadowSpot, lightDir); /*Вычисление теней*/ if (ShapeMet(shadowRay, ref shadowSpot, ref shadowNormal, ref tmpMaterial, out var shadowShape)) { if (tmpMaterial.Albedo[3] == 0) // Проверка объекта но прозрачность { continue; } intensity *= tmpMaterial.Albedo[3]; // Приглушение света в соответствии с прозрачностью объекта if (tmpMaterial.Albedo[0] != 0) // Придание лучу цвета прозрачного объекта { lightColor = tmpMaterial.Pattern.ColorFromPoint(shadowSpot) * tmpMaterial.Albedo[3]; } } else { specularIntensity += Math.Pow(Math.Max(0, Reflect(lightDir, normal) * beam.Direction), // Вычисление интенсивности бликов material.SpecularExponent) * light.Intensity; } illuminationColor += lightColor; // Суммарный цвет освещения в точке diffuseIntensity += Math.Max(0, intensity * (lightDir * normal)); } ColorHandler.NormalizeColor(ref illuminationColor); // Приведение цвета освещения к стандартному виду result = ColorHandler.Calculate(illuminationColor, result, reflectColor, refractColor, diffuseIntensity, specularIntensity, material); ColorHandler.NormalizeColor(ref result); // Предотвращение засветки return(result); }