Понятия фрактал и фрактальная геометрия, появившиеся в конце 70-х, с середины 80-х прочно вошли в обиход математиков и программистов. Слово фрактал образовано от латинского fractus и в переводе означает состоящий из фрагментов. Оно было предложено Бенуа Мандельбротом в 1975 году для обозначения нерегулярных, но самоподобных структур, которыми он занимался. Рождение фрактальной геометрии принято связывать с выходом в 1977 году книги Мандельброта `The Fractal Geometry of Nature'. В его работах использованы научные результаты других ученых, работавших в период 1875-1925 годов в той же области (Пуанкаре, Фату, Жюлиа, Кантор, Хаусдорф). Но только в наше время удалось объединить их работы в единую систему.
Роль фракталов в машинной графике сегодня достаточно велика. Они приходят на помощь, например, когда требуется, с помощью нескольких коэффициентов, задать линии и поверхности очень сложной формы. С точки зрения машинной графики, фрактальная геометрия незаменима при генерации искусственных облаков, гор, поверхности моря. Фактически найден способ легкого представления сложных неевклидовых объектов, образы которых весьма похожи на природные.
Одним из основных свойств фракталов является самоподобие. В самом простом случае небольшая часть фрактала содержит информацию о всем фрактале. Определение фрактала, данное Мандельбротом, звучит так: "Фракталом называется структура, состоящая из частей, которые в каком-то смысле подобны целому".
В качестве примера рассмотрим множество Мандельброта. Алгоритм его построения достаточно прост и основан на простом итеративном выражении: Z[i+1] = Z[i] * Z[i] + C, где Zi и C - комплексные переменные. Итерации выполняются для каждой стартовой точки с прямоугольной или квадратной области - подмножестве комплексной плоскости. Итерационный процесс продолжается до тех пор, пока Z[i] не выйдет за пределы окружности радиуса 2, центр которой лежит в точке (0,0), (это означает, что аттрактор динамической системы находится в бесконечности), или после достаточно большого числа итераций (например 200-500) Z[i] сойдется к какой-нибудь точке окружности. В зависимости от количества итераций, в течении которых Z[i] оставалась внутри окружности, можно установить цвет точки C (если Z[i] остается внутри окружности в течение достаточно большого количества итераций, итерационный процесс прекращается и эта точка растра окрашивается в черный цвет).
За основу мы взяли проект Mandelbrot-Set-in-Verilog, и адаптировали для нашей платы VE-XC6SLX9.
Основной модуль проекта представлен ниже:
Verilog Code:
module vga( input clk, input reset, input zoomin, input [3:0] switches, output red, output green, output blue, output reg hsync, output reg vsync, /* Outputs to RAM */ inout [5:0] ram_data, output [18:0] ram_addr, output ram_write, output ram_output, output ram_chipenable ); //Переменные reg [3:0]direction; //Направление перемещения reg [3:0]old_direction; reg [3:0]zoom; //Увеличение reg [3:0]old_zoom; reg [3:0]shift; //Сдвиг reg [31:0]write_cnt; reg [31:0]zoom_cnt; reg [7:0]deb; reg readSwitch; reg writeSwitch; reg [9:0] posx; //Координаты экрана reg [9:0] posy; reg syncing; wire vclk; video_clk my_vclk(.clk(clk), .reset(~reset), .vclk(vclk)); //Параметры горизонтальной развертки parameter HD = 10'd640; //Видимые пиксели parameter HFP = 10'd16; //Пикселей на переднюю площадку кадрового гасящего импульса parameter HS = 10'd96; //Пикселей на кадровый синхроимпульс parameter HBP = 10'd48; //Пикселей на заднюю площадку кадрового гасящего импульса //Параметры вертикальной развертки parameter VD = 10'd480; //Видимые линии parameter VFP = 10'd10; //Строк на переднюю площадку строчного гасящего импульса parameter VS = 10'd2; //Строк на строчный синхроимпульс parameter VBP = 10'd33; //Строк на заднююплощадку строчного гасящего импульса //Блок управления always @ (posedge clk) begin //Управление масштабом приближения if(zoom_cnt>0) begin zoom_cnt = zoom_cnt - 1; end if(zoomin==0 && zoom_cnt==0) begin zoom_cnt = 40000000; zoom = zoom + 1; end if(old_zoom != zoom) begin old_zoom <= zoom; write_cnt <= 0; end //Управление направлением смещения direction = switches[3:0]; if(old_direction != direction) begin old_direction <= direction; write_cnt <= 0; end if(write_cnt < 200000000) begin write_cnt <= write_cnt + 1; readSwitch <= 0; writeSwitch <= 1; end else begin readSwitch <= 1; writeSwitch <= 0; end end //Блок вывода изображения always @ (posedge vclk, negedge reset) begin if (~reset) begin posx = HD; posy = VD; hsync = 0; vsync = 0; syncing = 1; end else begin posx = posx + 1'b1; if (syncing) begin hsync = ((HD+HFP) <= posx) && (posx < (HD+HFP+HS)); if (posx == (HD+HFP+HS+HBP)) //Конец линии begin posx = 10'b0; posy = posy + 1'b1; end vsync = ((VD+VFP) < posy) && (posy < (VD+VFP+VS)); if (posy == (VD+VFP+VS+VBP)) //Конец кадра begin posy = 10'b0; end syncing = (posy >= VD) || (posx >= HD); end else begin if (posx == HD) //Первые пиксели за пределами кадра syncing = 1; end end end wire [18:0] write_address; wire [2:0] write_data; wire write_enable; wire [18:0] read_address; wire [2:0] read_data; assign read_address = {posy[8:0],posx[9:0]}; //Блок записи/чтения видеопамяти ram graphic_ram( .clk(clk), .reset(~reset), .read_addr(read_address), .read_data(read_data), .write_addr(write_address), .write_data(write_data), .write_enable(write_enable), .ram_data(ram_data), .ram_addr(ram_addr), .ram_write(ram_write), .ram_output(ram_output), .ram_chipenable(ram_chipenable), .readSwitch(readSwitch), .writeSwitch(writeSwitch) ); //Блок формирования множества мандельброта mandelbrot mandel( .iteration_clk(vclk/*read_cycle*/), .reset(~reset), .direction(direction), .zoom(zoom), .write_address(write_address), .write_data(write_data), .write_enable(write_enable), .debug_pos(deb) ); wire [2:0] dot; assign dot = read_data + shift; assign red = syncing ? 0 : dot[2]; assign green = syncing ? 0 : dot[1]; assign blue = syncing ? 0 : dot[0]; endmodule
- vga — Основной модуль проекта. Генерирует VGA развертку, управляет параметрами отображения и собирает во едино остальные модули.
- ram — модуль управления памятью.
- mandelbrot — генератор множества Мандельброта
Управление отображением осуществляется с помощью кнопок Key1- сброс, Key2- приближение. А также перемещение изображения с помошью клавиатуры, как в нашем примере Первый проект для VE-XC6SLX9. Часть 3.
Сгенерированное множество Манделброта:
Проект генератора множества Мандельброта: mandelbrot.zip