Нечеткие линии для рисования теней в C#
Один из способов рисования теней на C# - рисовать объект, сдвинутый вниз и вправо, светло-серого цвета, как показано слева на рисунке выше. Это работает довольно хорошо, но не совсем убедительно, потому что края тени слишком четкие. Реальные тени размываются возле краев.
Изображение справа использует другой подход для рисования теней и дает немного лучший результат. Чтобы нарисовать тени, он сначала рисует толстую полупрозрачную линию. Затем он рисует ряд строк, которые последовательно тоньше и более непрозрачны. Это делает теневую линию слабой на краях и темнее посередине.
Чтобы создать хороший результат, этот пример рисует черные линии тени с максимальной непрозрачностью в середине всего 10.
Следующий код показывает, как пример рисует изображение справа.
// Нарисуйте смайлик с нечеткой теневой строкой. private void picFuzzy_Paint(object sender, PaintEventArgs e) { e.Graphics.SmoothingMode = SmoothingMode.AntiAlias; DrawBackground(e.Graphics, picFuzzy.ClientSize); // Создаем смайлик. using (GraphicsPath path = MakeSmileyPath(picThin.ClientSize)) { // Рисуем тень. e.Graphics.TranslateTransform(6, 6); DrawPathWithFuzzyLine(path, e.Graphics, Color.Black, 200, 20, 2); e.Graphics.ResetTransform(); // Нарисуем лицо. using (Pen thick_pen = new Pen(Color.Black, 3)) { e.Graphics.DrawPath(thick_pen, path); } } }
Код вызывает метод MakeSmileyPath, чтобы сделать GraphicsPath, содержащий эллипсы и дугу, составляющие смайлик. Этот метод прост, поэтому он не показан здесь. Вниз, чтобы увидеть, как это работает.
В коде применяется трансляция объекта Graphics для перемещения результатов 6 пикселей вправо и вниз. Затем он вызывает метод DrawPathWithFuzzyLine для рисования теней с помощью нечеткой ручки. Код сбрасывает преобразование объекта Graphics и снова чертит путь в черном.
В следующем коде показан метод DrawPathWithFuzzyLine.
// Используйте серию перьев с уменьшающейся шириной и // увеличение непрозрачности для рисования GraphicsPath. private void DrawPathWithFuzzyLine(GraphicsPath path, Graphics gr, Color base_color, int max_opacity, int width, int opaque_width) { // Количество ручек, которые мы будем использовать. int num_steps = width - opaque_width + 1; // Изменение альфы между перьями. float delta = (float)max_opacity / num_steps / num_steps; // Начальная альфа. float alpha = delta; for (int thickness = width; thickness >= opaque_width; thickness--) { Color color = Color.FromArgb( (int)alpha, base_color.R, base_color.G, base_color.B); using (Pen pen = new Pen(color, thickness)) { pen.EndCap = LineCap.Round; pen.StartCap = LineCap.Round; gr.DrawPath(pen, path); } alpha += delta; } }
Параметр width дает общую ширину нечеткой линии. Параметр opaque_width дает ширину центра линии, где он имеет максимальную непрозрачность. Например, если width = 20 и opaque_width = 10, метод будет рисовать линию шириной 20 пикселей с полосой шириной 10 пикселей в середине на с высокой непрозрачностью и затем сбрасыванием непрозрачности по краям.
Этот код вычисляет количество строк, которые он должен нарисовать, и количество, при котором непрозрачность должна изменяться между каждой строкой. Затем он проходит через значения толщины линии, которые он должен рисовать. Для каждой строки он создает ручку с соответствующей непрозрачностью, рисует путь с помощью этого пера и увеличивает непрозрачность на соответствующую сумму.
Обратите внимание, что центр линии перерисовывается каждый раз, когда нарисована новая строка. Это означает, что внутренние части линии становятся темнее каждый раз, когда они нарисованы.