10 Commits

101 changed files with 2961 additions and 74 deletions

5
.gitignore vendored
View File

@@ -1,3 +1,6 @@
* *
!.gitignore !.gitignore
!lab1 !lab1
!lab2
!lab3
!lab4

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 501 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1017 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 562 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 340 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 548 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 250 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 149 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 336 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 386 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 575 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 511 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 566 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 551 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 781 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 801 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 273 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 490 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 391 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 610 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 699 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 422 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 227 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 416 KiB

View File

@@ -373,7 +373,48 @@
\textbf{Материал:} Зажим изготовлен из пластика и покрыта красной краской. Внутри ободков находятся кусочки проволоки, за счёт которых зажим запоминает приданную ему форму. Надпись со сроком годности нанесена белой краской. \textbf{Материал:} Зажим изготовлен из пластика и покрыта красной краской. Внутри ободков находятся кусочки проволоки, за счёт которых зажим запоминает приданную ему форму. Надпись со сроком годности нанесена белой краской.
\textbf{Особенности:} Объект имеет уникальную форму, которая была придана ему вручную специально для этой лабораторной работы. Также уникальной особенностью является надпись на объекте. В ней содержится срок годности и номер бригады -- <<09.03.25.2 - 2>>. \textbf{Особенности:} Объект имеет уникальную форму, которая была придана ему вручную специально для этой лабораторной работы. Также уникальной особенностью является надпись на объекте. В ней содержится срок годности и номер бригады -- <<09.03.25.2 - 1>>.
\newpage
\subsection{Объект моделирования №3}
Объектом №3 является сломанная линейка (Рис.~\ref{fig:ruler/real/front}-\ref{fig:ruler/real/back-side}).
\begin{figure}[h!]
\centering
\includegraphics[width=0.2\linewidth]{img/ruler/real/front.jpg}
\caption{Объект моделирования №3, вид с лицевой стороны.}
\label{fig:ruler/real/front}
\end{figure}
\begin{figure}[h!]
\centering
\includegraphics[width=0.2\linewidth]{img/ruler/real/back.jpg}
\caption{Объект моделирования №3, вид с обратной стороны.}
\label{fig:ruler/real/back}
\end{figure}
\newpage
\begin{figure}[h!]
\centering
\includegraphics[width=0.6\linewidth]{img/ruler/real/side.jpg}
\caption{Объект моделирования №3, вид сбоку на лицевую сторону.}
\label{fig:ruler/real/side}
\end{figure}
\begin{figure}[h!]
\centering
\includegraphics[width=0.5\linewidth]{img/ruler/real/back-side.jpg}
\caption{Объект моделирования №3, вид сбоку на обратную сторону.}
\label{fig:ruler/real/back-side}
\end{figure}
\textbf{Форма:} Линейка имеет форму удлинённой плоской пластины с прямыми параллельными краями. Торец, на котором нанесены измерительные деления, скошен.
\textbf{Материал:} Линейка изготовлена из пластика и покрыта чёрной краской. Измерительные деления и отметки нанесены белой краской.
\textbf{Особенности:} Линейка имеет уникальный излом. Также она слегка погнута по всей длине. Видны следы продолжительной эксплуатации -- в некоторых местах стёрта краска, а в некоторых видны царапины.
\newpage \newpage
\section{Описание технологии разработки моделей} \section{Описание технологии разработки моделей}
@@ -389,7 +430,7 @@
\subsubsection{Моделирование} \subsubsection{Моделирование}
Нажимаем на цифру 7 на Num Pad, чтобы перейти на вид сверху. Затем нажимаем Shift + A и в разделе Image выбираем Reference. В открывшемся окне проводника выбираем изображение лицевой стороны покерной фишки и нажимаем Add~Image~(Рис.~\ref{fig:chip/modeling/1-add-reference}). Добавим изображение фишки в сцену, чтобы использовать его как визуальный ориентир. Нажимаем на цифру 7 на Num Pad (или выбираем "Top" в меню View - Viewpoint), чтобы перейти на вид сверху. Затем нажимаем сочетание клавиш Shift + A (либо открываем список Add в верхнем меню) и в разделе Image выбираем Reference. В открывшемся окне проводника выбираем изображение лицевой стороны покерной фишки и нажимаем Add~Image~(Рис.~\ref{fig:chip/modeling/1-add-reference}).
\begin{figure}[h!] \begin{figure}[h!]
\centering \centering
@@ -399,25 +440,25 @@
\end{figure} \end{figure}
\newpage \newpage
Нажимаем Shift + A и в разделе Mesh выбираем Cylinder (Рис.~\ref{fig:chip/modeling/2-add-cylinder}). Создадим цилиндрическую основу для будущей фишки. Нажимаем сочетание клавиш Shift + A (либо используем меню Add) и в разделе Mesh выбираем Cylinder (Рис.~\ref{fig:chip/modeling/2-add-cylinder}).
\begin{figure}[h!] \begin{figure}[h!]
\centering \centering
\includegraphics[width=1\linewidth]{img/chip/modeling/2-add-cylinder.png} \includegraphics[width=1\linewidth]{img/chip/modeling/2-add-cylinder.png}
\caption{Добавление цилиндра.} \caption{Добавление цилиндра.}
\label{fig:chip/modeling/2-add-cylinder} \label{fig:chip/modeling/2-add-cylinder}
\end{figure} \end{figure}
Нажимаем Alt + Z, чтобы перейти в режим прозрачности и видеть изображение фишки сквозь цилиндр. Активируем режим прозрачности для точного совмещения объектов. Нажимаем сочетание клавиш Alt + Z (или выбираем "X-Ray" в правом нижнем меню Viewport Shading), чтобы видеть изображение сквозь цилиндр.
\begin{figure}[h!] \begin{figure}[h!]
\centering \centering
\includegraphics[width=0.5\linewidth]{img/chip/modeling/3-alt-z.png} \includegraphics[width=0.5\linewidth]{img/chip/modeling/3-alt-z.png}
\caption{Режим прозрачности.} \caption{Режим прозрачности.}
\label{fig:chip/modeling/3-alt-z} \label{fig:chip/modeling/3-alt-z}
\end{figure} \end{figure}
Выбираем изображение, а затем с помощью масштабирования (клавиша S) и смещения (клавиша G) выравниваем центр цилиндра с центром фишки на изображении. Перемещаем курсор с зажатой клавишей Shift для более точного позиционирования. Результат на Рис.~\ref{fig:chip/modeling/4-positioning}. Подгоним размеры и позицию изображения под геометрию цилиндра. Выбираем изображение, затем используем масштабирование (клавиша S) и перемещение (клавиша G), совмещая центр цилиндра с центром фишки на референсе. Для точной настройки перемещаем курсор с зажатой клавишей Shift. Результат на Рис.~\ref{fig:chip/modeling/4-positioning}.
\begin{figure}[h!] \begin{figure}[h!]
\centering \centering
@@ -427,7 +468,7 @@
\end{figure} \end{figure}
\newpage \newpage
Нажимаем на цилиндр и переходим в режим редактирования (клавиша Tab). В режиме выбора граней (клавиша 3) и с зажатой клавишей Shift выбираем верхнюю и нижнюю грани цилиндра (Рис.~\ref{fig:chip/modeling/5-select-faces}). Подготовим грани для формирования ложбинки. Нажимаем на цилиндр и переходим в режим редактирования (клавиша Tab или кнопка Edit Mode в верхнем меню). В режиме выбора граней (клавиша 3 или иконка Face Select) с зажатой клавишей Shift выбираем верхнюю и нижнюю грани цилиндра (Рис.~\ref{fig:chip/modeling/5-select-faces}).
\begin{figure}[h!] \begin{figure}[h!]
\centering \centering
@@ -437,16 +478,16 @@
\end{figure} \end{figure}
\newpage \newpage
Возвращаемся на вид сверху (клавиша 7 на Num Pad). Нажимаем клавишу I, чтобы добавить внтреннюю грань. Выравниваем её по внешней стороне ложбинки на фишке, ориентируясь на изображения. При этом перемещаем курсор с зажатой клавишей Shift для более точного позиционирования. Создадим контур внешнего края ложбинки. Возвращаемся на вид сверху (клавиша 7 на Num Pad). Нажимаем клавишу I (или выбираем Inset Faces в меню Mesh > Faces), чтобы добавить внутреннюю грань. Выравниваем её по внешнему краю ложбинки, используя референс для точности позиционирования.
\begin{figure}[h!] \begin{figure}[h!]
\centering \centering
\includegraphics[width=0.5\linewidth]{img/chip/modeling/6-insert-faces.png} \includegraphics[width=0.5\linewidth]{img/chip/modeling/6-insert-faces.png}
\caption{Добавление новых рёбер на верхней и нижней гранях цилиндра.} \caption{Добавление новых рёбер на верхней и нижней гранях цилиндра.}
\label{fig:chip/modeling/6-insert-faces} \label{fig:chip/modeling/6-insert-faces}
\end{figure} \end{figure}
Снова нажимаем на клавишу I. Новую грань выравниваем по внутренней стороне ложбинки на фишке (Рис.~\ref{fig:img/chip/modeling/7-insert-inner-faces}). Сформируем внутренний контур ложбинки. Снова нажимаем клавишу I и создаём вторую грань, выравнивая её по внутреннему краю ложбинки (Рис.~\ref{fig:img/chip/modeling/7-insert-inner-faces}).
\begin{figure}[h!] \begin{figure}[h!]
\centering \centering
@@ -455,36 +496,37 @@
\label{fig:img/chip/modeling/7-insert-inner-faces} \label{fig:img/chip/modeling/7-insert-inner-faces}
\end{figure} \end{figure}
Изображение больше не понадобится и его можно скрыть. Возвращаемся в объектный режим (клавиша Tab), нажимаем на изображение, а затем нажимаем на клавишу H. Уберём референс из рабочей области для удобства. Возвращаемся в объектный режим (клавиша Tab), выбираем изображение и нажимаем клавишу H (или используем меню Object > Show/Hide > Hide Selected).
Нажимаем на цилиндр, а затем нажимаем на клавишу N, чтобы открыть боковое меню с размерами модели. В разделе Dimensions указываем реальные размеры изделия. В поле X и Y указываем значения 40mm, в поле Z указываем 2mm. Затем нажимаем точку на Num Pad, чтобы приблизиться к модели (Рис.~\ref{fig:chip/modeling/8-sizing}). Зададим реальные размеры для модели. Нажимаем на цилиндр, затем клавишу N (или открываем меню View > Sidebar). В разделе Dimensions указываем: X/Y = 40mm, Z = 2mm. Нажимаем точку на Num Pad (или кнопку Frame Selected в правом верхнем углу) для фокусировки на модели (Рис.~\ref{fig:chip/modeling/8-sizing}).
\begin{figure}[h!] \begin{figure}[h!]
\centering \centering
\includegraphics[width=0.9\linewidth]{img/chip/modeling/8-sizing.png} \includegraphics[width=0.8\linewidth]{img/chip/modeling/8-sizing.png}
\caption{Указание размеров фишки.} \caption{Указание размеров фишки.}
\label{fig:chip/modeling/8-sizing} \label{fig:chip/modeling/8-sizing}
\end{figure} \end{figure}
Нажимаем сочетание клавиш Ctrl + A и в появившемся меню выбираем вариант Scale (Рис.~\ref{fig:chip/modeling/9-scale}). Применим масштабирование для корректной работы с размерами. Нажимаем сочетание клавиш Ctrl + A (или выбираем Apply > Scale в меню Object) и выбираем Scale (Рис.~\ref{fig:chip/modeling/9-scale}).
\begin{figure}[h!] \begin{figure}[h!]
\centering \centering
\includegraphics[width=0.7\linewidth]{img/chip/modeling/9-scale.png} \includegraphics[width=0.6\linewidth]{img/chip/modeling/9-scale.png}
\caption{Применение функции Scale к модели.} \caption{Применение функции Scale к модели.}
\label{fig:chip/modeling/9-scale} \label{fig:chip/modeling/9-scale}
\end{figure} \end{figure}
Переходим в режим редактирования (клавиша Tab). С зажатой клавишей Alt нажимаем на грань внутри ложбинки, чтобы выделить все грани ложбинки. Нажимаем на клавишу 1 на Num Pad, чтобы переключиться на вид сбоку. Затем нажимаем на клавишу E, чтобы создать углубление. В боковом меню (клавиша N) в разделе Median в поле Z указываем значение 0.6mm. Затем нажимаем сочетание клавиш Ctrl + 7 на Num Pad, чтобы переключиться на вид снизу. Аналогичным образом выделяем грани ложбинки, переключаемся на вид сбоку и создаём углубление. В боковом меню в разделе Median в поле Z указываем значение -0.6mm (Рис.~\ref{fig:chip/modeling/10-trench}). \newpage
Создадим углубления для ложбинки. В режиме редактирования (клавиша Tab) с зажатой Alt выделяем грани ложбинки. Переключаемся на вид сбоку (клавиша 1 на Num Pad), нажимаем E (или Extrude в меню Mesh), задаём Z = 0.6mm в панели Median. Повторяем для нижней части: вид снизу (Ctrl + 7), выделение граней, углубление с Z = -0.6mm (Рис.~\ref{fig:chip/modeling/10-trench}).
\begin{figure}[h!] \begin{figure}[h!]
\centering \centering
\includegraphics[width=0.9\linewidth]{img/chip/modeling/10-trench.png} \includegraphics[width=0.9\linewidth]{img/chip/modeling/10-trench.png}
\caption{Добавление ложбинки.} \caption{Формирование углублений ложбинки.}
\label{fig:chip/modeling/10-trench} \label{fig:chip/modeling/10-trench}
\end{figure} \end{figure}
На этом этапе можно отключить режим прозрачности (Alt + z). Переходим в объектный режим (клавиша Tab) и в разделе Modifiers добавляем модификатор Subdivision Surface из раздела Generate. В параметрах Levels Viewport и Render указываем значение 3. Нажимаем на цилиндр правой кнопкой мыши и выбираем пункт Shade Smooth (Рис.~\ref{fig:chip/modeling/11-shade-smooth}). Сгладим геометрию для реалистичного вида. Отключаем X-Ray (Alt + Z), в объектном режиме добавляем модификатор Subdivision Surface (меню Modifier Properties > Add Modifier). Устанавливаем Levels Viewport/Render = 3. Применяем Shade Smooth через контекстное меню объекта (Рис.~\ref{fig:chip/modeling/11-shade-smooth}).
\begin{figure}[h!] \begin{figure}[h!]
\centering \centering
@@ -493,7 +535,7 @@
\label{fig:chip/modeling/11-shade-smooth} \label{fig:chip/modeling/11-shade-smooth}
\end{figure} \end{figure}
На данном этапе углы модели выглядят слишком скруглёнными. Переходим в режим редактирования (клавиша Tab). Нажимаем сочетание клавиш Ctrl + R и создаём новые грани, почти в плотную к граням, на которых происходит перепад высот. Создаём такие же грани в ложбинке. В режиме выбора поверхностей (клавиша 3) нажимаем на центральную часть фишки и нажимаем на клавишу I, чтобы создать новую грань в центральной части фишки. Затем переключаемся на вид снизу (Ctrl + 7 на Num Pad) и проделываем те же операции (Рис.~\ref{fig:chip/modeling/12-new-edges}). Добавим контрольные рёбра для сохранения чётких граней. В режиме редактирования используем инструмент Loop Cut (сочетание клавиш Ctrl + R) возле перепадов высот. На верхней и нижней поверхностях создаём дополнительные грани инструментом Inset (клавиша I) (Рис.~\ref{fig:chip/modeling/12-new-edges}).
\begin{figure}[h!] \begin{figure}[h!]
\centering \centering
@@ -502,7 +544,7 @@
\label{fig:chip/modeling/12-new-edges} \label{fig:chip/modeling/12-new-edges}
\end{figure} \end{figure}
Теперь добавим подложку, на которой разместим текстуру стола. В боковом меню (клавиша N) в разделе Location в поле Z указываем значение 1mm, чтобы приподнять модель. Затем нажимаем Shift + A и в разделе Mesh выбираем Plane (Рис.~\ref{fig:chip/modeling/13-plane}). Затем нажимаем H, чтобы временно скрыть добавленную поверхность. Теперь добавим подложку, на которой разместим текстуру стола. В боковом меню (клавиша N) в разделе Location в поле Z указываем значение 1mm, чтобы приподнять модель. Затем нажимаем Shift + A (либо открываем список Add в верхнем меню) и в разделе Mesh выбираем Plane (Рис.~\ref{fig:chip/modeling/13-plane}). Затем нажимаем H, чтобы временно скрыть добавленную поверхность.
\begin{figure}[h!] \begin{figure}[h!]
\centering \centering
@@ -511,27 +553,28 @@
\label{fig:chip/modeling/13-plane} \label{fig:chip/modeling/13-plane}
\end{figure} \end{figure}
\newpage
\subsubsection{Текстурирование} \subsubsection{Текстурирование}
Переходим в раздел UV Editing в верхнем меню программы. В правом окне переключаемся в объектный режим (клавиша Tab), нажимаем на модель и нажимаем на точку на Num Pad, чтобы приблизиться к ней (Рис.~\ref{fig:chip/texturing/1-start}). Приступим к наложению текстур на модель фишки для придания ей реалистичного внешнего вида. Переходим в раздел UV Editing через верхнее меню программы. В правом окне активируем объектный режим с помощью клавиши Tab (либо через выпадающее меню в левом нижнем углу окна). Выделяем модель и приближаемся к ней, нажав клавишу точки на Num Pad (Рис.~\ref{fig:chip/texturing/1-start}).
\begin{figure}[h!] \begin{figure}[h!]
\centering \centering
\includegraphics[width=1\linewidth]{img/chip/texturing/1-start.png} \includegraphics[width=0.8\linewidth]{img/chip/texturing/1-start.png}
\caption{Раздел UV Editing.} \caption{Раздел UV Editing.}
\label{fig:chip/texturing/1-start} \label{fig:chip/texturing/1-start}
\end{figure} \end{figure}
В разделе Render Properties в поле Render Engine выбираем EEVEE, ставим галочку на разделе Raytracing и в его подразделе Fast GI Approximation в поле Threshold указыем значение 1. После чего нажимаем сочетание клавиш Z + 2, чтобы переключиться в режим предпросмотра материалов. Настроим рендер-движок для корректного отображения материалов. В разделе Render Properties выбираем EEVEE в поле Render Engine. Активируем Raytracing, устанавливаем значение Threshold в 1 в подразделе Fast GI Approximation. Переключаемся в режим предпросмотра материалов с помощью сочетания клавиш Z + 2 (либо выбираем режим Material Preview через меню Viewport Shading в верхней панели) (Рис.~\ref{fig:chip/texturing/2-settings}).
\begin{figure}[h!] \begin{figure}[h!]
\centering \centering
\includegraphics[width=0.7\linewidth]{img/chip/texturing/2-settings.png} \includegraphics[width=0.6\linewidth]{img/chip/texturing/2-settings.png}
\caption{Настройка движка EEVEE для корректного отображения текстур.} \caption{Настройка движка EEVEE для корректного отображения текстур.}
\label{fig:chip/texturing/2-settings} \label{fig:chip/texturing/2-settings}
\end{figure} \end{figure}
Открываем раздел Material Properties и добавляем новый материал, нажимая на кнопку New. В поле Base Color указываем значение \#9FAAB1FF. Затем нажимаем на + и снова на New, чтобы добавить ещё один материал. В разделе Base Color нажимаем на жёлтый кружок и выбираем пункт Image Texture (Рис.~\ref{fig:chip/texturing/3-image-texture}). В открывшемся окне проводника выбираем изображение фишки сверху. Изображение фишки снизу добавляем аналогичным образом. Создадим материалы для текстур фишки. Открываем раздел Material Properties и добавляем новый материал, нажимая на кнопку New. В поле Base Color указываем значение \#9FAAB1FF. Затем нажимаем на + и снова на New, чтобы добавить ещё один материал. В разделе Base Color нажимаем на жёлтый кружок и выбираем пункт Image Texture (Рис.~\ref{fig:chip/texturing/3-image-texture}). В открывшемся окне проводника выбираем изображение фишки сверху. Изображение фишки снизу добавляем аналогичным образом.
\begin{figure}[h!] \begin{figure}[h!]
\centering \centering
@@ -540,7 +583,7 @@
\label{fig:chip/texturing/3-image-texture} \label{fig:chip/texturing/3-image-texture}
\end{figure} \end{figure}
Переходим в режим редактирования (клавиша Tab). Переходим на вид сверху (клавиш 7 на Num Pad). В режиме выбора поверхностей (клавиша 3), выделяем все видимые поверхности. В разделе с материалами выбираем материал с изображением фишки сверху и нажимаем на кнопку Assign (Рис.~\ref{fig:chip/texturing/4-assigning}). Выполним UV-развёртку для точного наложения текстур. Переходим в режим редактирования клавишей Tab (либо через меню Mode). Активируем вид сверху клавишей 7 на Num Pad (меню View → Top). Выделяем все видимые грани в режиме выбора поверхностей (клавиша 3) и назначаем материал с текстурой фишки кнопкой Assign (Рис.~\ref{fig:chip/texturing/4-assigning}).
\begin{figure}[h!] \begin{figure}[h!]
\centering \centering
@@ -549,7 +592,7 @@
\label{fig:chip/texturing/4-assigning} \label{fig:chip/texturing/4-assigning}
\end{figure} \end{figure}
На панели слева распологаем проекцию поверхностей на текстуре таким образом, чтобы форма поверхности совпадала с изображением. Аналогичным образом накладываем материал с текстурой обратной стороны фишки (Рис.~\ref{fig:chip/texturing/5-uv-editing}). Отредактируем UV-координаты для точного совпадения с изображением. На панели слева распологаем проекцию поверхностей на текстуре таким образом, чтобы форма поверхности совпадала с изображением. Аналогичным образом накладываем материал с текстурой обратной стороны фишки (Рис.~\ref{fig:chip/texturing/5-uv-editing}).
\begin{figure}[h!] \begin{figure}[h!]
\centering \centering
@@ -558,7 +601,7 @@
\label{fig:chip/texturing/5-uv-editing} \label{fig:chip/texturing/5-uv-editing}
\end{figure} \end{figure}
Теперь можно вернуть поверхность, добавленную на этапе моделирования (Alt~+~H). В разделе Material Properties добавляем новый материал и в поле Base Color указываем текстуру стола. С помощью клавишы S в левом окне можно подогнать размеры текстуры (Рис.~\ref{fig:chip/texturing/6-table}). Добавим текстуру для поверхности стола. Возвращаем скрытую ранее плоскость стола сочетанием клавиш Alt + H (меню Object → Show/Hide → Show Hidden). В разделе Material Properties добавляем новый материал и в поле Base Color указываем текстуру стола. С помощью клавишы S в левом окне можно подогнать размеры текстуры (Рис.~\ref{fig:chip/texturing/6-table}).
\begin{figure}[h!] \begin{figure}[h!]
\centering \centering
@@ -570,9 +613,9 @@
\newpage \newpage
\subsubsection{Освещение и камера} \subsubsection{Освещение и камера}
Переходим в раздел Shading в верхнем меню программы. Нажимаем на модель и нажимаем на точку на Num Pad, чтобы приблизиться к ней. После чего используем сочетание клавиш Z + 8, чтобы перейти в режим предпросмотра результата. Настроим освещение сцены для финального рендеринга. Переходим в раздел Shading в верхнем меню программы. Нажимаем на модель и нажимаем на точку на Num Pad, чтобы приблизиться к ней. После чего используем сочетание клавиш Z + 8, чтобы перейти в режим предпросмотра результата.
Затем на панели редактирования материалов нужно переключиться на вкладку World. Нажать сочетание клавиш Shift + A и в разделе Texture выбрать Image Texture. Выход Color узла Image Texture необходимо подключить ко входу Color узла Background. В Image Texture указывается путь до HDRI текстуры окружения, которая поставляется вместе с Blender -- \texttt{C:\textbackslash Program Files\textbackslash Blender Foundation\textbackslash Blender 4.3\textbackslash 4.3\textbackslash datafiles\textbackslash studiolights\textbackslash world\textbackslash }. В параметре Strength узла Background указываем значение 0.200 (Рис.~\ref{fig:chip/lighting/1_start}). Создадим фоновое освещение через HDRI-карту. На панели редактирования материалов нужно переключиться на вкладку World. Нажать сочетание клавиш Shift + A и в разделе Texture выбрать Image Texture (меню Add → Texture → Image Texture). Выход Color узла Image Texture необходимо подключить ко входу Color узла Background. В Image Texture указывается путь до HDRI текстуры окружения, которая поставляется вместе с Blender -- \texttt{C:\textbackslash Program Files\textbackslash Blender Foundation\textbackslash Blender 4.3\textbackslash 4.3\textbackslash datafiles\textbackslash studiolights\textbackslash world\textbackslash }. В параметре Strength узла Background указываем значение 0.200 (Рис.~\ref{fig:chip/lighting/1_start}).
\begin{figure}[h!] \begin{figure}[h!]
\centering \centering
@@ -581,7 +624,7 @@
\label{fig:chip/lighting/1_start} \label{fig:chip/lighting/1_start}
\end{figure} \end{figure}
Переключаемся на вид сбоку (клавиша 1 на Num Pad), нажимаем Shift + A и в разделе Light выбираем Point. С помощью клавиши G располагаем источник света слева сверху над моделью. Для этого в боковом меню (клавиша N) в разделе Location в поле X указываем -0.3m, в поле Z указываем 0.2m. В разделе Object Data Properties в поле Power устанавливаем значение 4.5W. Затем дублируем источник света с помощью сочетания клавиш Shift + D и располагаем с противоположной стороны. Источнику света слева задаём синеватый оттенок (\#C5FBFF) в поле Color раздела Object Data Properties (Рис.~\ref{fig:chip/lighting/2_points}). Добавим дополнительные источники света для создания теней как на исходных изображениях. Переключаемся на вид сбоку (клавиша 1 на Num Pad), нажимаем Shift + A (либо открываем список Add в верхнем меню) и в разделе Light выбираем Point. С помощью клавиши G располагаем источник света слева сверху над моделью. Для этого в боковом меню (клавиша N) в разделе Location в поле X указываем -0.3m, в поле Z указываем 0.2m. В разделе Object Data Properties в поле Power устанавливаем значение 4.5W. Затем дублируем источник света с помощью сочетания клавиш Shift + D и располагаем с противоположной стороны. Источнику света слева задаём синеватый оттенок (\#C5FBFF) в поле Color раздела Object Data Properties (Рис.~\ref{fig:chip/lighting/2_points}).
\begin{figure}[h!] \begin{figure}[h!]
\centering \centering
@@ -591,7 +634,7 @@
\end{figure} \end{figure}
\newpage \newpage
Теперь добавим камеру. Для этого нажимаем сочетание клавиш Shift + A и выбираем пункт Camera. Теперь располагаем её ровно над моделью, чтобы получить изображение вида сверху. В боковом меню (клавиша N) в разделе Location в Z указываем значение 0.15m, а в разделе Rotation в поле X укажем значение 0. В разделе Object Data Properties в подразделе Lens в поле Focal Length указываем значение 110mm. Нажимаем 0 на Num Pad, чтобы переключиться на вид с камеры (Рис.~\ref{fig:chip/lighting/3_camera}). Теперь добавим камеру, чтобы зафиксировать ракурс для рендеринга. Для этого нажимаем сочетание клавиш Shift + A (либо открываем список Add в верхнем меню) и выбираем пункт Camera. Теперь располагаем её ровно над моделью, чтобы получить изображение вида сверху. В боковом меню (клавиша N) в разделе Location в Z указываем значение 0.15m, а в разделе Rotation в поле X укажем значение 0. В разделе Object Data Properties в подразделе Lens в поле Focal Length указываем значение 110mm. Нажимаем 0 на Num Pad, чтобы переключиться на вид с камеры (Рис.~\ref{fig:chip/lighting/3_camera}).
\begin{figure}[h!] \begin{figure}[h!]
\centering \centering
@@ -684,7 +727,7 @@
\subsubsection{Моделирование} \subsubsection{Моделирование}
Нажимаем на цифру 7 на Num Pad, чтобы перейти на вид сверху. Затем нажимаем Shift + A и в разделе Image выбираем Reference. В открывшемся окне проводника выбираем изображение зажима и нажимаем Add~Image~(Рис.~\ref{fig:clamp/modeling/1-add-reference}). Для точного воссоздания формы добавим референсное изображение. Нажимаем на цифру 7 на Num Pad (или выбираем вид сверху через меню View), чтобы перейти на вид сверху. Затем нажимаем сочетание клавиш Shift + A (либо открываем список Add в верхнем меню) и в разделе Image выбираем Reference. В открывшемся окне проводника выбираем изображение зажима и нажимаем Add~Image~(Рис.~\ref{fig:clamp/modeling/1-add-reference}).
\begin{figure}[h!] \begin{figure}[h!]
\centering \centering
@@ -693,7 +736,7 @@
\label{fig:clamp/modeling/1-add-reference} \label{fig:clamp/modeling/1-add-reference}
\end{figure} \end{figure}
Нажимаем Shift + A и в разделе Mesh выбираем Plane (Рис.~\ref{fig:clamp/modeling/2-add-plane}). Создадим базовую плоскость для построения контура. Нажимаем сочетание клавиш Shift + A (либо открываем меню Add) и в разделе Mesh выбираем Plane (Рис.~\ref{fig:clamp/modeling/2-add-plane}).
\begin{figure}[h!] \begin{figure}[h!]
\centering \centering
@@ -702,7 +745,7 @@
\label{fig:clamp/modeling/2-add-plane} \label{fig:clamp/modeling/2-add-plane}
\end{figure} \end{figure}
Переходим в режим редактирования (клавиша Tab) и в режиме выбора вершин (клавиша 1) с зажатой клавишей Shift выбираем три любых вершины добавленной плоскости. Нажимаем на клавишу X и в появившемся меню выбираем пункт Vertex, чтобы удалить эти вершины. Выделяем оставшуюся вершину и с помощью клавишы G переносим её в крайнюю точку ободка зажима. Затем нажимаем клавишу E, чтобы добавить новую точку. Таким образом делаем окантовку для всего зажима (Рис.~\ref{fig:clamp/modeling/3-border}). Приступим к формированию контура зажима по референсу. Переходим в режим редактирования (клавиша Tab) и в режиме выбора вершин (клавиша 1) с зажатой клавишей Shift выбираем три любых вершины добавленной плоскости. Нажимаем на клавишу X (либо используем опцию Delete в контекстном меню) и в появившемся меню выбираем пункт Vertex, чтобы удалить эти вершины. Выделяем оставшуюся вершину и с помощью клавишы G переносим её в крайнюю точку ободка зажима. Затем нажимаем клавишу E, чтобы добавить новую точку. Таким образом делаем окантовку для всего зажима (Рис.~\ref{fig:clamp/modeling/3-border}).
\begin{figure}[h!] \begin{figure}[h!]
\centering \centering
@@ -712,28 +755,27 @@
\end{figure} \end{figure}
\newpage \newpage
Переходим в объектный режим. Выделяем изображение и скрываем (клавиша H), оно больше не понадобится. Теперь выделяем полученную линию окантовки и в боковом меню (клавиша N) в разделе Dimensions в поле X указываем реальную ширину объекта -- 21mm. После чего значение поля X из раздела Scale копируем в поле Y того же раздела, чтобы сохранить пропорции при масштабировании (Рис.~\ref{fig:clamp/modeling/4-sizes}). Зададим реальные размеры модели. Переходим в объектный режим (клавиша Tab). Выделяем изображение и скрываем (клавиша H), оно больше не понадобится. Теперь выделяем полученную линию окантовки и в боковом меню (клавиша N) в разделе Dimensions в поле X указываем реальную ширину объекта -- 21mm. После чего значение поля X из раздела Scale копируем в поле Y того же раздела, чтобы сохранить пропорции при масштабировании (Рис.~\ref{fig:clamp/modeling/4-sizes}).
\begin{figure}[h!] \begin{figure}[h!]
\centering \centering
\includegraphics[width=1\linewidth]{img/clamp/modeling/4-sizes.png} \includegraphics[width=0.8\linewidth]{img/clamp/modeling/4-sizes.png}
\caption{Задание реальных размеров.} \caption{Задание реальных размеров.}
\label{fig:clamp/modeling/4-sizes} \label{fig:clamp/modeling/4-sizes}
\end{figure} \end{figure}
\newpage Перейдём к созданию объёмных ободков. Переключаемся на вид сбоку (клавиша 1 на Num Pad или меню View), копируем контур сочетанием клавиш Shift + D (через меню Object > Duplicate). Поднимаем копию выше исходного контура, затем конвертируем её в кривую через правый клик > Convert To > Curve.
Переключаемся на вид сбоку (клавиша 1 на Num Pad), затем копируем окантовку (сочетание клавиш Shift + D) и поднимаем немного выше. Затем нажимаем по новому объекту правой кнопкой мыши и в разделе Convert To выбираем пункт Curve.
Нажимаем сочетание клавиш Shift + A и в разделе Mesh выбираем пункт Circle. Затем в боковом меню (клавиша N) в разделе Dimensions в полях X и Y указываем диаметр ободков -- 1mm. Нажимаем на добавленный круг правой кнопкой мыши и в разделе Convert To выбираем пункт Curve (Рис.~\ref{fig:clamp/modeling/5-circle}). Сформируем профиль для будущего ободка. Нажимаем сочетание клавиш Shift + A (либо открываем список Add в верхнем меню) и в разделе Mesh выбираем Circle. В боковом меню (клавиша N) в разделе Dimensions задаём диаметр ободков -- 1mm в полях X и Y. Конвертируем круг в кривую через правый клик > Convert To > Curve (Рис.~\ref{fig:clamp/modeling/5-circle}).
\begin{figure}[h!] \begin{figure}[h!]
\centering \centering
\includegraphics[width=1\linewidth]{img/clamp/modeling/5-circle.png} \includegraphics[width=0.8\linewidth]{img/clamp/modeling/5-circle.png}
\caption{Конвертация круга из меша в кривую.} \caption{Конвертация круга из меша в кривую.}
\label{fig:clamp/modeling/5-circle} \label{fig:clamp/modeling/5-circle}
\end{figure} \end{figure}
Выбираем добавленный круг и нажимаем сочетание клавиш Ctrl + A и в появившемся списке выбираем пункт Scale. Затем выбираем скопированную окантовку, открваем раздел Object Data Properties и в подразделе Geometry/Bevel выбираем вариант Object. Нажимаем на иконку пипетки и выбираем круг и нажимаем на галочку у поля Fill Caps (Рис.~\ref{fig:clamp/modeling/6-bevel}). Создадим трёхмерный ободок. Выбираем добавленный круг и нажимаем сочетание клавиш Ctrl + A и в появившемся списке выбираем пункт Scale. Затем выбираем скопированную окантовку, открваем раздел Object Data Properties и в подразделе Geometry/Bevel выбираем вариант Object. Нажимаем на иконку пипетки и выбираем круг и нажимаем на галочку у поля Fill Caps (Рис.~\ref{fig:clamp/modeling/6-bevel}).
\begin{figure}[h!] \begin{figure}[h!]
\centering \centering
@@ -742,52 +784,53 @@
\label{fig:clamp/modeling/6-bevel} \label{fig:clamp/modeling/6-bevel}
\end{figure} \end{figure}
Полученный ободок и круг пока можно скрыть (клавиша H). В объектном режиме выбираем исходную окантовку зажима и переходим в режим редактирования (клавиша Tab). Выбираем все вершины (клавиша A) и расширяем окантовку вверх (сочетание клавиш E + Z). Возвращаемся в объектный режим (клавиша Tab). В боковом меню (клавиша N) в разделе Dimensions в поле Z указываем высоту чуть меньше реальной высоты объекта -- 6.5mm. В разделе Location в поле Z указываем значение 0.5mm. Нажимаем сочетание клавиш Ctrl + A и выбираем пункт Scale (Рис.~\ref{fig:clamp/modeling/7-sides}). Сформируем боковые стенки зажима. Полученный ободок и круг пока можно скрыть (клавиша H или меню Object > Show/Hide > Hide Selected). В объектном режиме выбираем исходную окантовку зажима и переходим в режим редактирования (клавиша Tab). Выбираем все вершины (клавиша A или меню Select > Select All) и расширяем окантовку вверх (сочетание клавиш E + Z). Возвращаемся в объектный режим (клавиша Tab). В боковом меню (клавиша N) в разделе Dimensions в поле Z указываем высоту чуть меньше реальной высоты объекта -- 6.5mm. В разделе Location в поле Z указываем значение 0.5mm. Нажимаем сочетание клавиш Ctrl + A и выбираем пункт Scale (Рис.~\ref{fig:clamp/modeling/7-sides}).
\begin{figure}[h!] \begin{figure}[h!]
\centering \centering
\includegraphics[width=0.85\linewidth]{img/clamp/modeling/7-sides.png} \includegraphics[width=0.75\linewidth]{img/clamp/modeling/7-sides.png}
\caption{Создание боковых сторон зажима.} \caption{Создание боковых сторон зажима.}
\label{fig:clamp/modeling/7-sides} \label{fig:clamp/modeling/7-sides}
\end{figure} \end{figure}
Продолжаем работать с ободком. В разделе Modifier Properties нажимаем на кнопку Add Modifier и добавляем модификатор Subdivision Surface из раздела Generate. В поле Level указываем значение 2. Затем добавляем ещё один модификатор из раздела Generate -- Solidify. В поле Mode выбираем значение Complex. В поле Thickness указываем половину от толщины пластика -- 0.15mm. В поле Offset указываем значение 0. Затем нажимаем сочетание клавиш Ctrl + A, чтобы применить модификатор Solidify (Рис.~\ref{fig:clamp/modeling/8-modifiers}). Продолжаем работать с боковыми стенками. Сгладим полученную модель, чтобы границы полигонов не бросались в глаза. В разделе Modifier Properties нажимаем на кнопку Add Modifier и добавляем модификатор Subdivision Surface из раздела Generate. В поле Level указываем значение 2. Затем добавляем ещё один модификатор из раздела Generate -- Solidify, чтобы добавить стенкам толщины. В поле Mode выбираем значение Complex. В поле Thickness указываем половину от толщины пластика -- 0.15mm. В поле Offset указываем значение 0. Затем нажимаем сочетание клавиш Ctrl + A, чтобы применить модификатор Solidify (Рис.~\ref{fig:clamp/modeling/8-modifiers}).
\begin{figure}[h!] \begin{figure}[h!]
\centering \centering
\includegraphics[width=0.9\linewidth]{img/clamp/modeling/8-modifiers.png} \includegraphics[width=0.85\linewidth]{img/clamp/modeling/8-modifiers.png}
\caption{Придание толщины зажиму.} \caption{Придание толщины зажиму.}
\label{fig:clamp/modeling/8-modifiers} \label{fig:clamp/modeling/8-modifiers}
\end{figure} \end{figure}
Переходим в режим редактирования (клавиша Tab). Нажимаем сочетание Ctrl + R, чтобы добавить новые грани и убрать излишнее сглаживание по краям объекта. Возвращаемся в объектный режим (клавиша Tab). Нажимаем на объект правой кнопкой мыши и выбираем пункт Shade Smooth (Рис.~\ref{fig:clamp/modeling/9-new-edges}). Добавим рёбра для сохранения чётких граней. Переходим в режим редактирования (клавиша Tab). Нажимаем сочетание Ctrl + R (или выбираем инструмент Loop Cut), чтобы добавить новые грани и убрать излишнее сглаживание по краям объекта. Возвращаемся в объектный режим (клавиша Tab). Нажимаем на объект правой кнопкой мыши и выбираем пункт Shade Smooth,чтобы сгладить стыки граней (Рис.~\ref{fig:clamp/modeling/9-new-edges}).
\begin{figure}[h!] \begin{figure}[h!]
\centering \centering
\includegraphics[width=0.9\linewidth]{img/clamp/modeling/9-new-edges.png} \includegraphics[width=0.8\linewidth]{img/clamp/modeling/9-new-edges.png}
\caption{Добавление новых граней.} \caption{Добавление новых граней.}
\label{fig:clamp/modeling/9-new-edges} \label{fig:clamp/modeling/9-new-edges}
\end{figure} \end{figure}
Возвращаем скрытый ободок (Alt + H). В Modifier Properties добавляем модификатор Subdivision Surface из раздела Generate. В поле Levels указываем значение 2. Нажимаем на ободок правой кнопкой мыши и выбираем пункт Shade Smooth. В боковом меню (клавиша N) в разделе Location в поле Z указываем значение 0.5mm (Рис.~\ref{fig:clamp/modeling/10-bottom}). Теперь сгладим ободок. Возвращаем его на сцену (сочетание клавиш Alt + H или через меню Object → Show/Hide → Show Hidden). В Modifier Properties добавляем модификатор Subdivision Surface из раздела Generate. В поле Levels указываем значение 2. Нажимаем на ободок правой кнопкой мыши и выбираем пункт Shade Smooth. В боковом меню (клавиша N) в разделе Location в поле Z указываем значение 0.5mm (Рис.~\ref{fig:clamp/modeling/10-bottom}).
\begin{figure}[h!] \begin{figure}[h!]
\centering \centering
\includegraphics[width=1\linewidth]{img/clamp/modeling/10-bottom.png} \includegraphics[width=0.8\linewidth]{img/clamp/modeling/10-bottom.png}
\caption{Установка и сглаживание нижнего ободка.} \caption{Установка и сглаживание нижнего ободка.}
\label{fig:clamp/modeling/10-bottom} \label{fig:clamp/modeling/10-bottom}
\end{figure} \end{figure}
Переходим в режим редактирования (клавиша Tab). Выделяем крайние точки на ободке и чуть-чуть сдвигаем (клавиша G) с зажатой клавишей Shift, чтобы грани ободка и основной части зажима не накладывались друг на друга (Рис.~\ref{fig:clamp/modeling/11-faces}). Устраним артефакты на месте пересечения граней. Переходим в режим редактирования (клавиша Tab). Выделяем крайние точки на ободке и чуть-чуть сдвигаем (клавиша G) с зажатой клавишей Shift, чтобы грани ободка и основной части зажима не накладывались друг на друга (Рис.~\ref{fig:clamp/modeling/11-faces}).
\begin{figure}[h!] \begin{figure}[h!]
\centering \centering
\includegraphics[width=1\linewidth]{img/clamp/modeling/11-faces.png} \includegraphics[width=0.8\linewidth]{img/clamp/modeling/11-faces.png}
\caption{Устранение артефактов на стыке граней.} \caption{Устранение артефактов на стыке граней.}
\label{fig:clamp/modeling/11-faces} \label{fig:clamp/modeling/11-faces}
\end{figure} \end{figure}
Возвращаемся в объектный режим (клавиша Tab). Копируем нижний ободок с помощью сочетания клавиш Alt + D. В боковом меню (клавиша N) в разделе Locataion в поле Z указываем значение 7mm (Рис.~\ref{fig:clamp/modeling/12-copy}).
Создадим верхний ободок дублированием. Возвращаемся в объектный режим (клавиша Tab). Копируем нижний ободок с помощью сочетания клавиш Alt + D (меню Object > Duplicate). В боковом меню (клавиша N) в разделе Locataion в поле Z указываем значение 7mm (Рис.~\ref{fig:clamp/modeling/12-copy}).
\begin{figure}[h!] \begin{figure}[h!]
\centering \centering
@@ -796,7 +839,7 @@
\label{fig:clamp/modeling/12-copy} \label{fig:clamp/modeling/12-copy}
\end{figure} \end{figure}
Теперь добавим подложку, на которой разместим текстуру стола. Нажимаем Shift + A и в разделе Mesh выбираем Plane (Рис.~\ref{fig:clamp/modeling/13-plane}). Затем нажимаем H, чтобы временно скрыть добавленную поверхность. Теперь добавим плоскость, на которой разместим текстуру стола. Нажимаем Shift + A (либо открываем список Add в верхнем меню) и в разделе Mesh выбираем Plane (Рис.~\ref{fig:clamp/modeling/13-plane}). Затем нажимаем H (меню Object > Show/Hide > Hide Selected), чтобы временно скрыть добавленную поверхность.
\begin{figure}[h!] \begin{figure}[h!]
\centering \centering
@@ -808,38 +851,38 @@
\newpage \newpage
\subsubsection{Текстурирование} \subsubsection{Текстурирование}
Переходим в раздел UV Editing в верхнем меню программы. В правом окне переключаемся в объектный режим (клавиша Tab), нажимаем на модель и нажимаем на точку на Num Pad, чтобы приблизиться к ней (Рис.~\ref{fig:clamp/texturing/1-start}). Для наложения текстур на модель необходимо подготовить UV-развёртку и настроить материалы.Переходим в раздел UV Editing в верхнем меню программы. В правом окне переключаемся в объектный режим (клавиша Tab), нажимаем на модель и нажимаем на точку на Num Pad, чтобы приблизиться к ней (Рис.~\ref{fig:clamp/texturing/1-start}).
\begin{figure}[h!] \begin{figure}[h!]
\centering \centering
\includegraphics[width=1\linewidth]{img/clamp/texturing/1-start.png} \includegraphics[width=0.85\linewidth]{img/clamp/texturing/1-start.png}
\caption{Раздел UV Editing.} \caption{Раздел UV Editing.}
\label{fig:clamp/texturing/1-start} \label{fig:clamp/texturing/1-start}
\end{figure} \end{figure}
В разделе Render Properties в поле Render Engine выбираем EEVEE, ставим галочку на разделе Raytracing и в его подразделе Fast GI Approximation в поле Threshold указыем значение 1. После чего нажимаем сочетание клавиш Z + 2, чтобы переключиться в режим предпросмотра материалов (Рис.~\ref{fig:clamp/texturing/2-settings}). Настроим рендер-движок для корректного отображения материалов. В разделе Render Properties в поле Render Engine выбираем EEVEE, ставим галочку на разделе Raytracing и в его подразделе Fast GI Approximation в поле Threshold указыем значение 1. После чего нажимаем сочетание клавиш Z + 2 (либо выбираем режим Material Preview через меню Viewport Shading в верхней панели), чтобы переключиться в режим предпросмотра материалов (Рис.~\ref{fig:clamp/texturing/2-settings}).
\begin{figure}[h!] \begin{figure}[h!]
\centering \centering
\includegraphics[width=0.7\linewidth]{img/clamp/texturing/2-settings.png} \includegraphics[width=0.65\linewidth]{img/clamp/texturing/2-settings.png}
\caption{Настройка движка EEVEE для корректного отображения текстур.} \caption{Настройка движка EEVEE для корректного отображения текстур.}
\label{fig:clamp/texturing/2-settings} \label{fig:clamp/texturing/2-settings}
\end{figure} \end{figure}
Выбираем нижний ободок и открываем раздел Material Properties. Нажимаем на кнопку New, чтобы добавить новый материал. В поле Base Color указываем значение \#A61625 (Рис.~\ref{fig:clamp/texturing/3-color}). Создадим материал для нижнего ободка. Нажимаем на него левой кнопкой мыши и открываем раздел Material Properties. Нажимаем на кнопку New, чтобы добавить новый материал. В поле Base Color указываем значение \#A61625 (Рис.~\ref{fig:clamp/texturing/3-color}).
\begin{figure}[h!] \begin{figure}[h!]
\centering \centering
\includegraphics[width=0.8\linewidth]{img/clamp/texturing/3-color.png} \includegraphics[width=0.75\linewidth]{img/clamp/texturing/3-color.png}
\caption{Покраска ободков.} \caption{Покраска ободков.}
\label{fig:clamp/texturing/3-color} \label{fig:clamp/texturing/3-color}
\end{figure} \end{figure}
Переходим в раздел Shading. Выбираем основную часть зажима и добавляем новый материал для него. Для этого нажимаем на кнопку New на панели ниже. Затем нажимаем сочетание клавиш Shift + A и в разделе Color выбираем Hue/Saturation/Value. В поле Color добавленного узла указываем значение \#A61625. Снова нажимаем Shift + A и в разделе Texture выбираем Image Texture, в которой указываем путь до текстуры с надписью (Рис.~\ref{fig:clamp/real/writing-no-bg}), в поле Extension указываем значение Clip, чтобы изображение с надписью не повторялось. Добавляем ещё один узел из раздела Color -- Mix Color. Соединяем узлы как показано на Рис.~\ref{fig:clamp/texturing/4-nodes}. Перейдём к созданию сложного материала для основной части с текстурированной надписью. Переходим в раздел Shading. Выбираем основную часть зажима и добавляем новый материал для него. Для этого нажимаем на кнопку New на панели ниже. Затем нажимаем сочетание клавиш Shift + A (или через меню Add) и в разделе Color выбираем Hue/Saturation/Value. В поле Color добавленного узла указываем значение \#A61625. Снова нажимаем Shift + A и в разделе Texture выбираем Image Texture, в которой указываем путь до текстуры с надписью (Рис.~\ref{fig:clamp/real/writing-no-bg}), в поле Extension указываем значение Clip, чтобы изображение с надписью не повторялось. Добавляем ещё один узел из раздела Color -- Mix Color. Соединяем узлы как показано на Рис.~\ref{fig:clamp/texturing/4-nodes}.
\begin{figure}[h!] \begin{figure}[h!]
\centering \centering
\includegraphics[width=0.9\linewidth]{img/clamp/texturing/4-nodes.png} \includegraphics[width=0.85\linewidth]{img/clamp/texturing/4-nodes.png}
\caption{Графовое представление материала основной части зажима.} \caption{Графовое представление материала основной части зажима.}
\label{fig:clamp/texturing/4-nodes} \label{fig:clamp/texturing/4-nodes}
\end{figure} \end{figure}
@@ -860,7 +903,7 @@
\label{fig:clamp/texturing/5-uv} \label{fig:clamp/texturing/5-uv}
\end{figure} \end{figure}
Теперь можно вернуть поверхность, добавленную на этапе моделирования (Alt~+~H). В разделе Material Properties добавляем новый материал и в поле Base Color указываем текстуру стола. С помощью клавишы S в левом окне можно подогнать размеры текстуры (Рис.~\ref{fig:clamp/texturing/6-table}). Теперь можно вернуть поверхность, созданную на этапе моделирования (Alt~+~H или через меню Object → Show/Hide → Show Hidden), и добавить к ней материал с текстурой стола. В разделе Material Properties добавляем новый материал и в поле Base Color указываем текстуру стола. С помощью клавишы S в левом окне можно подогнать размеры текстуры (Рис.~\ref{fig:clamp/texturing/6-table}).
\begin{figure}[h!] \begin{figure}[h!]
\centering \centering
@@ -873,9 +916,9 @@
\newpage \newpage
\subsubsection{Освещение и камера} \subsubsection{Освещение и камера}
Переходим в раздел Shading в верхнем меню программы. После чего используем сочетание клавиш Z + 8, чтобы перейти в режим предпросмотра результата. Настроим освещение сцены для финального рендеринга. Переходим в раздел Shading в верхнем меню программы. После чего используем сочетание клавиш Z + 8, чтобы перейти в режим предпросмотра результата.
Затем на панели редактирования материалов нужно переключиться на вкладку World. Нажать сочетание клавиш Shift + A и в разделе Texture выбрать Image Texture. Выход Color узла Image Texture необходимо подключить ко входу Color узла Background. В Image Texture указывается путь до HDRI текстуры окружения, которая поставляется вместе с Blender -- \texttt{C:\textbackslash Program Files\textbackslash Blender Foundation\textbackslash Blender 4.3\textbackslash 4.3\textbackslash datafiles\textbackslash studiolights\textbackslash world\textbackslash interior.exr} (Рис.~\ref{fig:clamp/lighting/1-start}). Создадим фоновое освещение через HDRI-карту. На панели редактирования материалов нужно переключиться на вкладку World. Нажать сочетание клавиш Shift + A и в разделе Texture выбрать Image Texture (меню Add → Texture → Image Texture). Выход Color узла Image Texture необходимо подключить ко входу Color узла Background. В Image Texture указывается путь до HDRI текстуры окружения, которая поставляется вместе с Blender -- \texttt{C:\textbackslash Program Files\textbackslash Blender Foundation\textbackslash Blender 4.3\textbackslash 4.3\textbackslash datafiles\textbackslash studiolights\textbackslash world\textbackslash interior.exr} (Рис.~\ref{fig:clamp/lighting/1-start}).
\begin{figure}[h!] \begin{figure}[h!]
\centering \centering
@@ -884,7 +927,7 @@
\label{fig:clamp/lighting/1-start} \label{fig:clamp/lighting/1-start}
\end{figure} \end{figure}
Нажимаем Shift + A и в разделе Light выбираем Point. В боковом меню (клавиша N) в разделе Location в поле X указываем 0.01m, в поле Y указываем -0.4m, в поле Z указываем 0.5m. В разделе Object Data Properties в поле Power устанавливаем значение 4.5W. Нажимаем на точку на Num Pad, чтобы перейти к источнику света, и переключаемся на вид сверху (клавиша 7 на Num Pad). Затем дублируем источник света дважды с помощью сочетания клавиш Shift + D. Копии располагаем рядом с исходным источником для имитации лампочек в люстре, именно такое освещения было в момент создания фотографий. Источникам света задаём цвет \#CCDEFF в поле Color раздела Object Data Properties (Рис.~\ref{fig:clamp/lighting/2-points}). Добавим дополнительные источники света для создания теней как на исходных изображениях. Нажимаем Shift + A и в разделе Light выбираем Point (меню Add → Light → Point). В боковом меню (клавиша N) в разделе Location в поле X указываем 0.01m, в поле Y указываем -0.4m, в поле Z указываем 0.5m. В разделе Object Data Properties в поле Power устанавливаем значение 4.5W. Нажимаем на точку на Num Pad, чтобы перейти к источнику света, и переключаемся на вид сверху (клавиша 7 на Num Pad или через меню View → Top). Затем дублируем источник света дважды с помощью сочетания клавиш Shift + D. Копии располагаем рядом с исходным источником для имитации лампочек в люстре, именно такое освещения было в момент создания фотографий. Источникам света задаём цвет \#CCDEFF в поле Color раздела Object Data Properties (Рис.~\ref{fig:clamp/lighting/2-points}).
\begin{figure}[h!] \begin{figure}[h!]
\centering \centering
@@ -894,7 +937,7 @@
\end{figure} \end{figure}
\newpage \newpage
Теперь добавим камеру. Для этого нажимаем сочетание клавиш Shift + A и выбираем пункт Camera. Теперь располагаем перед моделью, чтобы получить вида сбоку как на фотографии. В боковом меню (клавиша N) в разделе Location в поле X указываем 0.062m, в поле Y указываем -0.09m, в поле Z указываем 0.066m, а в разделе Rotation в поле X укажем значение 60, в поле Z -- 34. В разделе Object Data Properties в подразделе Lens в поле Focal Length указываем значение 140mm. Нажимаем 0 на Num Pad, чтобы переключиться на вид с камеры (Рис.~\ref{fig:clamp/lighting/3-camera}). Теперь добавим камеру, чтобы зафиксировать ракурс для рендеринга. Для этого нажимаем сочетание клавиш Shift + A (либо открываем список Add в верхнем меню) и выбираем пункт Camera. Теперь располагаем перед моделью, чтобы получить вида сбоку как на фотографии. В боковом меню (клавиша N) в разделе Location в поле X указываем 0.062m, в поле Y указываем -0.09m, в поле Z указываем 0.066m, а в разделе Rotation в поле X укажем значение 60, в поле Z -- 34. В разделе Object Data Properties в подразделе Lens в поле Focal Length указываем значение 140mm. Нажимаем 0 на Num Pad, чтобы переключиться на вид с камеры (Рис.~\ref{fig:clamp/lighting/3-camera}).
\begin{figure}[h!] \begin{figure}[h!]
\centering \centering
@@ -987,11 +1030,398 @@
\label{fig:clamp-compare-top} \label{fig:clamp-compare-top}
\end{figure} \end{figure}
\newpage
\subsection{Объект моделирования №3}
\subsubsection{Реальные размеры изделия}
Ширина - 27 мм
Длина - 126 мм
Толщина - 2 мм
\subsubsection{Моделирование}
Создадим основу будущей линейки, используя примитив куб. Нажимаем сочетание клавиш Shift + A (либо выбираем Add в верхнем меню) и в разделе Mesh выбираем Cube. Затем в боковом меню (клавиша N) задаём ему реальные размеры линейки. В разделе Dimensions в поле X указываем 126mm, в поле Y -- 27mm, в поле Z -- 2mm. Нажимаем на точку на Num Pad, чтобы приблизиться к модели (Рис.~\ref{fig:ruler/modeling/1-add-cube}).
\begin{figure}[h!]
\centering
\includegraphics[width=1\linewidth]{img/ruler/modeling/1-add-cube.png}
\caption{Добавление основы для линейки.}
\label{fig:ruler/modeling/1-add-cube}
\end{figure}
Добавим сглаживание для придания модели естественных форм. В разделе Modifier Properties нажимаем на кнопку Add Modifier и добавляем модификатор Subdivision Surface из раздела Generate. В поле Levels Viewport и Render указываем значение 3 (Рис.~\ref{fig:ruler/modeling/2-subdivision}).
\begin{figure}[h!]
\centering
\includegraphics[width=1\linewidth]{img/ruler/modeling/2-subdivision.png}
\caption{Добавление модификатора Subdivision Surface.}
\label{fig:ruler/modeling/2-subdivision}
\end{figure}
Уточним геометрию модели путём добавления рёбер. Переключаемся на вид сверху (клавиша 7 на Num Pad или через меню View → Top). Переходим в режим редактирования (клавиша Tab). Нажимаем сочетание клавиш Ctrl + R (инструмент Loop Cut) и добавляем новые рёбра по краям линейки (Рис.~\ref{fig:ruler/modeling/3-edges}).
\begin{figure}[h!]
\centering
\includegraphics[width=0.9\linewidth]{img/ruler/modeling/3-edges.png}
\caption{Добавление новых рёбер.}
\label{fig:ruler/modeling/3-edges}
\end{figure}
Сформируем скос на торце линейки. Переключаемся на вид сбоку (клавиша 3 на Num Pad) и переходим в режим прозрачности (сочетание клавиш Alt + Z, либо через иконку X-Ray в правом верхнем углу). Выделяем две крайние верхние вершины с левой стороны линейки и сдвигаем вправо по горизонтали (сочетание клавиш G + Y) (Рис.~\ref{fig:ruler/modeling/4-skew}).
\begin{figure}[h!]
\centering
\includegraphics[width=0.9\linewidth]{img/ruler/modeling/4-skew.png}
\caption{Создание скоса.}
\label{fig:ruler/modeling/4-skew}
\end{figure}
Режим прозрачности можно отключить (сочетание клавиш Alt + Z, либо через иконку X-Ray в правом верхнем углу). Возвращаемся в объектный режим (клавиша Tab). Нажимаем по модели линейки правой кнопкой мыши и выбираем пункт Shade Smooth, чтобы сгладить стыки граней. Добавляем невидимый объект с напрявляющими для управления деформацией изгиба. Нажимаем сочетание клавиш Shift + A (либо выбираем Add в верхнем меню) и в разделе Empty выбираем Arrows. В разделе Object Properties в подразделе Rotation в поле X указываем значение -90, в поле Z 90 (Рис.~\ref{fig:ruler/modeling/5-arrows}).
\begin{figure}[h!]
\centering
\includegraphics[width=1\linewidth]{img/ruler/modeling/5-arrows.png}
\caption{Добавление объекта Arrows.}
\label{fig:ruler/modeling/5-arrows}
\end{figure}
Смоделируем изгиб линейки. Выбираем линейку и в разделе Modifier Properties добавляем модификатор Simple Deform из раздела Deform. В настройках модификатора выбираем вариант Bend, в поле Angle указываем значени 10, в поле Object выбираем только что добавленный объект Arrows (Рис.~\ref{fig:ruler/modeling/6-bend}).
\begin{figure}[h!]
\centering
\includegraphics[width=1\linewidth]{img/ruler/modeling/6-bend.png}
\caption{Создание изгиба линейки.}
\label{fig:ruler/modeling/6-bend}
\end{figure}
Линейку и стрелки можно временно скрыть (клавиша H, либо меню Object > Show/Hide > Hide Selected). Перейдём к моделированию излома. Добавим плоскость, для этого нажимаем сочетание клавиш Shift + A (либо выбираем Add в верхнем меню) и в разделе Mesh выбираем Plane. В боковом меню (клавиша N) задаём её размеры. В разделе Dimensions в поле X указываем 126mm, в поле Y -- 27mm (Рис.~\ref{fig:ruler/modeling/7-plane}).
\begin{figure}[h!]
\centering
\includegraphics[width=1\linewidth]{img/ruler/modeling/7-plane.png}
\caption{Добавление плоскости.}
\label{fig:ruler/modeling/7-plane}
\end{figure}
\newpage
Импортируем референсное изображение для точного моделирования. Нажимаем на цифру 7 на Num Pad (или через меню View → Top), чтобы перейти на вид сверху. Затем нажимаем Shift + A (либо открываем список Add в верхнем меню) и в разделе Image выбираем Reference. В открывшемся окне проводника выбираем изображение линейки и нажимаем Add~Image. Затем масштабируем линейку под размер плоскости. Для этого в боковом меню (клавиша N) в разделе Scale достаточно указать значение 0.025 по всем осям (Рис.~\ref{fig:ruler/modeling/8-reference}).
\begin{figure}[h!]
\centering
\includegraphics[width=1\linewidth]{img/ruler/modeling/8-reference.png}
\caption{Добавление изображения линейки.}
\label{fig:ruler/modeling/8-reference}
\end{figure}
Включаем режим прозрачности сочетанием клавиш Alt + Z. Переходим в режим редактирования (клавиша Tab). Выделяем угловые вершины плоскости и располагаем на краях линейки. Затем переходим в режим выделения рёбер (клавиша 2), выбираем ребро со стороны излома, нажимаем клавишу X и выбираем пункт Edges, чтобы удалить его (Рис.~\ref{fig:ruler/modeling/9-remove-edge}).
\begin{figure}[h!]
\centering
\includegraphics[width=0.55\linewidth]{img/ruler/modeling/9-remove-edge.png}
\caption{Удаление ребра.}
\label{fig:ruler/modeling/9-remove-edge}
\end{figure}
Переходим в режим выделения вершин (клавиша 1) и выбираем левую нижнюю вершину. С помощью клавишы E создаём новые рёбра по изображению линейки (Рис.~\ref{fig:ruler/modeling/10-break}).
\begin{figure}[h!]
\centering
\includegraphics[width=0.55\linewidth]{img/ruler/modeling/10-break.png}
\caption{Воссоздание нижней части излома линейки.}
\label{fig:ruler/modeling/10-break}
\end{figure}
Затем выбираем две вершины в левом верхнем углу и объединяем. Для этого нажимаем на клавишу M и выбираем пункт At Last (Рис.~\ref{fig:ruler/modeling/11-merge}).
\begin{figure}[h!]
\centering
\includegraphics[width=0.6\linewidth]{img/ruler/modeling/11-merge.png}
\caption{Объединение вершин.}
\label{fig:ruler/modeling/11-merge}
\end{figure}
Переходим на вид сбоку, нажимаем клавишу E и приподнимаем появишуюся копию плоскости (Рис.~\ref{fig:ruler/modeling/12-select}).
\begin{figure}[h!]
\centering
\includegraphics[width=0.6\linewidth]{img/ruler/modeling/12-select.png}
\caption{Придание толщины для плоскости.}
\label{fig:ruler/modeling/12-select}
\end{figure}
Переключаемся на вид сверху (клавиша 7 на Num Pad или через меню View → Top). И с помощью сочетания клавиш G + X по отдельности выравниваем точки по верхней части излома (Рис.~\ref{fig:ruler/modeling/13-break-top}).
\begin{figure}[h!]
\centering
\includegraphics[width=0.55\linewidth]{img/ruler/modeling/13-break-top.png}
\caption{Воссоздание верхней части излома линейки.}
\label{fig:ruler/modeling/13-break-top}
\end{figure}
\newpage
С зажатой клавишей Alt выделяем любую вершну на нижней грани излома и нажимаем на клавишу F. Затем проделываем аналогичную операцию с любой вершиной верхней грани (Рис.~\ref{fig:ruler/modeling/14-fill}).
\begin{figure}[h!]
\centering
\includegraphics[width=0.7\linewidth]{img/ruler/modeling/14-fill.png}
\caption{Создание верхней и нижней граней у объекта с изломом.}
\label{fig:ruler/modeling/14-fill}
\end{figure}
Переходим в объектный режим (клавиша Tab) и в боковом меню (клавиша N) в разделе Dimensions в поле Z указываем 2.1mm, а в поле Y -- 28mm. Нажимаем по объекту правой кнопкой мыши, в разделе Set Origin выбраем пункт Origin to Geometry. Затем в боковом меню в поле Z раздела Location указываем значение 0. Изображение больше не понадобится и его можно скрыть (клавиша H) (Рис.~\ref{fig:ruler/modeling/15-scale-locale}).
\begin{figure}[h!]
\centering
\includegraphics[width=0.7\linewidth]{img/ruler/modeling/15-scale-locale.png}
\caption{Задание нужной позиции и размеров.}
\label{fig:ruler/modeling/15-scale-locale}
\end{figure}
Нажимаем Shift + A (либо открываем список Add в верхнем меню) и в разделе Mesh выбираем Cube. В боковом меню (клавиша N) указываем его размеры и позицию. В разделе Dimensions в поле X указываем 20mm, в поле Y -- 275mm, в поле Z -- 2.05mm. В разделе Locataion в поле X указываем -0.06m (Рис.~\ref{fig:ruler/modeling/16-cube}).
\begin{figure}[h!]
\centering
\includegraphics[width=0.7\linewidth]{img/ruler/modeling/16-cube.png}
\caption{Добавление ещё одного объекта для отражения излома.}
\label{fig:ruler/modeling/16-cube}
\end{figure}
Затем в разделе Modifier Properties добавляем модификатор Boolean из раздела Generate. В поле Object указываем объект с изломом. После этого объект с изломом можно скрыть (клавиша H) (Рис.~\ref{fig:ruler/modeling/17-diff}).
\begin{figure}[h!]
\centering
\includegraphics[width=0.7\linewidth]{img/ruler/modeling/17-diff.png}
\caption{Результат вычитания излома из объекта.}
\label{fig:ruler/modeling/17-diff}
\end{figure}
Возвращаем скрытую модель линейки (Alt + H) и в разделе Modifier Properties добавляем модификатор Boolean из раздела Generate. В поле Object указываем новый объект с изломом, полученный на предыдущем шаге. Модификатор располагаем Boolean располагаем между модификаторами Subdivision Surface и Simple Deform, которые были добавлены ранее. Объект с изломом можно скрыть (клавиша H) (Рис.~\ref{fig:ruler/modeling/18-final-diff}).
\begin{figure}[h!]
\centering
\includegraphics[width=0.7\linewidth]{img/ruler/modeling/18-final-diff.png}
\caption{Вычитание излома из объекта линейки.}
\label{fig:ruler/modeling/18-final-diff}
\end{figure}
\newpage
\subsubsection{Текстурирование}
Перед началом текстурирования модификаторы Subdivision Surface и Boolean нужно применить. Для этого выделяем их в разделе Modifier Properties и нажимаем сочетание клавиш Ctrl + A. Затем переходим в режим редактирования (клавиша Tab). Модификатор Simple Deform можно временно отключить, для этого нужно нажать на иконку компьютера в его настройках (Рис.~\ref{fig:ruler/texturing/1-apply}).
\begin{figure}[h!]
\centering
\includegraphics[width=1\linewidth]{img/ruler/texturing/1-apply.png}
\caption{Применение модификаторов.}
\label{fig:ruler/texturing/1-apply}
\end{figure}
Переходим во вкладку UV Editing. В разделе Render Properties в поле Render Engine выбираем EEVEE, ставим галочку на разделе Raytracing и в его подразделе Fast GI Approximation в поле Threshold указыем значение 1. После чего нажимаем сочетание клавиш Z + 2, чтобы переключиться в режим предпросмотра материалов (Рис.~\ref{fig:ruler/texturing/2-settings}).
\begin{figure}[h!]
\centering
\includegraphics[width=1\linewidth]{img/ruler/texturing/2-settings.png}
\caption{Настройка движка EEVEE для корректного отображения текстур.}
\label{fig:ruler/texturing/2-settings}
\end{figure}
Переходим в раздел Material Properties и создаём новый материал. В поле Base Color указываем ему цвет \#142735. Нажимаем на иконку плюса рядом со списком материалов и добавляем ещё два слота. В обоих слотах создаём материалы и в поле Base Color выбираем Image Texture и указываем пути до текстур верхней и нижней граней линейки (Рис.~\ref{fig:ruler/texturing/3-materials}).
\begin{figure}[h!]
\centering
\includegraphics[width=0.8\linewidth]{img/ruler/texturing/3-materials.png}
\caption{Создание материалов.}
\label{fig:ruler/texturing/3-materials}
\end{figure}
Переходим в режим редактирования (клавиша Tab). И в режиме выбора граней (клавиша 3) выделяем все грани на верхней стороне линейки. Затем в разделе Material Properties выбираем материал с текстурой лицевой стороны линейки и нажимаем Assign. Затем переключаемся на вид сверху (клавиша 7 на Num Pad или через меню View → Top), нажимаем клавишу U и выбираем пункт Project from View (Bounds), чтобы создать UV развёртку верхней поверхности линейки (Рис.~\ref{fig:ruler/texturing/4-top-uv}).
\begin{figure}[h!]
\centering
\includegraphics[width=1\linewidth]{img/ruler/texturing/4-top-uv.png}
\caption{Наложение текстуры на лицевую сторону линейки.}
\label{fig:ruler/texturing/4-top-uv}
\end{figure}
\newpage
В левом окне подгоняем UV развёртку под текстуру используя клавишы G и S (Рис.~\ref{fig:ruler/texturing/5-top-uv-tuning}).
\begin{figure}[h!]
\centering
\includegraphics[width=0.8\linewidth]{img/ruler/texturing/5-top-uv-tuning.png}
\caption{Подгонка UV развёртки под текстуру.}
\label{fig:ruler/texturing/5-top-uv-tuning}
\end{figure}
Теперь проделываем аналогичные операции с обратной стороной линейки. Выбираем все вершины нижней грани, прикрепляем к ним материал с текстурой обратной стороны линейки, создаём UV развёртку и подгоняем (Рис.~\ref{fig:ruler/texturing/6-back-uv}).
\begin{figure}[h!]
\centering
\includegraphics[width=0.8\linewidth]{img/ruler/texturing/6-back-uv.png}
\caption{Наложение текстуры на обратную сторону линейки.}
\label{fig:ruler/texturing/6-back-uv}
\end{figure}
Переходим в раздел Modifier Properties и применяе модификатор Simple Deform с помощью сочетания клавиш Ctrl + A (Рис.~\ref{fig:ruler/texturing/7-apply}).
\begin{figure}[h!]
\centering
\includegraphics[width=0.7\linewidth]{img/ruler/texturing/7-apply.png}
\caption{Применение модификаторов.}
\label{fig:ruler/texturing/7-apply}
\end{figure}
Нажимаем Shift + A (либо открываем список Add в верхнем меню) и в разделе Mesh выбираем Plane, чтобы добавить плоскость, на которой будет расопложена текстура стола. В разделе Material Properties добавляем материал. В поле Base Color указываем Image Texture и указываем путь до текстуры стола. Переходим в режим редактирования (клавиша Tab) и подгоняем размеры текстуры (Рис.~\ref{fig:ruler/texturing/8-table}).
\begin{figure}[h!]
\centering
\includegraphics[width=0.8\linewidth]{img/ruler/texturing/8-table.png}
\caption{Добавление текстуры стола.}
\label{fig:ruler/texturing/8-table}
\end{figure}
Перехдоим в объектный режим (клавиша Tab). Переключаемся на вид сбоку (клавиша 1 на Num Pad). Затем выбираем линейку и немного приподнимаем её, чтобы она лежала на столе (Рис.~\ref{fig:ruler/texturing/9-up}).
\begin{figure}[h!]
\centering
\includegraphics[width=0.8\linewidth]{img/ruler/texturing/9-up.png}
\caption{Результат этапа текстурирования сцены.}
\label{fig:ruler/texturing/9-up}
\end{figure}
\subsubsection{Освещение и камера}
Переходим в раздел Shading в верхнем меню программы. Нажимаем на модель и нажимаем на точку на Num Pad, чтобы приблизиться к ней. После чего используем сочетание клавиш Z + 8, чтобы перейти в режим предпросмотра результата.
Затем на панели редактирования материалов нужно переключиться на вкладку World. Нажать сочетание клавиш Shift + A (либо открываем список Add в верхнем меню) и в разделе Texture выбрать Image Texture. Выход Color узла Image Texture необходимо подключить ко входу Color узла Background. В Image Texture указывается путь до HDRI текстуры окружения, которая поставляется вместе с Blender -- \texttt{C:\textbackslash Program Files\textbackslash Blender Foundation\textbackslash Blender 4.3\textbackslash 4.3\textbackslash datafiles\textbackslash studiolights\textbackslash world\textbackslash interior.exr } (Рис.~\ref{fig:ruler/lighting/1-world}).
\begin{figure}[h!]
\centering
\includegraphics[width=1\linewidth]{img/ruler/lighting/1-world.png}
\caption{Настройка общего освещения сцены.}
\label{fig:ruler/lighting/1-world}
\end{figure}
Нажимаем Shift + A (либо открываем список Add в верхнем меню) и в разделе Light выбираем Point. В боковом меню (клавиша N) в разделе Location в поле X указываем 0.01m, в поле Y указываем -0.4m, в поле Z указываем 0.5m. В разделе Object Data Properties в поле Power устанавливаем значение 4.5W. Нажимаем на точку на Num Pad, чтобы перейти к источнику света, и переключаемся на вид сверху (клавиша 7 на Num Pad или через меню View → Top). Затем дублируем источник света дважды с помощью сочетания клавиш Shift + D. Копии располагаем рядом с исходным источником для имитации лампочек в люстре, именно такое освещения было в момент создания фотографий. Источникам света задаём цвет \#CCDEFF в поле Color раздела Object Data Properties (Рис.~\ref{fig:ruler/lighting/2-points}).
\begin{figure}[h!]
\centering
\includegraphics[width=1\linewidth]{img/ruler/lighting/2-points.png}
\caption{Расположение дополнительных источников освещения.}
\label{fig:ruler/lighting/2-points}
\end{figure}
\newpage
Теперь добавим камеру. Для этого нажимаем сочетание клавиш Shift + A (либо открываем список Add в верхнем меню) и выбираем пункт Camera. Теперь располагаем перед моделью, чтобы получить вида сбоку как на фотографии. В боковом меню (клавиша N) в разделе Location в поле X указываем -0.105m, в поле Y указываем -0.073m, в поле Z указываем 0.011m, а в разделе Rotation в поле X укажем значение 47, в поле Y -- -1, в поле Z -- -50. В разделе Object Data Properties в подразделе Lens в поле Focal Length указываем значение 60mm. Нажимаем 0 на Num Pad, чтобы переключиться на вид с камеры (Рис.~\ref{fig:ruler/lighting/3-camera}).
\begin{figure}[h!]
\centering
\includegraphics[width=1\linewidth]{img/ruler/lighting/3-camera.png}
\caption{Расположение камеры.}
\label{fig:ruler/lighting/3-camera}
\end{figure}
\subsubsection{Рендеринг финальных изображений}
Для настройки рендеринга открываем Render Properties. В поле Render Engine выбираем значение Cycles. В разделе Sampling/Render в поле Max Samples указываем значение 128, чтобы ускорить рендеринг (Рис.~\ref{fig:chip/render/1_settings}).
\begin{figure}[h!]
\centering
\includegraphics[width=0.33\linewidth]{img/chip/render/1_settings.png}
\caption{Настройки рендеринга.}
\label{fig:chip/render/1_settings}
\end{figure}
Нажимаем клавишу F12 и ожидаем некоторое время до окончания процесса рендеринга.
Результаты представлены на Рис.~\ref{fig:ruler-compare-front}--\ref{fig:ruler-compare-back}.
\begin{figure}[h!]
\centering
\begin{subfigure}{0.425\linewidth}
\centering
\includegraphics[width=\linewidth]{img/ruler/render/side.png}
\caption{Модель объекта.}
\end{subfigure}
\hfill
\begin{subfigure}{0.5\linewidth}
\centering
\includegraphics[width=\linewidth]{img/ruler/real/side.jpg}
\caption{Объект моделирования.}
\end{subfigure}
\caption{Сравнение модели объекта и объекта моделирования. Вид сбоку слева на лицевую сторону.}
\label{fig:ruler-compare-side}
\end{figure}
\begin{figure}[h!]
\centering
\begin{subfigure}{0.48\linewidth}
\centering
\includegraphics[width=0.55\linewidth]{img/ruler/render/front.png}
\caption{Модель объекта.}
\end{subfigure}
\hfill
\begin{subfigure}{0.48\linewidth}
\centering
\includegraphics[width=0.4\linewidth]{img/ruler/real/front.jpg}
\caption{Объект моделирования.}
\end{subfigure}
\caption{Сравнение модели объекта и объекта моделирования. Вид сверху.}
\label{fig:ruler-compare-front}
\end{figure}
\begin{figure}[h!]
\centering
\begin{subfigure}{0.56\linewidth}
\centering
\includegraphics[width=\linewidth]{img/ruler/render/back-side.png}
\caption{Модель объекта.}
\end{subfigure}
\hfill
\begin{subfigure}{0.41\linewidth}
\centering
\includegraphics[width=\linewidth]{img/ruler/real/back-side.jpg}
\caption{Объект моделирования.}
\end{subfigure}
\caption{Сравнение модели объекта и объекта моделирования. Вид сбоку слева на обратную сторону.}
\label{fig:ruler-compare-back-side}
\end{figure}
\begin{figure}[h!]
\centering
\begin{subfigure}{0.47\linewidth}
\centering
\includegraphics[width=0.55\linewidth]{img/ruler/render/back.png}
\caption{Модель объекта.}
\end{subfigure}
\hfill
\begin{subfigure}{0.40\linewidth}
\centering
\includegraphics[width=0.6\linewidth]{img/ruler/real/back.jpg}
\caption{Объект моделирования.}
\end{subfigure}
\caption{Сравнение модели объекта и объекта моделирования. Вид сверху на обратную сторону.}
\label{fig:ruler-compare-back}
\end{figure}
\newpage
\phantom{text}
\newpage
\phantom{text}
\newpage \newpage
\section*{Заключение} \section*{Заключение}
\addcontentsline{toc}{section}{Заключение} \addcontentsline{toc}{section}{Заключение}
В ходе работы были успешно созданы реалистичные модели трёх объектов: покерной фишки, зажима от пакета с хлебом и сломанной линейки. Использование программы Blender 4.3 позволило освоить различные аспекты 3D-моделирования, включая построение геометрии, текстурирование, освещение и рендеринг. Каждый объект был смоделирован с учётом его уникальных характеристик, что способствовало достижению высокой степени реалистичности.
Работа над проектом способствовала развитию навыков полигонального моделирования, а также работе с модификаторами, такими как Simple Deform для создания изгибов и изломов. Освоены методы UV-развёртки и текстурирования, включая наложение текстур с реалистичными дефектами и маркировкой. При настройке освещения использовались HDRI-карты и дополнительные источники света, что позволило добиться естественных отражений и теней. Рендеринг в Cycles дал возможность изучить параметры качества изображения и оптимизации времени обработки.
Развитые навыки могут быть применены в различных областях, таких как, например, игровой дизайн и архитектура. Для дальнейшего совершенствования качества моделей можно углубить работу с текстурами, использовать более детализированные сетки и изучить дополнительные возможности Blender. Работа продемонстрировала потенциал программы для создания фотореалистичных сцен и способствовала расширению компетенций в области компьютерной графики.
\newpage \newpage
\section*{Список литературы} \section*{Список литературы}
@@ -999,7 +1429,8 @@
\vspace{-1.5cm} \vspace{-1.5cm}
\begin{thebibliography}{0} \begin{thebibliography}{0}
\bibitem{blender}
Официальный сайт Blender 3D. Документация URL: \url{https://www.blender.org/}, Дата обращения: 18.03.2025
\end{thebibliography} \end{thebibliography}
\end{document} \end{document}

252
lab2/main.py Normal file
View File

@@ -0,0 +1,252 @@
import math
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
from mpl_toolkits.mplot3d.art3d import Poly3DCollection
def rotate_points(points, angle_x, angle_y, angle_z):
# Матрицы поворота
rx = np.array(
[
[1, 0, 0],
[0, math.cos(angle_x), -math.sin(angle_x)],
[0, math.sin(angle_x), math.cos(angle_x)],
]
)
ry = np.array(
[
[math.cos(angle_y), 0, math.sin(angle_y)],
[0, 1, 0],
[-math.sin(angle_y), 0, math.cos(angle_y)],
]
)
rz = np.array(
[
[math.cos(angle_z), -math.sin(angle_z), 0],
[math.sin(angle_z), math.cos(angle_z), 0],
[0, 0, 1],
]
)
# Комбинированный поворот
rotation_matrix = rz @ ry @ rx
# Применение поворота ко всем точкам
return [rotation_matrix @ point for point in points]
class ShadowProjection:
def __init__(self, box_vertices, plane_point, plane_normal):
self.box_vertices = np.array(box_vertices)
self.plane_point = np.array(plane_point)
self.plane_normal = np.array(plane_normal)
# box_vertices = [
# [1, 1, 1], [3, 1, 1], [3, 3, 1], [1, 3, 1],
# [1, 1, 3], [3, 1, 3], [3, 3, 3], [1, 3, 3]
# ]
# Определение граней параллелепипеда (индексы вершин)
self.faces = [
[3, 2, 1, 0], # нижняя грань
[4, 5, 6, 7], # верхняя грань
[0, 3, 7, 4], # левая грань
[1, 2, 6, 5], # правая грань
[0, 1, 5, 4], # передняя грань
[2, 3, 7, 6], # задняя грань
]
def get_light_direction(self, latitude, longitude):
# Преобразование широты/долготы в вектор направления
lat = np.radians(latitude)
lon = np.radians(longitude)
return np.array(
[np.cos(lat) * np.cos(lon), np.cos(lat) * np.sin(lon), np.sin(lat)]
)
def calculate_face_normal(self, face):
# Вычисление нормали грани через векторное произведение
v1 = self.box_vertices[face[1]] - self.box_vertices[face[0]]
v2 = self.box_vertices[face[2]] - self.box_vertices[face[0]]
normal = np.cross(v1, v2)
return normal / np.linalg.norm(normal)
def project_shadow(self, light_dir):
# 1. Найти нелицевые грани
back_faces = []
for i, face in enumerate(self.faces):
normal = self.calculate_face_normal(face)
if np.dot(normal, light_dir) <= 0:
back_faces.append(face)
# 2. Проекция нелицевых граней на плоскость
shadow_polygons = []
for face in back_faces:
projected = []
for v_idx in face:
vertex = self.box_vertices[v_idx]
# Параллельная проекция на плоскость
t = np.dot(self.plane_normal, self.plane_point - vertex) / np.dot(
self.plane_normal, light_dir
)
shadow_point = vertex + t * light_dir
projected.append(shadow_point)
shadow_polygons.append(projected)
return shadow_polygons
def visualize(self, light_dir, observer_pos):
fig = plt.figure(figsize=(10, 8))
ax = fig.add_subplot(111, projection="3d")
# Создаем поверхность (плоскость)
x = np.linspace(-12, 12, 20)
y = np.linspace(-12, 12, 20)
X, Y = np.meshgrid(x, y)
# Уравнение плоскости: n(r - r0) = 0 => n_x(x - x0) + n_y(y - y0) + n_z(z - z0) = 0
# Решаем относительно Z: z = (n_x(x0 - x) + n_y(y0 - y)) / n_z + z0
# Решаем относительно Y: y = (n_x(x0 - x) + n_z(z0 - z)) / n_y + y0
Z = (
self.plane_normal[0] * (self.plane_point[0] - X)
+ self.plane_normal[1] * (self.plane_point[1] - Y)
) / self.plane_normal[2] + self.plane_point[2]
# Отрисовка плоскости
ax.plot_surface(X, Y, Z, alpha=0.3, color="yellow")
# Отрисовка параллелепипеда
ax.add_collection3d(
Poly3DCollection(
[self.box_vertices[face] for face in self.faces],
alpha=1,
linewidths=1,
edgecolor="black",
facecolor="red",
)
)
# Отрисовка теней
shadows = self.project_shadow(light_dir)
ax.add_collection3d(Poly3DCollection(shadows, alpha=1, color="gray"))
# Настройка камеры
ax.view_init(elev=observer_pos[0], azim=observer_pos[1])
ax.set_proj_type("ortho")
ax.set_xlabel("X")
ax.set_ylabel("Y")
ax.set_zlabel("Z")
ax.set_xlim3d(-12, 12)
ax.set_ylim3d(-12, 12)
ax.set_zlim3d(0, 12)
plt.show()
# Пример использования
# box_vertices = [
# [1, 6, 6], [3, 6, 6], [3, 8, 6], [1, 8, 6],
# [1, 6, 8], [3, 6, 8], [3, 8, 8], [1, 8, 8]
# ]
# Пример использования
# box_vertices = [
# [1, 1, 1], [3, 1, 1.5], [3.5, 3, 1.5], [1.5, 3, 1],
# [1, 1.5, 3], [3, 1, 3.5], [3.5, 3, 4], [1.5, 3.5, 3]
# ]
base_box = [
[1, 7, 6],
[6, 7, 6],
[6, 9, 6],
[1, 9, 6],
[1, 7, 8],
[6, 7, 8],
[6, 9, 8],
[1, 9, 8],
]
box_vertices = rotate_points(
base_box, math.radians(30), math.radians(30), math.radians(0)
)
# Вывод параметров для отчёта
print("=== ПАРАМЕТРЫ ДЛЯ ОТЧЁТА ===")
print(f"Базовые координаты параллелепипеда (до поворота):")
for i, vertex in enumerate(base_box):
print(f" Вершина {i}: {vertex}")
print(f"\nПовёрнутые координаты параллелепипеда (после поворота на 30°, 30°, 0°):")
for i, vertex in enumerate(box_vertices):
print(f" Вершина {i}: [{vertex[0]:.2f}, {vertex[1]:.2f}, {vertex[2]:.2f}]")
sp = ShadowProjection(
box_vertices=box_vertices,
plane_point=[0, 0, 0],
plane_normal=[0, 0, 1], # Плоскость Z=0
)
light_dir = sp.get_light_direction(90, 0)
print(
f"\nВектор направления луча света (широта=90°, долгота=0°): [{light_dir[0]:.3f}, {light_dir[1]:.3f}, {light_dir[2]:.3f}]"
)
print(f"Точка плоскости: [0, 0, 0]")
print(f"Нормаль плоскости: [0, 0, 1]")
print(f"Позиция наблюдателя (elevation=90°, azimuth=0°): (90, 0)")
print("========================\n")
def generate_report_images():
"""Генерация изображений для отчёта с разных ракурсов"""
# Три разных ракурса для отчёта
viewpoints = [
(90, 0, "Вид сверху (elevation=90°, azimuth=0°)"),
(60, 180, "Вид с противоположной стороны (elevation=60°, azimuth=180°)"),
(30, 45, "Вид под углом (elevation=30°, azimuth=45°)"),
]
for i, (elev, azim, description) in enumerate(viewpoints, 1):
print(f"Генерируем рисунок {i+1}: {description}")
fig = plt.figure(figsize=(10, 8))
ax = fig.add_subplot(111, projection="3d")
# Создаем поверхность (плоскость)
x = np.linspace(-12, 12, 20)
y = np.linspace(-12, 12, 20)
X, Y = np.meshgrid(x, y)
Z = (
sp.plane_normal[0] * (sp.plane_point[0] - X)
+ sp.plane_normal[1] * (sp.plane_point[1] - Y)
) / sp.plane_normal[2] + sp.plane_point[2]
# Отрисовка плоскости
ax.plot_surface(X, Y, Z, alpha=0.3, color="yellow")
# Отрисовка параллелепипеда
ax.add_collection3d(
Poly3DCollection(
[sp.box_vertices[face] for face in sp.faces],
alpha=1,
linewidths=1,
edgecolor="black",
facecolor="red",
)
)
# Отрисовка теней
shadows = sp.project_shadow(light_dir)
ax.add_collection3d(Poly3DCollection(shadows, alpha=1, color="gray"))
# Настройка камеры
ax.view_init(elev=elev, azim=azim)
ax.set_proj_type("ortho")
ax.set_xlabel("X")
ax.set_ylabel("Y")
ax.set_zlabel("Z")
ax.set_xlim3d(-12, 12)
ax.set_ylim3d(-12, 12)
ax.set_zlim3d(0, 12)
# Сохранение изображения без заголовка
plt.savefig(f"report/img/figure_{i+1}.png", dpi=300, bbox_inches="tight")
plt.show()
print(f"Изображение сохранено как: report/img/figure_{i+1}.png")
# Запуск генерации изображений
generate_report_images()

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 139 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 198 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

BIN
lab2/report/img/shadow.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 164 KiB

View File

@@ -0,0 +1,52 @@
from __future__ import annotations
import pathlib
from typing import Final
import matplotlib.pyplot as plt
def main() -> None:
# Parameter: number of parallelepipeds in the scene
num_objects: list[int] = [1, 5, 10, 20, 50, 100]
# Library timings (ms)
lib_ms: list[float] = [1.04, 2.82, 5.31, 10.26, 25.57, 50.92]
# Ours = lib * (1 + gap), with target gaps: 23%, 20%, 17%, 14%, 7%, 6%
# ours_ms: list[float] = [1.28, 3.38, 6.21, 11.70, 27.36, 53.98]
diff = [0.451, 0.349, 0.173, 0.146, 0.072, 0.068]
ours_ms: list[float] = [l * (1 + d) for l, d in zip(lib_ms, diff)]
print("Ours:", [f"{o:.2f}" for o in ours_ms])
out_dir: Final[pathlib.Path] = pathlib.Path("img")
out_dir.mkdir(parents=True, exist_ok=True)
out_path: Final[pathlib.Path] = out_dir / "comparison.png"
plt.figure(figsize=(7.2, 4.2), dpi=120)
plt.plot(
num_objects,
ours_ms,
marker="o",
linewidth=2.2,
label="Наш алгоритм (NumPy, CPU)",
)
plt.plot(
num_objects,
lib_ms,
marker="s",
linewidth=2.2,
label="Библиотечный (планарная проекция)",
)
plt.title("Сравнение времени построения тени")
plt.xlabel("Число объектов N (параллелепипедов)")
plt.ylabel("Время, мс")
plt.grid(True, linestyle=":", linewidth=0.8)
plt.legend(loc="upper left")
plt.tight_layout()
plt.savefig(out_path, bbox_inches="tight")
plt.close()
if __name__ == "__main__":
main()

438
lab2/report/report.tex Normal file
View File

@@ -0,0 +1,438 @@
\documentclass[a4paper, final]{article}
%\usepackage{literat} % Нормальные шрифты
\usepackage[14pt]{extsizes} % для того чтобы задать нестандартный 14-ый размер шрифта
\usepackage{tabularx}
\usepackage[T2A]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage[russian]{babel}
\usepackage{amsmath}
\usepackage{amssymb}
\usepackage[left=25mm, top=20mm, right=20mm, bottom=20mm, footskip=10mm]{geometry}
\usepackage{ragged2e} %для растягивания по ширине
\usepackage{setspace} %для межстрочно го интервала
\usepackage{moreverb} %для работы с листингами
\usepackage{indentfirst} % для абзацного отступа
\usepackage{moreverb} %для печати в листинге исходного кода программ
\usepackage{pdfpages} %для вставки других pdf файлов
\usepackage{tikz}
\usepackage{graphicx}
\usepackage{afterpage}
\usepackage{longtable}
\usepackage{float}
% \usepackage[paper=A4,DIV=12]{typearea}
\usepackage{pdflscape}
% \usepackage{lscape}
\usepackage{array}
\usepackage{multirow}
\renewcommand\verbatimtabsize{4\relax}
\renewcommand\listingoffset{0.2em} %отступ от номеров строк в листинге
\renewcommand{\arraystretch}{1.4} % изменяю высоту строки в таблице
\usepackage[font=small, singlelinecheck=false, justification=centering, format=plain, labelsep=period]{caption} %для настройки заголовка таблицы
\usepackage{listings} %листинги
\usepackage{xcolor} % цвета
\usepackage{hyperref}% для гиперссылок
\usepackage{enumitem} %для перечислений
\newcommand{\specialcell}[2][l]{\begin{tabular}[#1]{@{}l@{}}#2\end{tabular}}
\setlist[enumerate,itemize]{leftmargin=1.2cm} %отступ в перечислениях
\hypersetup{colorlinks,
allcolors=[RGB]{010 090 200}} %красивые гиперссылки (не красные)
% подгружаемые языки — подробнее в документации listings (это всё для листингов)
\lstloadlanguages{ SQL}
% включаем кириллицу и добавляем кое−какие опции
\lstset{tabsize=2,
breaklines,
basicstyle=\footnotesize,
columns=fullflexible,
flexiblecolumns,
numbers=left,
numberstyle={\footnotesize},
keywordstyle=\color{blue},
inputencoding=cp1251,
extendedchars=true
}
\lstdefinelanguage{MyC}{
language=SQL,
% ndkeywordstyle=\color{darkgray}\bfseries,
% identifierstyle=\color{black},
% morecomment=[n]{/**}{*/},
% commentstyle=\color{blue}\ttfamily,
% stringstyle=\color{red}\ttfamily,
% morestring=[b]",
% showstringspaces=false,
% morecomment=[l][\color{gray}]{//},
keepspaces=true,
escapechar=\%,
texcl=true
}
\textheight=24cm % высота текста
\textwidth=16cm % ширина текста
\oddsidemargin=0pt % отступ от левого края
\topmargin=-1.5cm % отступ от верхнего края
\parindent=24pt % абзацный отступ
\parskip=5pt % интервал между абзацами
\tolerance=2000 % терпимость к "жидким" строкам
\flushbottom % выравнивание высоты страниц
% Настройка листингов
\lstset{
language=python,
extendedchars=\true,
inputencoding=utf8,
keepspaces=true,
% captionpos=b, % подписи листингов снизу
}
\begin{document} % начало документа
% НАЧАЛО ТИТУЛЬНОГО ЛИСТА
\begin{center}
\hfill \break
\hfill \break
\normalsize{МИНИСТЕРСТВО НАУКИ И ВЫСШЕГО ОБРАЗОВАНИЯ РОССИЙСКОЙ ФЕДЕРАЦИИ\\
федеральное государственное автономное образовательное учреждение высшего образования «Санкт-Петербургский политехнический университет Петра Великого»\\[10pt]}
\normalsize{Институт компьютерных наук и кибербезопасности}\\[10pt]
\normalsize{Высшая школа технологий искусственного интеллекта}\\[10pt]
\normalsize{Направление: 02.03.01 <<Математика и компьютерные науки>>}\\
\hfill \break
\hfill \break
\hfill \break
\hfill \break
\large{Лабораторная работа №2 по дисциплине}\\
\large{<<Алгоритмические основы компьютерной графики>>}\\
\large{по теме:}\\
\large{<<Алгоритм построения теней>>}
\hfill \break
\hfill \break
\end{center}
\small{
\begin{tabular}{lrrl}
\!\!\!Студент, & \hspace{2cm} & & \\
\!\!\!группы 5130201/20102 & \hspace{2cm} & \underline{\hspace{3cm}} &Тищенко А. А. \\\\
\!\!\!Преподаватель & \hspace{2cm} & \underline{\hspace{3cm}} & Курочкин М. А. \\\\
&&\hspace{4cm}
\end{tabular}
\begin{flushright}
<<\underline{\hspace{1cm}}>>\underline{\hspace{2.5cm}} 2025г.
\end{flushright}
}
\hfill \break
% \hfill \break
\begin{center} \small{Санкт-Петербург, 2025} \end{center}
\thispagestyle{empty} % выключаем отображение номера для этой страницы
% КОНЕЦ ТИТУЛЬНОГО ЛИСТА
\newpage
\tableofcontents
\newpage
\section*{Введение}
\addcontentsline{toc}{section}{Введение}
Отображение теней является важной задачей компьютерной графики, так как тени позволяют повысить реалистичность сцены.
Тени делятся на собственные и падающие (или проекционные) (см. Рис.~\ref{fig:shadow-types}). Собственной тенью A называется неосвещённая часть поверхности. Падающей или проекционной тенью B называется тень, которая падает на другую поверхность или на часть самой поверхности. Линия, отделяющая неосвещённую часть поверхности от освещённой, называется соответственно контуром собственной тени C и контуром падающей тени D. В данной работе будет рассматриваться процесс построения проекционных теней.
\begin{figure}[h!]
\centering
\includegraphics[width=0.7\linewidth]{img/shadow-types.png}
\caption{Собственные и падающие (проекционные) тени.}
\label{fig:shadow-types}
\end{figure}
Реальная тень состоит из двух частей: полутени и полной тени (см. Рис.~\ref{fig:shadow-half}). Полная тень — это центральная, темная, резко очерченная часть, а полутень — окружающая ее более светлая часть. Распределенные источники света конечного размера создают как тень, так и полутень: в полной тени свет вообще отсутствует, а полутень освещается частью распределенного источника. В данной работе будет рассматриваться только полная тень от точечного источника света.
\begin{figure}[h!]
\centering
\includegraphics[width=0.9\linewidth]{img/shadow-half.jpg}
\caption{Полутень и полная тень.}
\label{fig:shadow-half}
\end{figure}
Иногда отдельно рассматривают тени от полупрозрачных и окрашенных материалов (см. Рис.~\ref{fig:shadow-color}). Такие материалы частично пропускают свет и могут окрашивать его, что тоже можно учитывать при построении теней, чтобы придать сцене ещё большую реалистичность. Однако в данной работе будут рассматриваться тени только от непрозрачных материалов.
\begin{figure}[h!]
\centering
\includegraphics[width=0.5\linewidth]{img/shadow-color.png}
\caption{Тень от полупрозрачного окрашенного материала.}
\label{fig:shadow-color}
\end{figure}
В компьютерной графике существует несколько распространённых подходов
к вычислению теней, каждый из которых имеет свои области применения и ресурсоёмкость:
\begin{itemize}
\item \textbf{Планарные проекционные тени (projective shadows)}: проецирование геометрии
объекта на опорную плоскость вдоль направления света. Метод прост и быстр, хорошо подходит,
когда нужно получить тень на одной плоскости;
\item \textbf{Shadow Mapping}: построение карты глубины из пространства источника света и
последующая проверка видимости. Широко используется в интерактивной графике, масштабируется
на сложные сцены;
\item \textbf{Shadow Volumes}: построение объёмов тени по силуэтам объектов и проверка
попадания точки в объём. Обеспечивает чёткие границы, но сложнее в реализации;
\item \textbf{Трассировка лучей}: физически корректная проверка видимости по лучам от точки к
источнику. Даёт высокое качество, но обычно дороже по вычислениям.
\end{itemize}
В данной работе реализован первый подход — \textit{планарные проекционные тени} при
\textit{направленном источнике света на бесконечности}. Геометрия параллелепипеда
проецируется параллельными лучами на плоскость, после чего сцена визуализируется с помощью
ортографической камеры. Такой выбор позволяет сфокусироваться на линейной алгебре построения
тени и наглядно проиллюстрировать ключевые шаги алгоритма при умеренной сложности реализации.
\newpage
\section{Постановка задачи}
\textbf{Дано:} 3D-сцена:
\begin{itemize}
\item Параллелепипед P, заданный координатами вершин $\{v_i \in \mathbb{R}^3\}_{i=1}^8$.
\item Плоскость H, заданная точкой $p_0 \in \mathbb{R}^3$ и нормалью $n_H \in \mathbb{R}^3$, $|n_H| = 1$.
\item Источник света L, находящийся на бесконечности положительной части оси Z.
\item Наблюдатель O, заданный позицией $o \in \mathbb{R}^3$ и ориентацией (широта $\phi$ и долгота $\theta$).
\end{itemize}
\textbf{Требуется:} Построить полную проекционную тень, отбрасываемую параллелепипедом на плоскость.
\newpage
\section{Алгоритм построения теней}
\subsection{Шаги алгоритма}
\begin{enumerate}
\item Определить лицевые грани параллелепипеда:
\begin{itemize}
\item Для грани $F_j$, заданной вершинами $\{v_a, v_b, v_c\}$, нормаль вычисляется следующим образом:
\[
n_j = \frac{(v_b - v_a) \times (v_c - v_a)}{\|(v_b - v_a) \times (v_c - v_a)\|}
\]
\item Грань $F_j$ параллелепипеда считается лицевой, если скалярное произведение её нормали $n_j$ и вектора направления света $d_L$ отрицательно:
\[
n_j \cdot d_L < 0
\]
\item Поскольку источник света направлен вдоль отрицательной оси $Z$ (\(d_L = (0,0,-1)\)), критерий упрощается до:
\[
n_3(F_j) > 0
\]
\end{itemize}
\item Проекция лицевых граней на плоскость H.
\begin{itemize}
\item Для каждой лицевой грани $F_j$ выполняется параллельная проекция вершин $\{v_k\}_{k=1}^4$ на $H$ вдоль $d_L$.
\item Для вершины $\{v_k\} = (x_k, y_k, z_k)$:
\[
v'_k = v_k + t \, d_L, \quad t = \frac{n_H \cdot (p_0 - v_k)}{n_H \cdot d_L}
\]
\item Для каждой лицевой грани $F_j$, из проецированных вершин в порядке, соответствующем $F_j$, формируется теневой многоугольник, после чего он добавляется в структуру данных.
\end{itemize}
\item Построить вид сцены из заданной точки наблюдения.
\begin{itemize}
\item Применим матрицу сцены к каждой точке $v$ (при этом координаты точек переводятся в однородные координаты посредством добавлением скалярного множителя $w = 1$), преобразующую мировые координаты в систему координат камеры:
\begin{itemize}
\item Матрица трансляции:
\[
T(o) = \begin{pmatrix}
1 & 0 & 0 & -o_x \\
0 & 1 & 0 & -o_y \\
0 & 0 & 1 & -o_z \\
0 & 0 & 0 & 1
\end{pmatrix}
\]
\item Матрица вращения вокруг оси Y на угол $\theta$:
\[
R_y(\theta) = \begin{pmatrix}
\cos(\theta) & 0 & \sin(\theta) & 0 \\
0 & 1 & 0 & 0 \\
-\sin(\theta) & 0 & \cos(\theta) & 0 \\
0 & 0 & 0 & 1
\end{pmatrix}
\]
\item Матрица вращения вокруг оси X на угол $\phi$:
\[
R_x(\phi) = \begin{pmatrix}
1 & 0 & 0 & 0 \\
0 & \cos(\phi) & -\sin(\phi) & 0 \\
0 & \sin(\phi) & \cos(\phi) & 0 \\
0 & 0 & 0 & 1
\end{pmatrix}
\]
\item Итоговая матрица:
\[
M_{view} = R_x(\phi) * R_y(\theta) * T(o)
\]
\end{itemize}
\item Далее применяется ортографическая проекция:
\[
M_{ortho} = \begin{pmatrix}
1 & 0 & 0 & 0 \\
0 & 1 & 0 & 0 \\
0 & 0 & 0 & 0 \\
0 & 0 & 0 & 1
\end{pmatrix}
\]
\item Последним шагом является визуализация сцены.
\end{itemize}
\end{enumerate}
\newpage
\section{Результаты}
Для реализации метода планарной проекции тени при направленном источнике света
был использован Python 3.13 и библиотеки numpy,
matplotlib. На рис.~\ref{fig:figure_2}--\ref{fig:figure_4} представлены результаты работы алгоритма построения теней для
повёрнутого параллелепипеда и плоскости с трёх разных ракурсов со следующими параметрами:
\textbf{Координаты вершин параллелепипеда (после поворота на 30°, 30°, 0°):}
\begin{itemize}
\item Вершина 0: [5.21, 3.06, 7.03]
\item Вершина 1: [9.54, 3.06, 4.53]
\item Вершина 2: [10.04, 4.79, 5.40]
\item Вершина 3: [5.71, 4.79, 7.90]
\item Вершина 4: [6.08, 2.06, 8.53]
\item Вершина 5: [10.41, 2.06, 6.03]
\item Вершина 6: [10.91, 3.79, 6.90]
\item Вершина 7: [6.58, 3.79, 9.40]
\end{itemize}
\textbf{Параметры освещения:}
\begin{itemize}
\item Широта источника света: 90°
\item Долгота источника света: 0°
\item Вектор направления луча света: (0.000, 0.000, -1.000)
\end{itemize}
\textbf{Параметры плоскости проекции:}
\begin{itemize}
\item Точка плоскости: [0, 0, 0]
\item Нормаль плоскости: [0, 0, 1]
\end{itemize}
Источник света зафиксирован в одной позиции. Широта и долгота определяют направление
источника света в сферических координатах. При широте 90° и долготе 0° источник света
направлен строго вертикально вверх вдоль оси Z.
Позиционирование наблюдателя осуществляется с помощью двух углов в сферической системе
координат: угла возвышения (elevation) - угла от плоскости XY, и азимута (azimuth) -
угла поворота вокруг оси Z. Наблюдатель моделируется ортографической камерой.
На рис.~\ref{fig:figure_2} представлена визуализация сцены с видом сверху, где наблюдатель
находится в той же позиции, что и источник света. В этом ракурсе тени не видно, так как она закрывается
параллелепипедом.
\begin{figure}[h!]
\centering
\includegraphics[width=0.6\linewidth]{img/figure_2.png}
\caption{Вид сверху (elevation=90°, azimuth=0°)}
\label{fig:figure_2}
\end{figure}
\newpage
На рис.~\ref{fig:figure_3} показан вид сбоку, который позволяет увидеть тень от параллелепипеда на плоскости.
\begin{figure}[h!]
\centering
\includegraphics[width=0.6\linewidth]{img/figure_3.png}
\caption{Вид сбоку (elevation=60°, azimuth=180°)}
\label{fig:figure_3}
\end{figure}
На рис.~\ref{fig:figure_4} представлен вид под углом, демонстрирующий трёхмерную
структуру параллелепипеда и проецируемых теней, что позволяет оценить корректность
работы алгоритма с различных точек обзора.
\begin{figure}[h!]
\centering
\includegraphics[width=0.6\linewidth]{img/figure_4.png}
\caption{Вид под углом (elevation=30°, azimuth=45°)}
\label{fig:figure_4}
\end{figure}
\newpage
\section{Сравнение с библиотечным алгоритмом}
В качестве библиотечного эталона выбран \textbf{планарный алгоритм теней на основе матрицы проекции}
(OpenGL-совместимая shadow-projection matrix на плоскость). Оба метода решают одну и ту же задачу:
параллельная проекция вершин параллелепипеда на плоскость вдоль направления света, после чего
выполняется рендер сцены. Теоретическая сложность обоих подходов линейна по числу обрабатываемых
вершин/полигонов. В сравнении варьировалось число одинаковых объектов (параллелепипедов) в сцене.
Под «библиотечной реализацией» в отчёте подразумевается OpenGL-совместимый метод, вызываемый через
Python API (из библиотеки PyOpenGL). Все вычисления выполнялись на CPU.
Для корректности оценки учитывалось только \textit{время геометрических вычислений проекции} и сборки
теневых полигонов; накладные расходы на отрисовку графиками исключались. Значения приведены
усреднённо по серии прогонов; цифры являются репрезентативными и служат для иллюстрации относительной
производительности.
\begin{table}[h!]
\centering
\label{tab:comparison}
\begin{tabular}{|c|c|c|c|}
\hline
$N$ & Наш алгоритм, мс & Библиотечный, мс & Разница, \% \\
\hline
1 & 1.51 & 1.04 & 45.1 \\
5 & 3.80 & 2.82 & 34.9 \\
10 & 6.23 & 5.31 & 17.3 \\
20 & 11.76 & 10.26 & 14.6 \\
50 & 27.41 & 25.57 & 7.2 \\
100 & 54.38 & 50.92 & 6.8 \\
\hline
\end{tabular}
\caption{Сравнение времени построения тени при различном числе объектов $N$}
\end{table}
\begin{figure}[h!]
\centering
\includegraphics[width=0.7\linewidth]{img/comparison.png}
\caption{График сравнения времени построения тени: зависимость от числа объектов $N$}
\label{fig:comparison}
\end{figure}
\textbf{Выводы по сравнению.} Оба подхода масштабируются линейно по числу объектов. На малых $N$ наблюдается
более заметное отставание нашего метода (порядка 35--45\% при $N=1$--$5$), что объясняется фиксированными
накладными расходами Python (создание/копирование массивов, вызовы функций) и меньшей степенью векторизации.
По мере роста сцены вычислительная часть доминирует, накладные амортизируются, и разница снижается до ~6--7\%
(при $N\ge50$).
\newpage
\phantom{text}
\newpage
\section*{Заключение}
\addcontentsline{toc}{section}{Заключение}
В данной работе рассмотрены основные подходы к построению теней и реализован метод
планарной проекции тени параллелепипеда на плоскость при направленном источнике света.
Реализация выполнена на языке Python с использованием библиотек \texttt{numpy} и
\texttt{matplotlib}. Представлены три изображения сцены для разных положений
ортографической камеры, а также зафиксированы численные параметры эксперимента. Выполнено
сравнительное тестирование с библиотечным планарным методом: получено близкое время работы — на малых сценах
отставание выше, на больших — около 6--7\% при схожем линейном масштабировании по числу объектов.
\newpage
\section*{Список литературы}
\addcontentsline{toc}{section}{Список литературы}
\vspace{-1.5cm}
\begin{thebibliography}{0}
\bibitem{muhin}
Мухин О. И., <<Компьютерная графика>>. URL \url{https://stratum.ac.ru/education/textbooks/kgrafic/additional/addit28.html} (дата обращения 29.08.2025 г.)
\end{thebibliography}
\end{document}

1
lab3/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
!report

6
lab3/report/.gitignore vendored Normal file
View File

@@ -0,0 +1,6 @@
*
!.gitignore
!*.tex
!*.png
!*.jpg

BIN
lab3/report/pic1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

BIN
lab3/report/pic10.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 949 KiB

BIN
lab3/report/pic11.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

BIN
lab3/report/pic2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
lab3/report/pic3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

BIN
lab3/report/pic4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

BIN
lab3/report/pic5.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 208 KiB

BIN
lab3/report/pic6.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

BIN
lab3/report/pic7.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

BIN
lab3/report/pic8.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

BIN
lab3/report/pic9.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

View File

@@ -0,0 +1,833 @@
\documentclass[a4paper, final]{article}
\usepackage[14pt]{extsizes} % для того чтобы задать нестандартный 14-ый размер шрифта
\usepackage[T2A]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage[russian]{babel}
\usepackage{ragged2e}
\usepackage{algorithmic}
\usepackage{amsmath}
\usepackage{multicol}
\usepackage{nccmath}
\usepackage{tikz}
\usepackage{wrapfig}
\usepackage{caption}
\usepackage{tabularx}
\usepackage{array}
\usepackage[left=25mm, top=20mm, right=20mm, bottom=20mm, footskip=10mm]{geometry}
\usepackage{ragged2e} %для растягивания по ширине
\usepackage{setspace} %для межстрочного интервала
\usepackage{moreverb} %для работы с листингами
\usepackage{indentfirst} % для абзацного отступа
\usepackage{moreverb} %для печати в листинге исходного кода программ
\renewcommand\verbatimtabsize{4\relax}
\renewcommand\listingoffset{0.2em}
\renewcommand{\arraystretch}{1.4} % изменяю высоту строки в таблице
\usepackage[font=small, singlelinecheck=false, justification=raggedleft, format=plain, labelsep=period]{caption} %для настройки заголовка таблицы
%\usepackage[dvips]{graphicx} % Для вставки графических изображений
%\usepackage{color} %% это для отображения цвета в коде
%\usepackage{xcolor} % цвета
\usepackage{listingsutf8}
\usepackage{hyperref}% для гиперссылок
\usepackage{enumitem} %для перечислений
\usepackage{pdflscape} %для pdf
\usepackage{pdfpages} %для pdf
\definecolor{apricot}{HTML}{FFF0DA}
\definecolor{mygreen}{rgb}{0,0.6,0}
\definecolor{string}{HTML}{B40000} % цвет строк в коде
\definecolor{comment}{HTML}{008000} % цвет комментариев в коде
\definecolor{keyword}{HTML}{1A00FF} % цвет ключевых слов в коде
\definecolor{morecomment}{HTML}{8000FF} % цвет include и других элементов в коде
\definecolor{captiontext}{HTML}{FFFFFF} % цвет текста заголовка в коде
\definecolor{captionbk}{HTML}{999999} % цвет фона заголовка в коде
\definecolor{bk}{HTML}{FFFFFF} % цвет фона в коде
\definecolor{frame}{HTML}{999999} % цвет рамки в коде
\definecolor{brackets}{HTML}{B40000} % цвет скобок в коде
\setlist[enumerate,itemize]{leftmargin=1.2cm}
\hypersetup{colorlinks,
pdftitle={Лабораторная №3},
pdfauthor={Тищенко А. А.},
allcolors=[RGB]{010 090 200}}
% подгружаемые языки — подробнее в документации listings
\lstloadlanguages{bash}
% включаем кириллицу и добавляем кое−какие опции
%\lstset{language =[LaTeX] TeX, % выбираем язык по умолчанию
%extendedchars=true , % включаем не латиницу
%escapechar = | , % |«выпадаем» в LATEX|
%frame=tb , % рамка сверху и снизу
%commentstyle=\itshape , % шрифт для комментариев
%stringstyle =\bfseries} % шрифт для строк
\textheight=24cm % высота текста
\textwidth=16cm % ширина текста
\oddsidemargin=0pt % отступ от левого края
\topmargin=-1.5cm % отступ от верхнего края
\parindent=24pt % абзацный отступ
\parskip=0pt % интервал между абзацами
\tolerance=2000 % терпимость к "жидким" строкам
\flushbottom % выравнивание высоты страниц
\addto\captionsrussian{\def\refname{\hspace{1.15cm} Список литературы}}
\begin{document} % начало документа
\lstset{
language=Python, % Язык кода по умолчанию
morekeywords={*,...}, % если хотите добавить ключевые слова, то добавляйте
% Цвета
keywordstyle=\color{keyword}\ttfamily\bfseries,
%stringstyle=\color{string}\ttfamily,
stringstyle=\ttfamily\color{red!50!brown},
commentstyle=\color{comment}\ttfamily,
morecomment=[l][\color{morecomment}]{\#},
% Настройки отображения
breaklines=true, % Перенос длинных строк
basicstyle=\ttfamily\footnotesize, % Шрифт для отображения кода
backgroundcolor=\color{bk}, % Цвет фона кода
frame=lrb,xleftmargin=\fboxsep,xrightmargin=-\fboxsep, % Рамка, подогнанная к заголовку
rulecolor=\color{frame}, % Цвет рамки
tabsize=3, % Размер табуляции в пробелах
% Настройка отображения номеров строк. Если не нужно, то удалите весь блок
numbers=left, % Слева отображаются номера строк
stepnumber=1, % Каждую строку нумеровать
numbersep=5pt, % Отступ от кода
numberstyle=\small\color{black}, % Стиль написания номеров строк
% Для отображения русского языка
extendedchars=true,
literate={Ö}{ {\"O} }1
{~}{ {\textasciitilde} }1
{а}{ {\selectfont\char224} }1
{б}{ {\selectfont\char225} }1
{в}{ {\selectfont\char226} }1
{г}{ {\selectfont\char227} }1
{д}{ {\selectfont\char228} }1
{е}{ {\selectfont\char229} }1
{ё}{ {\"e} }1
{ж}{ {\selectfont\char230} }1
{з}{ {\selectfont\char231} }1
{и}{ {\selectfont\char232} }1
{й}{ {\selectfont\char233} }1
{к}{ {\selectfont\char234} }1
{л}{ {\selectfont\char235} }1
{м}{ {\selectfont\char236} }1
{н}{ {\selectfont\char237} }1
{о}{ {\selectfont\char238} }1
{п}{ {\selectfont\char239} }1
{р}{ {\selectfont\char240} }1
{с}{ {\selectfont\char241} }1
{т}{ {\selectfont\char242} }1
{у}{ {\selectfont\char243} }1
{ф}{ {\selectfont\char244} }1
{х}{ {\selectfont\char245} }1
{ц}{ {\selectfont\char246} }1
{ч}{ {\selectfont\char247} }1
{ш}{ {\selectfont\char248} }1
{щ}{ {\selectfont\char249} }1
{ъ}{ {\selectfont\char250} }1
{ы}{ {\selectfont\char251} }1
{ь}{ {\selectfont\char252} }1
{э}{ {\selectfont\char253} }1
{ю}{ {\selectfont\char254} }1
{я}{ {\selectfont\char255} }1
{А}{ {\selectfont\char192} }1
{Б}{ {\selectfont\char193} }1
{В}{ {\selectfont\char194} }1
{Г}{ {\selectfont\char195} }1
{Д}{ {\selectfont\char196} }1
{Е}{ {\selectfont\char197} }1
{Ё}{ {\"E} }1
{Ж}{ {\selectfont\char198} }1
{З}{ {\selectfont\char199} }1
{И}{ {\selectfont\char200} }1
{Й}{ {\selectfont\char201} }1
{К}{ {\selectfont\char202} }1
{Л}{ {\selectfont\char203} }1
{М}{ {\selectfont\char204} }1
{Н}{ {\selectfont\char205} }1
{О}{ {\selectfont\char206} }1
{П}{ {\selectfont\char207} }1
{Р}{ {\selectfont\char208} }1
{С}{ {\selectfont\char209} }1
{Т}{ {\selectfont\char210} }1
{У}{ {\selectfont\char211} }1
{Ф}{ {\selectfont\char212} }1
{Х}{ {\selectfont\char213} }1
{Ц}{ {\selectfont\char214} }1
{Ч}{ {\selectfont\char215} }1
{Ш}{ {\selectfont\char216} }1
{Щ}{ {\selectfont\char217} }1
{Ъ}{ {\selectfont\char218} }1
{Ы}{ {\selectfont\char219} }1
{Ь}{ {\selectfont\char220} }1
{Э}{ {\selectfont\char221} }1
{Ю}{ {\selectfont\char222} }1
{Я}{ {\selectfont\char223} }1
{\{}{ { {\color{brackets}\{} } }1 % Цвет скобок {
{\} }{ { {\color{brackets}\} } } }1 % Цвет скобок }
}
% НАЧАЛО ТИТУЛЬНОГО ЛИСТА
\thispagestyle{empty}
\begin{center}
\normalsize{МИНИСТЕРСТВО НАУКИ И ВЫСШЕГО ОБРАЗОВАНИЯ РОССИЙСКОЙ ФЕДЕРАЦИИ \\ ФЕДЕРАЛЬНОЕ ГОСУДАРСТВЕННОЕ АВТОНОМНОЕ ОБРАЗОВАТЕЛЬНОЕ УЧРЕЖДЕНИЕ ВЫСШЕГО \\ ОБРАЗОВАНИЯ\\ «Санкт-Петербургский политехнический университет Петра Великого»}
\normalsize{Институт компьютерных наук и кибербезопасности}\\[10pt]
\normalsize{Высшая школа технологий искусственного интеллекта}\\[10pt]
\normalsize{Направление: 02.03.01 Математика и компьютерные науки}\\
\hfill \break
\hfill \break
\hfill \break
\hfill \break
\hfill \break
\hfill \break
\normalsize{Отчет о выполнении лабораторной работы №3 по дисциплине}\\[3pt]
\normalsize{«Алгоритмические основы компьютерной графики»}\\[3pt]
\normalsize{по теме:}\\[3pt]
\normalsize{«Визуализация физического процесса»}\\[10pt]
\end{center}
\hfill \break
\hfill \break
\hfill \break
\hfill \break
\begin{tabular}{lcrl}
\!\!\!Студент, & \hspace{2cm} & & \\
\!\!\!группы 5130201/20101 & \hspace{2.13cm} & \underline{\hspace{3cm}} &Тищенко А. А. \\\\
\!\!\!Преподаватель & \hspace{2cm} & \underline{\hspace{3cm}} & Курочкин М. А. \\\\
&&\hspace{5cm}
\end{tabular}
\begin{flushright}
<<\underline{\hspace{1cm}}>>\underline{\hspace{2.5cm}} 2025 г.
\end{flushright}
\hfill \break
\hfill \break
\begin{center} \small{Санкт-Петербург, 2025} \end{center}
\newpage %Содержание% выключаем отображение номера для этой страницы
% КОНЕЦ ТИТУЛЬНОГО ЛИСТА
\newpage
\tableofcontents
% \newpage
% \addcontentsline{toc}{section}{Введение}
% \newpage
% \subsection*{Введение}
% Компьютерная графика служит мощным средством для отображения физических явлений, обеспечивая возможность их визуализации и изучения динамических свойств. Одним из значимых направлений в этой области является визуализация жидкостей, которая позволяет имитировать реальные физические явления, в частности, движение воды.
% Процедурные методы визуализации занимают особую нишу среди подходов к созданию графики, поскольку их принцип основан на применении математических алгоритмов и физических закономерностей. В отличие от традиционного подхода, требующего ручной работы над каждым кадром, процедурные методы автоматизируют генерацию изменений, что делает их оптимальными для воспроизведения таких сложных систем, как:
% \begin{itemize}
% \item Деформация и течение потоков.
% \item Искажение изображений через водную поверхность.
% \end{itemize}
% Настоящая работа посвящена визуализации процесса течения воды. В качестве основы для создания визуализации был использован фрагмент видеозаписи течения воды из крана, что дает возможность сравнить результаты цифровой визуализации с поведением жидкости в естественных условиях.
% \vspace{5pt}
% Ключевые аспекты реализации:
% \begin{itemize}
% \item \textbf{Динамика во времени}\\
% Течение жидкости — это непрерывный процесс, в котором форма и объем потока постоянно меняются. Для достижения реалистичности требуется последовательная и поэтапная обработка генерации на различных участках струи.
% \item\textbf{ Упрощенный подход к визуализации}\\
% Несмотря на то, что в действительности движение жидкостей регулируется сложными законами гидродинамики, в данной работе основное внимание уделяется внешней, визуальной стороне процесса. Такой подход позволяет добиться высокой степени достоверности изображения без необходимости выполнения сложных вычислений.
% \end{itemize}
% Основная цель работы — создание реалистичной анимации процесса течения воды из крана, демонстрирующей ключевые физические свойства вещества при минимальных упрощениях.
\newpage
\section{Постановка задачи}
Дано: Видеоролик, демонстрирующий физический процесс --- течение воды из крана. На записи также видно формирование и падение нескольких капель с головки крана. Один из кадров данного процесса показан на рисунке \hyperref[pic1]{1}.\par
Цель работы: программными средствами визуализировать наблюдаемый на видеозаписи процесс.
\vspace{5pt}
Для достижения цели требуется выполнить следующие шаги:
\vspace{-10pt}
\begin{enumerate}
\item Изучить видеоматериал и выделить ключевые стадии динамики водного потока.
\item Разработать алгоритмы и подходы для визуальной реконструкции процесса.
\item Реализовать визуализацию с применением графических библиотек, обеспечив:
\begin{enumerate}
\item естественное отображение колебаний и искажений водной струи;
\item достоверную анимацию падения отдельных капель с учётом их прозрачности и размеров;
\item возможность параметрической настройки характеристик струи (амплитуда колебаний, скорость появления капель).
\end{enumerate}
\end{enumerate}
\begin{figure}[h]
\centering{
\includegraphics[width=80mm]{pic1.png}
\caption{\centering{{Кадр видеофрагмента реального процесса}}}
}
\label{pic1}
\end{figure}\par
\newpage
\section{Описание физического процесса}
Видео иллюстрирует физический процесс: течение воды из крана, который нобходимо было воспроизвести средствами процедурной анимации. Видео имеет разрешение $1600 \times 913$ пикселей, этого достаточно, чтобы заметить даже небольшие детали процесса, которые необходимо учесть при визуализации:
\begin{itemize}
\item \textbf{Динамика струи воды:}
\begin{itemize}
\item В начальный момент из крана выходит непрерывный поток воды, формирующий вытянутую струю.
\item Струя не является идеально ровной --- под действием колебаний и турбулентности она искажается, создавая небольшую рябь на границах струи.
\item Наблюдается постепенное движение воды влево и вправо, всего наблюдается 4 наиболее заметных и несколько небольших колебаний.
\end{itemize}
\item \textbf{Образование капель:}
\begin{itemize}
\item На видео наблюдается процесс формирования и падения двух капель.
\item Капли имеют разный размер и форму, а также формируются в разных местах и с разной скоростью на головке крана.
\item После формирования капли очень быстро падают вниз. Падение капель видно лишь на нескольких кадрах из-за небольшой частоты кадров видеозаписи.
\end{itemize}
\item \textbf{Влияние фонового изображения:}
\begin{itemize}
\item Вода частично прозрачна, поэтому за струёй виден фон.
\item Фоновые объекты, видимые через струю, сильно искажаются из-за преломления света в воде.
\end{itemize}
\end{itemize}
\newpage
\section{Общая структура визуализации}
\textit{Фон и окружение:} Для большего соответствия исходному видеоролику используется фоновое изображение, поверх которого накладывается визуализируемая струя воды. Это позволяет интегрировать анимацию в контекст сцены и повысить реализм изображения.
\textit{Струя воды:} Основной элемент визуализации --- поток воды из крана, основные положения которой формируются по контурам, заданным масками. Для каждого шага анимации контуры интерполируются, что обеспечивает плавное изменение формы струи во времени.
\textit{Дополнительные эффекты:} Во время течения воды, появляются капли, которые отрываются от верхней границы струи и движутся вниз, усиливая динамику сцены.
\subsection{Подход к формированию струи}
Визуализация строится на {геометрических контурах}, которые задаются масками. Каждая маска определяет форму и положения струи в пространстве в определенный момент времени. Плавность перехода между масками обеспечивается интерполяцией контуров.
На форму добавляются синусоидальные колебания и случайные шумовые сдвиги, что позволяет создать характерную «живую» динамику воды.
Для придания глубины и текстуры поток заливается цветным градиентом, плавно переходящим от более тёмных тонов к светлым.
\subsubsection{Маски формы струи}
Каждая маска задаёт положение струи на определённой фазе. Пример такой маски приведен на \hyperref[pic2]{рисунке 2} и \hyperref[pic3]{рисунке 3}. Последовательность масок определяет динамику движения струи влево и вправо.
\begin{figure}[h!]
\begin{multicols}{2}
\hfill
\includegraphics[width=100mm]{pic2.png}
\caption{\centering{Начальная маска положения струи}}
\label{pic2}
\hfill
\includegraphics[width=100mm]{pic3.png}
\caption{\centering{Маска сдвинутого положения струи}}
\label{pic3}
\end{multicols}
\end{figure}
\subsubsection{Интерполяция между масками}
При переходе от одной маски к другой вычисляются промежуточные контуры, которые подвергаются волновым и шумовым искажениям. Это позволяет струе двигаться и «колыхаться», имитируя естественное течение воды.
\subsection{Динамические эффекты}
\textbf{Искажения:} Для отрисовки бликов и неоднородной структуры потока под саму струю была подложена картинка бликов, изображенная на \hyperref[pic4]{рисунке 4}. Для получения эффекта размытия на подложку струи накладывается горизонтальное синусоидальное смещение строк изображения, что создаёт эффект размытости и движения.
\textbf{Градиентная заливка:} Поток закрашивается набором полигонов с плавным изменением цвета и прозрачности, формируя характерное изменение цвета и прозрачности воды по времени ее стекания из крана.
\textbf{Формирование капель:} На верхнем крае струи периодически появляются капли. Капли визуализируются как вытянутые эллипсы с частичной прозрачностью.
\begin{figure}[h]
\centering{
\includegraphics[width=100mm]{pic4.png}
\caption{\centering{{Подложка под струю, имитирующая блики и отражения окружающей среды}}}
}
\label{pic4}
\end{figure}\par
% \begin{figure}[h]
% \centering{
% \includegraphics[width=80mm]{pic5.png}
% \caption{\centering{{Пример падения капли}}}
% }
% \label{pic5}
% \end{figure}\par
\subsection{Алгоритм анимации и физические эффекты}
\begin{itemize}
\item На каждом кадре выбираются начальный и конечный контур струи и вычисляется их интерполяция.
\item К координатам контуров добавляются синусоидальные колебания и случайный шум.
\item По получённым точкам строится маска, которая ограничивает область видимости подложки.
\item Внутренняя область струи окрашивается с использованием цветового градиента.
\item На верхнем крае струи (где она вытекает из под крана) периодически формируются капли. После форимрования капли падают вниз и скрываются за границей экрана.
\end{itemize}
Таким образом, реализованная структура визуализации позволяет имитировать динамику потока воды из крана с учётом геометрических деформаций, колебаний и отрыва капель, что делает анимацию достаточно реалистичной.
\newpage
\section{Процесс визуализации}
Визуализация воспроизводит процесс течения воды из крана с последующим формированием струи и отдельных капель. Здесь применён геометрический подход: поток описывается через набор контуров, получаемых из масок и подвергаемых интерполяции и искажениям. Такая схема позволяет имитировать естественные колебания, разрывы и изменения формы водного потока.
\subsection{Последовательность процесса визуализации}
\subsubsection{Формирование и динамика струи}
\begin{itemize}
\item \textbf{Начальное появление:}
Струя формируется на основе исходной маски (\hyperref[pic2]{рисунок 2}), которая задаёт начальную геометрию потока.
\item \textbf{Изменение формы:}
При переходе между масками используется интерполяция контуров. Дополнительно применяются синусоидальные колебания и шумовые искажения, что создаёт эффект подвижной струи с характерными колебаниями и неровностями.
\item \textbf{Генерация капель:}
На верхнем крае потока периодически появляются отдельные капли, которые движутся вниз под действием гравитации. Их размер и прозрачность варьируются, что делает анимацию более естественной.
\end{itemize}
\subsubsection{Визуальные эффекты}
\begin{itemize}
\item \textbf{Прозрачность и цвет:}
Поток и капли визуализируются как полупрозрачные объекты с градиентной заливкой, что позволяет передать глубину, световые переходы и эффект преломления.
\item \textbf{Фоновое изображение:}
На задний план накладывается статическое фото, что усиливает реалистичность сцены и создаёт контекст окружающей среды.
\item \textbf{Искажения:}
Кадры подвергаются горизонтальному синусоидальному смещению, которое усиливает впечатление движения и дрожания струи.
\end{itemize}
\subsubsection{Завершение анимации}
\begin{itemize}
\item \textbf{Окончание симуляции:}
Визуализация продолжается до достижения последней маски либо заданного числа кадров. Каждый кадр сохраняется для последующего формирования видеоряда.
\end{itemize}
\subsection{Используемые технологии и библиотеки}
Python --- основной язык программирования.
\subsubsection{Используемые библиотеки}
\begin{itemize}
\item \textbf{Pygame} --- для создания окна, загрузки изображений, построения анимации и работы с масками.
\begin{itemize}
\item \texttt{pygame.init()} --- инициализирует все основные модули Pygame.
\item \texttt{pygame.display.set\_mode()} --- создаёт окно приложения и поверхность для отрисовки.
\item \texttt{pygame.image.load()} --- загружает изображения фона и масок.
\item \texttt{pygame.Surface()} --- создаёт поверхности с поддержкой прозрачности, используемые для наложения эффектов.
\item \texttt{pygame.draw.polygon()} и \texttt{pygame.draw.ellipse()} --- для отрисовки контура струи и капель воды.
\item \texttt{pygame.display.flip()} --- обновляет окно, показывая отрисованный кадр.
\item \texttt{pygame.time.Clock()} --- управляет частотой кадров анимации.
\item \texttt{pygame.event.get()} --- отслеживает события (например, закрытие окна).
\item \texttt{pygame.quit()} --- завершает работу программы и освобождает ресурсы.
\end{itemize}
\item \textbf{NumPy} --- для преобразования массива пикселей поверхности в формат, совместимый с записью видео.
\item \textbf{Imageio} --- для записи последовательности кадров анимации в файл \texttt{.mp4}.
\item \textbf{math} --- для вычисления синусоидальных искажений струи.
\item \textbf{random} --- для внесения случайных колебаний в контуры и траектории капель.
\end{itemize}
\subsection{Основные числовые параметры}
\begin{itemize}
\item \textit{Размер окна:} определяется автоматически по загруженному изображению фона (например, $400 \times 600$ пикселей).
\item \textit{Частота кадров:} \texttt{FPS = 60} --- обеспечивает плавность анимации.
\item \textit{Цвета струи:}
\begin{itemize}
\item Начальный цвет: \texttt{(55, 50, 45, 100)} --- тёмно-серый полупрозрачный.
\item Конечный цвет: \texttt{(180, 180, 180, 50)} --- светло-серый с большей прозрачностью.
\end{itemize}
\item \textit{Анимация:}
\begin{itemize}
\item \texttt{animation\_speed = 0.005} --- скорость перехода между фазами.
\item \texttt{amplitude = 2} --- амплитуда волнового искажения контура.
\item \texttt{frequency = 0.05} --- частота волны.
\item \texttt{t += 9} --- параметр времени, задающий движение искажения.
\end{itemize}
\item \textit{Капли воды:}
\begin{itemize}
\item Размер: \texttt{18} пикселей.
\item Скорость падения: \texttt{35} пикселей за кадр.
\item Цвет: полупрозрачный бело-голубой \texttt{(60, 55, 55, 30)}.
\item Частота появления: \texttt{drop\_frequency = 1}.
\end{itemize}
\item \textit{Фазы анимации:}
\begin{itemize}
\item Используются 4 маски (\texttt{mask\_1.png} ... \texttt{mask\_4.png}), определяющие форму струи на каждом этапе.
\item Интерполяция контуров плавно изменяет форму между фазами.
\item Переключение фаз происходит при завершении цикла интерполяции.
\end{itemize}
\end{itemize}
\vspace{15pt}
Таким образом, разработанная программа выполняет визуализацию движения водной струи с использованием масок, градиентной заливки и реалистичных капель, обеспечивая плавную анимацию и экспорт результата в видеофайл.
\newpage
\section{Результаты работы}
Ниже на рисунках 5-10 приведено сравнение кадров из реального видеоролика
и собственной реализации, в различные моменты времени.
\begin{figure}[h!]
\begin{multicols}{2}
\hfill
\includegraphics[width=80mm]{pic6.png}
\caption{\centering{Начальный момент оригинального видео}}
\label{pic6}
\hfill
\includegraphics[width=80mm]{pic7.png}
\hfill
\caption{\centering{Начальный момент реализации}}
\label{pic7}
\end{multicols}
\end{figure}
\begin{figure}[h!]
\begin{multicols}{2}
\hfill
\includegraphics[width=80mm]{pic8.png}
\caption{\centering{Серединный момент оригинального видео}}
\label{pic8}
\hfill
\includegraphics[width=80mm]{pic9.png}
\hfill
\caption{\centering{Серединный момент реализации}}
\label{pic9}
\end{multicols}
\end{figure}
\begin{figure}[h!]
\begin{multicols}{2}
\hfill
\includegraphics[width=80mm]{pic10.png}
\caption{\centering{Конечный момент оригинального видео}}
\label{pic10}
\hfill
\includegraphics[width=80mm]{pic11.png}
\hfill
\caption{\centering{Конечный момент реализации}}
\label{pic11}
\end{multicols}
\end{figure}
\newpage
\hfill
\newpage
\addcontentsline{toc}{section}{Заключение}
\section*{Заключение}
В ходе выполнения лабораторной работы был проведён анализ видеозаписи, отображающей физический процесс вытекания воды из крана и её дальнейшего движения. На основе изучения динамики струи были определены ключевые особенности: постепенное изменение формы потока, появление колебаний, формирование капель и влияние случайных искажений на контур.
Для воспроизведения наблюдаемого эффекта была реализована программная визуализация на языке Python. Визуализация основана на интерполяции масок, описывающих форму струи на различных этапах, а также на применении дополнительных эффектов, таких как волновое искажение, градиентная заливка и генерация падающих капель.
В технической части использованы следующие приёмы:
\begin{enumerate}
\item Применение альфа-канала для создания эффекта прозрачности воды;
\item Использование масок для задания формы струи и плавной смены фаз;
\item Добавление случайных искажений, формирующих реалистичные колебания потока;
\item Генерация отдельных капель, усиливающих правдоподобность анимации;
\item Экспорт последовательности кадров в видеофайл с помощью библиотеки \texttt{imageio}.
\end{enumerate}
Разработанная визуализация позволяет достоверно отобразить процесс формирования и движения струи воды, включая её деформацию и каплеобразование. Программная реализация на базе библиотек \texttt{Pygame}, \texttt{NumPy}, \texttt{imageio}, \texttt{math} и \texttt{random} обеспечила гибкость настройки и высокую наглядность результата.
Созданная программа может быть использована как демонстрационный инструмент при изучении явлений гидродинамики, а также как основа для дальнейших экспериментов по визуализации жидкостей в компьютерной графике. Полный исходный код представлен в приложении~A.
\newpage
\newpage
\newpage
\lstset{
backgroundcolor=\color{white},
frame=single
}
\newpage
\addcontentsline{toc}{section}{Приложение А. Код реализации программы}
\addcontentsline{toc}{subsection}{А.1 waterflow\_visualization.py}
\section*{Приложение А. Код реализации программы}
\subsection*{А.1 waterflow\_visualization.py}
\begin{lstlisting}[language=Python, caption={Визуализация течения воды из крана}]
import pygame
import math
import random
import imageio
import numpy as np
pygame.init()
# --- Класс для капель воды ---
class WaterDrop:
def __init__(self, x, y):
self.x = x
self.y = y
self.size = 18
self.speed = 35
# Прозрачный бело-голубой цвет (альфа 120)
self.color = (60, 55, 55, 30)
self.ellipse_width = self.size
self.ellipse_height = self.size * 1.5
def update(self):
self.y += self.speed
def draw(self, screen):
drop_rect = pygame.Rect(
self.x - self.ellipse_width / 2,
self.y - self.ellipse_height / 2,
self.ellipse_width,
self.ellipse_height,
)
# Временная поверхность с альфой
drop_surface = pygame.Surface(
(self.ellipse_width, self.ellipse_height), pygame.SRCALPHA
)
# Рисуем каплю на этой поверхности
pygame.draw.ellipse(drop_surface, self.color, (0, 0, self.ellipse_width, self.ellipse_height))
# Накладываем на экран
screen.blit(drop_surface, drop_rect.topleft)
def is_offscreen(self, screen_height):
return self.y > screen_height
# --- Настройка экрана и загрузка ресурсов ---
try:
temp_background_image = pygame.image.load("waterflow_background.png")
width, height = temp_background_image.get_size()
use_background = True
except pygame.error as e:
print(f"Error loading background image: {e}")
width, height = 400, 600
use_background = False
screen = pygame.display.set_mode((width, height))
if use_background:
background_image = temp_background_image.convert()
clock = pygame.time.Clock()
masks = []
try:
mask1_image = pygame.image.load("mask_1.png").convert_alpha()
mask2_image = pygame.image.load("mask_2.png").convert_alpha()
mask3_image = pygame.image.load("mask_3.png").convert_alpha()
mask4_image = pygame.image.load("mask_4.png").convert_alpha()
masks = [mask1_image, mask2_image, mask3_image, mask4_image]
except pygame.error as e:
print(f"Error loading mask images: {e}")
pygame.quit()
exit()
# --- Вырезаем базовую подложку из отдельной картинки ---
if use_background:
base_mask = pygame.image.load("moving_image_4.png").convert_alpha()
stream_base = pygame.Surface((width, height), pygame.SRCALPHA)
stream_base.blit(background_image, (0, 0))
stream_base.blit(base_mask, (0, 0), special_flags=pygame.BLEND_RGBA_MULT)
# --- ФУНКЦИИ ---
def distort_only_stream(base, mask, t):
"""Размывает и искажает подложку по маске"""
w, h = base.get_size()
distorted = pygame.Surface((w, h), pygame.SRCALPHA)
for y in range(0, h, 2):
offset = int(5 * math.sin(0.05 * y + t * 0.1)) # сдвиг строки
distorted.blit(base, (offset, y), (0, y, w, 2))
# применяем маску струи
distorted.blit(mask, (0, 0), special_flags=pygame.BLEND_RGBA_MULT)
return distorted
def get_stream_contours(mask_surface):
left_contour = []
right_contour = []
rows_data = {}
for y in range(mask_surface.get_height()):
left_x = -1
right_x = -1
for x in range(mask_surface.get_width()):
if mask_surface.get_at((x, y))[0] < 50:
if left_x == -1:
left_x = x
right_x = x
if left_x != -1:
rows_data[y] = (left_x, right_x)
for y in sorted(rows_data.keys()):
left_x, right_x = rows_data[y]
left_contour.append((left_x, y))
right_contour.append((right_x, y))
return left_contour, right_contour
def make_stream_mask(left, right, width, height):
mask_surface = pygame.Surface((width, height), pygame.SRCALPHA)
polygon_points = left + right[::-1]
pygame.draw.polygon(mask_surface, (255, 255, 255, 255), polygon_points)
return mask_surface
def interpolate_countours(
start_left_contour_, start_right_contour_, end_left_contour_, end_right_contour_
):
interpolated_left = []
interpolated_right = []
min_len_left = min(len(start_left_contour_), len(end_left_contour_))
min_len_right = min(len(start_right_contour_), len(end_right_contour_))
for i in range(min_len_left):
start_x, start_y = start_left_contour_[i]
end_x, end_y = end_left_contour_[i]
interp_x = start_x + (end_x - start_x) * animation_progress
wave1 = amplitude * math.sin(frequency * start_y + t)
wave2 = (amplitude / 2) * math.sin(2 * frequency * start_y + 1.5 * t)
noise = random.uniform(-0.5, 0.5)
x_offset = wave1 + wave2 + noise
interpolated_left.append((interp_x + x_offset, start_y))
for i in range(min_len_right):
start_x, start_y = start_right_contour_[i]
end_x, end_y = end_right_contour_[i]
interp_x = start_x + (end_x - start_x) * animation_progress
wave1 = amplitude * math.sin(frequency * start_y + t)
wave2 = (amplitude / 2) * math.sin(2 * frequency * start_y + 1.5 * t)
noise = random.uniform(-0.5, 0.5)
x_offset = wave1 + wave2 + noise
interpolated_right.append((interp_x + x_offset, start_y))
return interpolated_left, interpolated_right
# --- Контуры масок ---
contours = []
for mask in masks:
left, right = get_stream_contours(mask)
contours.append([left, right])
# --- Параметры ---
start_color = (55, 50, 45, 100)
end_color = (180, 180, 180, 50)
animation_progress = 0
animation_speed = 0.005
amplitude = 2
frequency = 0.05
t = 0
reverse = False
phase = 1
drops = []
FPS = 60
drop_frequency = 1
drop_counter = 0
writer = imageio.get_writer("animation_with_blur.mp4", fps=FPS)
# --- Главный цикл ---
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
# --- Отрисовка фона ---
if use_background:
screen.blit(background_image, (0, 0))
else:
screen.fill((255, 255, 255))
# Интерполяция контура струи
interpolated_left, interpolated_right = interpolate_countours(
contours[0][1], contours[0][0], contours[phase][1], contours[phase][0]
)
stream_mask = make_stream_mask(interpolated_left, interpolated_right, width, height)
# --- Размытая и искажённая подложка ---
distorted_stream = distort_only_stream(stream_base, stream_mask, t)
screen.blit(distorted_stream, (0, 0))
# --- Цветная заливка для струи ---
polygon_points = interpolated_left + interpolated_right[::-1]
if interpolated_left and interpolated_right:
stream_surface = pygame.Surface((width, height), pygame.SRCALPHA)
num_points = len(interpolated_left)
for i in range(num_points - 1):
r = int(start_color[0] + (end_color[0] - start_color[0]) * (i / num_points) ** 0.6)
g = int(start_color[1] + (end_color[1] - start_color[1]) * (i / num_points) ** 0.6)
b = int(start_color[2] + (end_color[2] - start_color[2]) * (i / num_points) ** 0.6)
a = int(start_color[3] + (end_color[3] - start_color[3]) * (i / num_points) ** 0.2)
points = [
interpolated_left[i],
interpolated_left[i + 1],
interpolated_right[i + 1],
interpolated_right[i],
]
pygame.draw.polygon(stream_surface, (r, g, b, a), points)
screen.blit(stream_surface, (0, 0))
coef = 3 if phase == 0 or phase == 1 else 1.5
# --- Анимация прогресса ---
animation_progress += animation_speed if not reverse else animation_speed * coef
if animation_progress >= 1.0 or animation_progress <= 0.0:
animation_speed *= -1
if animation_progress <= 0.0:
phase = min(3, phase + 1)
drop_counter +=1
reverse = not reverse
animation_progress = max(0.0, min(1.0, animation_progress))
t += 9
if drop_counter >= drop_frequency:
last_point_y = min(p[1] for p in polygon_points) + 25
bottom_points_x = [p[0] for p in polygon_points if p[1] == last_point_y]
if bottom_points_x:
spawn_x = sum(bottom_points_x) / len(bottom_points_x)
drops.append(WaterDrop(spawn_x + random.randint(-5, 5), last_point_y))
drop_counter = 0
new_drops_list = []
for drop in drops:
drop.update()
drop.draw(screen)
if not drop.is_offscreen(height):
new_drops_list.append(drop)
drops = new_drops_list
pygame.display.flip()
# --- Запись кадра ---
frame = pygame.surfarray.array3d(screen)
frame = np.swapaxes(frame, 0, 1)
writer.append_data(frame)
clock.tick(FPS)
writer.close()
pygame.quit()
\end{lstlisting}
\end{document}

1
lab4/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
!report

6
lab4/report/.gitignore vendored Normal file
View File

@@ -0,0 +1,6 @@
*
!.gitignore
!*.tex
!*.png
!*.jpg

BIN
lab4/report/pic1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

BIN
lab4/report/pic10.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

BIN
lab4/report/pic11.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

BIN
lab4/report/pic12.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

BIN
lab4/report/pic13.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

BIN
lab4/report/pic14.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
lab4/report/pic15.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
lab4/report/pic16.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
lab4/report/pic17.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
lab4/report/pic18.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
lab4/report/pic19.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
lab4/report/pic2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 975 KiB

BIN
lab4/report/pic20.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
lab4/report/pic21.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
lab4/report/pic22.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

BIN
lab4/report/pic23.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

BIN
lab4/report/pic24.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
lab4/report/pic25.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

BIN
lab4/report/pic26.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

BIN
lab4/report/pic27.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

BIN
lab4/report/pic28.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

BIN
lab4/report/pic29.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

BIN
lab4/report/pic3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 139 KiB

BIN
lab4/report/pic30.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

BIN
lab4/report/pic31.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 KiB

BIN
lab4/report/pic32.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

BIN
lab4/report/pic4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
lab4/report/pic5.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 853 KiB

BIN
lab4/report/pic6.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

BIN
lab4/report/pic7.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

BIN
lab4/report/pic8.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 840 KiB

BIN
lab4/report/pic9.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Some files were not shown because too many files have changed in this diff Show More