Визуальная электроника

Понятия фрактал и фрактальная геометрия, появившиеся в конце 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] остается внутри окружности в течение достаточно большого количества итераций, итерационный процесс прекращается и эта точка растра окрашивается в черный цвет).

pic1

За основу мы взяли проект Mandelbrot-Set-in-Verilog, и адаптировали для нашей платы VE-XC6SLX9.

Основной модуль проекта представлен ниже:

Verilog Code:
  1. module vga(
  2. input clk,
  3. input reset,
  4. input zoomin,
  5. input [3:0] switches,
  6. output red,
  7. output green,
  8. output blue,
  9. output reg hsync,
  10. output reg vsync,
  11. /* Outputs to RAM */
  12. inout [5:0] ram_data,
  13. output [18:0] ram_addr,
  14. output ram_write,
  15. output ram_output,
  16. output ram_chipenable
  17. );
  18.  
  19. //Переменные
  20. reg [3:0]direction; //Направление перемещения
  21. reg [3:0]old_direction;
  22. reg [3:0]zoom; //Увеличение
  23. reg [3:0]old_zoom;
  24. reg [3:0]shift; //Сдвиг
  25. reg [31:0]write_cnt;
  26. reg [31:0]zoom_cnt;
  27. reg [7:0]deb;
  28.  
  29. reg readSwitch;
  30. reg writeSwitch;
  31.  
  32. reg [9:0] posx; //Координаты экрана
  33. reg [9:0] posy;
  34.  
  35. reg syncing;
  36.  
  37. wire vclk;
  38. video_clk my_vclk(.clk(clk), .reset(~reset), .vclk(vclk));
  39.  
  40. //Параметры горизонтальной развертки
  41. parameter HD = 10'd640; //Видимые пиксели
  42. parameter HFP = 10'd16; //Пикселей на переднюю площадку кадрового гасящего импульса
  43. parameter HS = 10'd96; //Пикселей на кадровый синхроимпульс
  44. parameter HBP = 10'd48; //Пикселей на заднюю площадку кадрового гасящего импульса
  45.  
  46. //Параметры вертикальной развертки
  47. parameter VD = 10'd480; //Видимые линии
  48. parameter VFP = 10'd10; //Строк на переднюю площадку строчного гасящего импульса
  49. parameter VS = 10'd2; //Строк на строчный синхроимпульс
  50. parameter VBP = 10'd33; //Строк на заднююплощадку строчного гасящего импульса
  51.  
  52. //Блок управления
  53. always @ (posedge clk)
  54. begin
  55.  
  56. //Управление масштабом приближения
  57. if(zoom_cnt>0)
  58. begin
  59. zoom_cnt = zoom_cnt - 1;
  60. end
  61.  
  62. if(zoomin==0 && zoom_cnt==0)
  63. begin
  64. zoom_cnt = 40000000;
  65. zoom = zoom + 1;
  66. end
  67.  
  68. if(old_zoom != zoom)
  69. begin
  70. old_zoom <= zoom;
  71. write_cnt <= 0;
  72. end
  73.  
  74. //Управление направлением смещения
  75. direction = switches[3:0];
  76. if(old_direction != direction)
  77. begin
  78. old_direction <= direction;
  79. write_cnt <= 0;
  80. end
  81.  
  82. if(write_cnt < 200000000)
  83. begin
  84. write_cnt <= write_cnt + 1;
  85. readSwitch <= 0;
  86. writeSwitch <= 1;
  87. end
  88. else
  89. begin
  90. readSwitch <= 1;
  91. writeSwitch <= 0;
  92. end
  93. end
  94.  
  95. //Блок вывода изображения
  96. always @ (posedge vclk, negedge reset)
  97. begin
  98. if (~reset)
  99. begin
  100. posx = HD;
  101. posy = VD;
  102. hsync = 0;
  103. vsync = 0;
  104. syncing = 1;
  105. end
  106. else
  107. begin
  108. posx = posx + 1'b1;
  109.  
  110. if (syncing)
  111. begin
  112.  
  113. hsync = ((HD+HFP) <= posx) && (posx < (HD+HFP+HS));
  114.  
  115.  
  116. if (posx == (HD+HFP+HS+HBP)) //Конец линии
  117. begin
  118. posx = 10'b0;
  119. posy = posy + 1'b1;
  120. end
  121.  
  122.  
  123. vsync = ((VD+VFP) < posy) && (posy < (VD+VFP+VS));
  124.  
  125. if (posy == (VD+VFP+VS+VBP)) //Конец кадра
  126. begin
  127. posy = 10'b0;
  128. end
  129.  
  130.  
  131. syncing = (posy >= VD) || (posx >= HD);
  132. end
  133. else
  134. begin
  135. if (posx == HD) //Первые пиксели за пределами кадра
  136. syncing = 1;
  137.  
  138. end
  139. end
  140. end
  141.  
  142.  
  143. wire [18:0] write_address;
  144. wire [2:0] write_data;
  145. wire write_enable;
  146.  
  147. wire [18:0] read_address;
  148. wire [2:0] read_data;
  149. assign read_address = {posy[8:0],posx[9:0]};
  150.  
  151. //Блок записи/чтения видеопамяти
  152. ram graphic_ram(
  153. .clk(clk),
  154. .reset(~reset),
  155. .read_addr(read_address),
  156. .read_data(read_data),
  157. .write_addr(write_address),
  158. .write_data(write_data),
  159. .write_enable(write_enable),
  160. .ram_data(ram_data),
  161. .ram_addr(ram_addr),
  162. .ram_write(ram_write),
  163. .ram_output(ram_output),
  164. .ram_chipenable(ram_chipenable),
  165. .readSwitch(readSwitch),
  166. .writeSwitch(writeSwitch)
  167. );
  168.  
  169. //Блок формирования множества мандельброта
  170. mandelbrot mandel(
  171. .iteration_clk(vclk/*read_cycle*/),
  172. .reset(~reset),
  173. .direction(direction),
  174. .zoom(zoom),
  175. .write_address(write_address),
  176. .write_data(write_data),
  177. .write_enable(write_enable),
  178. .debug_pos(deb)
  179. );
  180.  
  181.  
  182. wire [2:0] dot;
  183. assign dot = read_data + shift;
  184.  
  185. assign red = syncing ? 0 : dot[2];
  186. assign green = syncing ? 0 : dot[1];
  187. assign blue = syncing ? 0 : dot[0];
  188.  
  189. endmodule
  • vga — Основной модуль проекта. Генерирует VGA развертку, управляет параметрами отображения и собирает во едино остальные модули.
  • ram — модуль управления памятью.
  • mandelbrot — генератор множества Мандельброта

Управление отображением осуществляется с помощью кнопок Key1- сброс, Key2- приближение. А также перемещение изображения с помошью клавиатуры, как в нашем примере Первый проект для VE-XC6SLX9. Часть 3.

Сгенерированное множество Манделброта:

pic2

Проект генератора множества Мандельброта: mandelbrot.zip

Добавить комментарий