Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2792d2657d | |||
| 36b296254b | |||
| 6f3b5c3cc5 | |||
| d85c3a36a6 | |||
| cd907cbf75 | |||
| 960b54b168 |
3
.gitignore
vendored
@@ -1,3 +1,6 @@
|
||||
*
|
||||
!.gitignore
|
||||
!lab1
|
||||
!lab2
|
||||
!lab3
|
||||
!lab4
|
||||
168
lab1/report.tex
@@ -430,7 +430,7 @@
|
||||
|
||||
\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!]
|
||||
\centering
|
||||
@@ -440,7 +440,7 @@
|
||||
\end{figure}
|
||||
|
||||
\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!]
|
||||
\centering
|
||||
@@ -449,7 +449,7 @@
|
||||
\label{fig:chip/modeling/2-add-cylinder}
|
||||
\end{figure}
|
||||
|
||||
Нажимаем Alt + Z, чтобы перейти в режим прозрачности и видеть изображение фишки сквозь цилиндр.
|
||||
Активируем режим прозрачности для точного совмещения объектов. Нажимаем сочетание клавиш Alt + Z (или выбираем "X-Ray" в правом нижнем меню Viewport Shading), чтобы видеть изображение сквозь цилиндр.
|
||||
|
||||
\begin{figure}[h!]
|
||||
\centering
|
||||
@@ -458,7 +458,7 @@
|
||||
\label{fig:chip/modeling/3-alt-z}
|
||||
\end{figure}
|
||||
|
||||
Выбираем изображение, а затем с помощью масштабирования (клавиша S) и смещения (клавиша G) выравниваем центр цилиндра с центром фишки на изображении. Перемещаем курсор с зажатой клавишей Shift для более точного позиционирования. Результат на Рис.~\ref{fig:chip/modeling/4-positioning}.
|
||||
Подгоним размеры и позицию изображения под геометрию цилиндра. Выбираем изображение, затем используем масштабирование (клавиша S) и перемещение (клавиша G), совмещая центр цилиндра с центром фишки на референсе. Для точной настройки перемещаем курсор с зажатой клавишей Shift. Результат на Рис.~\ref{fig:chip/modeling/4-positioning}.
|
||||
|
||||
\begin{figure}[h!]
|
||||
\centering
|
||||
@@ -468,7 +468,7 @@
|
||||
\end{figure}
|
||||
|
||||
\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!]
|
||||
\centering
|
||||
@@ -478,7 +478,7 @@
|
||||
\end{figure}
|
||||
|
||||
\newpage
|
||||
Возвращаемся на вид сверху (клавиша 7 на Num Pad). Нажимаем клавишу I, чтобы добавить внтреннюю грань. Выравниваем её по внешней стороне ложбинки на фишке, ориентируясь на изображения. При этом перемещаем курсор с зажатой клавишей Shift для более точного позиционирования.
|
||||
Создадим контур внешнего края ложбинки. Возвращаемся на вид сверху (клавиша 7 на Num Pad). Нажимаем клавишу I (или выбираем Inset Faces в меню Mesh > Faces), чтобы добавить внутреннюю грань. Выравниваем её по внешнему краю ложбинки, используя референс для точности позиционирования.
|
||||
|
||||
\begin{figure}[h!]
|
||||
\centering
|
||||
@@ -487,7 +487,7 @@
|
||||
\label{fig:chip/modeling/6-insert-faces}
|
||||
\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!]
|
||||
\centering
|
||||
@@ -496,36 +496,37 @@
|
||||
\label{fig:img/chip/modeling/7-insert-inner-faces}
|
||||
\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!]
|
||||
\centering
|
||||
\includegraphics[width=0.9\linewidth]{img/chip/modeling/8-sizing.png}
|
||||
\includegraphics[width=0.8\linewidth]{img/chip/modeling/8-sizing.png}
|
||||
\caption{Указание размеров фишки.}
|
||||
\label{fig:chip/modeling/8-sizing}
|
||||
\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!]
|
||||
\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 к модели.}
|
||||
\label{fig:chip/modeling/9-scale}
|
||||
\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!]
|
||||
\centering
|
||||
\includegraphics[width=0.9\linewidth]{img/chip/modeling/10-trench.png}
|
||||
\caption{Добавление ложбинки.}
|
||||
\caption{Формирование углублений ложбинки.}
|
||||
\label{fig:chip/modeling/10-trench}
|
||||
\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!]
|
||||
\centering
|
||||
@@ -534,7 +535,7 @@
|
||||
\label{fig:chip/modeling/11-shade-smooth}
|
||||
\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!]
|
||||
\centering
|
||||
@@ -543,7 +544,7 @@
|
||||
\label{fig:chip/modeling/12-new-edges}
|
||||
\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!]
|
||||
\centering
|
||||
@@ -552,27 +553,28 @@
|
||||
\label{fig:chip/modeling/13-plane}
|
||||
\end{figure}
|
||||
|
||||
\newpage
|
||||
\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!]
|
||||
\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.}
|
||||
\label{fig:chip/texturing/1-start}
|
||||
\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!]
|
||||
\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 для корректного отображения текстур.}
|
||||
\label{fig:chip/texturing/2-settings}
|
||||
\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!]
|
||||
\centering
|
||||
@@ -581,7 +583,7 @@
|
||||
\label{fig:chip/texturing/3-image-texture}
|
||||
\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!]
|
||||
\centering
|
||||
@@ -590,7 +592,7 @@
|
||||
\label{fig:chip/texturing/4-assigning}
|
||||
\end{figure}
|
||||
|
||||
На панели слева распологаем проекцию поверхностей на текстуре таким образом, чтобы форма поверхности совпадала с изображением. Аналогичным образом накладываем материал с текстурой обратной стороны фишки (Рис.~\ref{fig:chip/texturing/5-uv-editing}).
|
||||
Отредактируем UV-координаты для точного совпадения с изображением. На панели слева распологаем проекцию поверхностей на текстуре таким образом, чтобы форма поверхности совпадала с изображением. Аналогичным образом накладываем материал с текстурой обратной стороны фишки (Рис.~\ref{fig:chip/texturing/5-uv-editing}).
|
||||
|
||||
\begin{figure}[h!]
|
||||
\centering
|
||||
@@ -599,7 +601,7 @@
|
||||
\label{fig:chip/texturing/5-uv-editing}
|
||||
\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!]
|
||||
\centering
|
||||
@@ -611,9 +613,9 @@
|
||||
\newpage
|
||||
\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!]
|
||||
\centering
|
||||
@@ -622,7 +624,7 @@
|
||||
\label{fig:chip/lighting/1_start}
|
||||
\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!]
|
||||
\centering
|
||||
@@ -632,7 +634,7 @@
|
||||
\end{figure}
|
||||
|
||||
\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!]
|
||||
\centering
|
||||
@@ -725,7 +727,7 @@
|
||||
|
||||
\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!]
|
||||
\centering
|
||||
@@ -734,7 +736,7 @@
|
||||
\label{fig:clamp/modeling/1-add-reference}
|
||||
\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!]
|
||||
\centering
|
||||
@@ -743,7 +745,7 @@
|
||||
\label{fig:clamp/modeling/2-add-plane}
|
||||
\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!]
|
||||
\centering
|
||||
@@ -753,28 +755,27 @@
|
||||
\end{figure}
|
||||
|
||||
\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!]
|
||||
\centering
|
||||
\includegraphics[width=1\linewidth]{img/clamp/modeling/4-sizes.png}
|
||||
\includegraphics[width=0.8\linewidth]{img/clamp/modeling/4-sizes.png}
|
||||
\caption{Задание реальных размеров.}
|
||||
\label{fig:clamp/modeling/4-sizes}
|
||||
\end{figure}
|
||||
|
||||
\newpage
|
||||
Переключаемся на вид сбоку (клавиша 1 на Num Pad), затем копируем окантовку (сочетание клавиш Shift + D) и поднимаем немного выше. Затем нажимаем по новому объекту правой кнопкой мыши и в разделе Convert To выбираем пункт Curve.
|
||||
Перейдём к созданию объёмных ободков. Переключаемся на вид сбоку (клавиша 1 на Num Pad или меню View), копируем контур сочетанием клавиш Shift + D (через меню Object > Duplicate). Поднимаем копию выше исходного контура, затем конвертируем её в кривую через правый клик > 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!]
|
||||
\centering
|
||||
\includegraphics[width=1\linewidth]{img/clamp/modeling/5-circle.png}
|
||||
\includegraphics[width=0.8\linewidth]{img/clamp/modeling/5-circle.png}
|
||||
\caption{Конвертация круга из меша в кривую.}
|
||||
\label{fig:clamp/modeling/5-circle}
|
||||
\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!]
|
||||
\centering
|
||||
@@ -783,52 +784,53 @@
|
||||
\label{fig:clamp/modeling/6-bevel}
|
||||
\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!]
|
||||
\centering
|
||||
\includegraphics[width=0.85\linewidth]{img/clamp/modeling/7-sides.png}
|
||||
\includegraphics[width=0.75\linewidth]{img/clamp/modeling/7-sides.png}
|
||||
\caption{Создание боковых сторон зажима.}
|
||||
\label{fig:clamp/modeling/7-sides}
|
||||
\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!]
|
||||
\centering
|
||||
\includegraphics[width=0.9\linewidth]{img/clamp/modeling/8-modifiers.png}
|
||||
\includegraphics[width=0.85\linewidth]{img/clamp/modeling/8-modifiers.png}
|
||||
\caption{Придание толщины зажиму.}
|
||||
\label{fig:clamp/modeling/8-modifiers}
|
||||
\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!]
|
||||
\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{Добавление новых граней.}
|
||||
\label{fig:clamp/modeling/9-new-edges}
|
||||
\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!]
|
||||
\centering
|
||||
\includegraphics[width=1\linewidth]{img/clamp/modeling/10-bottom.png}
|
||||
\includegraphics[width=0.8\linewidth]{img/clamp/modeling/10-bottom.png}
|
||||
\caption{Установка и сглаживание нижнего ободка.}
|
||||
\label{fig:clamp/modeling/10-bottom}
|
||||
\end{figure}
|
||||
|
||||
Переходим в режим редактирования (клавиша Tab). Выделяем крайние точки на ободке и чуть-чуть сдвигаем (клавиша G) с зажатой клавишей Shift, чтобы грани ободка и основной части зажима не накладывались друг на друга (Рис.~\ref{fig:clamp/modeling/11-faces}).
|
||||
Устраним артефакты на месте пересечения граней. Переходим в режим редактирования (клавиша Tab). Выделяем крайние точки на ободке и чуть-чуть сдвигаем (клавиша G) с зажатой клавишей Shift, чтобы грани ободка и основной части зажима не накладывались друг на друга (Рис.~\ref{fig:clamp/modeling/11-faces}).
|
||||
|
||||
\begin{figure}[h!]
|
||||
\centering
|
||||
\includegraphics[width=1\linewidth]{img/clamp/modeling/11-faces.png}
|
||||
\includegraphics[width=0.8\linewidth]{img/clamp/modeling/11-faces.png}
|
||||
\caption{Устранение артефактов на стыке граней.}
|
||||
\label{fig:clamp/modeling/11-faces}
|
||||
\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!]
|
||||
\centering
|
||||
@@ -837,7 +839,7 @@
|
||||
\label{fig:clamp/modeling/12-copy}
|
||||
\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!]
|
||||
\centering
|
||||
@@ -849,38 +851,38 @@
|
||||
\newpage
|
||||
\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!]
|
||||
\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.}
|
||||
\label{fig:clamp/texturing/1-start}
|
||||
\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!]
|
||||
\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 для корректного отображения текстур.}
|
||||
\label{fig:clamp/texturing/2-settings}
|
||||
\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!]
|
||||
\centering
|
||||
\includegraphics[width=0.8\linewidth]{img/clamp/texturing/3-color.png}
|
||||
\includegraphics[width=0.75\linewidth]{img/clamp/texturing/3-color.png}
|
||||
\caption{Покраска ободков.}
|
||||
\label{fig:clamp/texturing/3-color}
|
||||
\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!]
|
||||
\centering
|
||||
\includegraphics[width=0.9\linewidth]{img/clamp/texturing/4-nodes.png}
|
||||
\includegraphics[width=0.85\linewidth]{img/clamp/texturing/4-nodes.png}
|
||||
\caption{Графовое представление материала основной части зажима.}
|
||||
\label{fig:clamp/texturing/4-nodes}
|
||||
\end{figure}
|
||||
@@ -901,7 +903,7 @@
|
||||
\label{fig:clamp/texturing/5-uv}
|
||||
\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!]
|
||||
\centering
|
||||
@@ -914,9 +916,9 @@
|
||||
\newpage
|
||||
\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!]
|
||||
\centering
|
||||
@@ -925,7 +927,7 @@
|
||||
\label{fig:clamp/lighting/1-start}
|
||||
\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!]
|
||||
\centering
|
||||
@@ -935,7 +937,7 @@
|
||||
\end{figure}
|
||||
|
||||
\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!]
|
||||
\centering
|
||||
@@ -1039,7 +1041,7 @@
|
||||
Толщина - 2 мм
|
||||
|
||||
\subsubsection{Моделирование}
|
||||
Начинаем с добавления куба. Нажимаем сочетание клавиш Shift + A и в разделе Mesh выбираем Cube. Затем в боковом меню (клавиша N) задаём ему реальные размеры линейки. В разделе Dimensions в поле X указываем 126mm, в поле Y -- 27mm, в поле Z -- 2mm. Нажимаем на точку на Num Pad, чтобы приблизиться к модели (Рис.~\ref{fig:ruler/modeling/1-add-cube}).
|
||||
Создадим основу будущей линейки, используя примитив куб. Нажимаем сочетание клавиш 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
|
||||
@@ -1048,7 +1050,7 @@
|
||||
\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}).
|
||||
Добавим сглаживание для придания модели естественных форм. В разделе Modifier Properties нажимаем на кнопку Add Modifier и добавляем модификатор Subdivision Surface из раздела Generate. В поле Levels Viewport и Render указываем значение 3 (Рис.~\ref{fig:ruler/modeling/2-subdivision}).
|
||||
|
||||
\begin{figure}[h!]
|
||||
\centering
|
||||
@@ -1057,26 +1059,25 @@
|
||||
\label{fig:ruler/modeling/2-subdivision}
|
||||
\end{figure}
|
||||
|
||||
Модель получается слишком сглаженной. Нужно добавить полигонов, чтобы уточнить её. Переключаемся на вид сверху (клавиша 7 на Num Pad). Переходим в режим редактирования (клавиша Tab). Нажимаем сочетание клавиш Ctrl + R и добавляем новые грани по краям линейки (Рис.~\ref{fig:ruler/modeling/3-edges}).
|
||||
|
||||
Уточним геометрию модели путём добавления рёбер. Переключаемся на вид сверху (клавиша 7 на Num Pad или через меню View → Top). Переходим в режим редактирования (клавиша Tab). Нажимаем сочетание клавиш Ctrl + R (инструмент Loop Cut) и добавляем новые рёбра по краям линейки (Рис.~\ref{fig:ruler/modeling/3-edges}).
|
||||
|
||||
\begin{figure}[h!]
|
||||
\centering
|
||||
\includegraphics[width=1\linewidth]{img/ruler/modeling/3-edges.png}
|
||||
\caption{Добавление новых граней.}
|
||||
\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). Выделяем две крайние верхние вершины с левой стороны линейки и сдвигаем вправо по горизонтали (сочетание клавиш G + Y), чтобы сделать скос (Рис.~\ref{fig:ruler/modeling/4-skew}).
|
||||
Сформируем скос на торце линейки. Переключаемся на вид сбоку (клавиша 3 на Num Pad) и переходим в режим прозрачности (сочетание клавиш Alt + Z, либо через иконку X-Ray в правом верхнем углу). Выделяем две крайние верхние вершины с левой стороны линейки и сдвигаем вправо по горизонтали (сочетание клавиш G + Y) (Рис.~\ref{fig:ruler/modeling/4-skew}).
|
||||
|
||||
\begin{figure}[h!]
|
||||
\centering
|
||||
\includegraphics[width=1\linewidth]{img/ruler/modeling/4-skew.png}
|
||||
\includegraphics[width=0.9\linewidth]{img/ruler/modeling/4-skew.png}
|
||||
\caption{Создание скоса.}
|
||||
\label{fig:ruler/modeling/4-skew}
|
||||
\end{figure}
|
||||
|
||||
Режим прозрачности можно отключить (сочетание клавиш Alt + Z). Возвращаемся в объектный режим (клавиша Tab). Нажимаем по модели линейки правой кнопкой мыши на и выбираем пункт Shade Smooth. Нажимаем сочетание клавиш Shift + A и в разделе Empty выбираем Arrows. В разделе Object Properties в подразделе Rotation в поле X указываем значение -90, в поле Z 90 (Рис.~\ref{fig:ruler/modeling/5-arrows}).
|
||||
Режим прозрачности можно отключить (сочетание клавиш 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
|
||||
@@ -1085,7 +1086,7 @@
|
||||
\label{fig:ruler/modeling/5-arrows}
|
||||
\end{figure}
|
||||
|
||||
Выбираем линейку и в разделе Modifier Properties добавляем модификатор Simple Deform из раздела Deform. В настройках модификатора выбираем вариант Bend, в поле Angle указываем значени 10, в поле Object выбираем только что добавленный объект Arrows (Рис.~\ref{fig:ruler/modeling/6-bend}).
|
||||
Смоделируем изгиб линейки. Выбираем линейку и в разделе Modifier Properties добавляем модификатор Simple Deform из раздела Deform. В настройках модификатора выбираем вариант Bend, в поле Angle указываем значени 10, в поле Object выбираем только что добавленный объект Arrows (Рис.~\ref{fig:ruler/modeling/6-bend}).
|
||||
|
||||
\begin{figure}[h!]
|
||||
\centering
|
||||
@@ -1094,7 +1095,7 @@
|
||||
\label{fig:ruler/modeling/6-bend}
|
||||
\end{figure}
|
||||
|
||||
Линейку и стрелки можно временно скрыть (клавиша H). Нажимаем Shift + A и в разделе Mesh выбираем Plane. В боковом меню (клавиша N) задаём её размеры. В разделе Dimensions в поле X указываем 126mm, в поле Y -- 27mm (Рис.~\ref{fig:ruler/modeling/7-plane}).
|
||||
Линейку и стрелки можно временно скрыть (клавиша 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
|
||||
@@ -1104,7 +1105,7 @@
|
||||
\end{figure}
|
||||
|
||||
\newpage
|
||||
Нажимаем на цифру 7 на Num Pad, чтобы перейти на вид сверху. Затем нажимаем Shift + A и в разделе Image выбираем Reference. В открывшемся окне проводника выбираем изображение линейки и нажимаем Add~Image. Затем масштабируем линейку под размер плоскости. Для этого в боковом меню (клавиша N) в разделе Scale достаточно указать значение 0.025 по всем осям (Рис.~\ref{fig:ruler/modeling/8-reference}).
|
||||
Импортируем референсное изображение для точного моделирования. Нажимаем на цифру 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
|
||||
@@ -1149,7 +1150,7 @@
|
||||
\label{fig:ruler/modeling/12-select}
|
||||
\end{figure}
|
||||
|
||||
Переключаемся на вид сверху (клавиша 7 на Num Pad). И с помощью сочетания клавиш G + X по отдельности выравниваем точки по верхней части излома (Рис.~\ref{fig:13-break-top}).
|
||||
Переключаемся на вид сверху (клавиша 7 на Num Pad или через меню View → Top). И с помощью сочетания клавиш G + X по отдельности выравниваем точки по верхней части излома (Рис.~\ref{fig:ruler/modeling/13-break-top}).
|
||||
|
||||
\begin{figure}[h!]
|
||||
\centering
|
||||
@@ -1177,7 +1178,7 @@
|
||||
\label{fig:ruler/modeling/15-scale-locale}
|
||||
\end{figure}
|
||||
|
||||
Нажимаем Shift + A и в разделе Mesh выбираем Cube. В боковом меню (клавиша N) указываем его размеры и позицию. В разделе Dimensions в поле X указываем 20mm, в поле Y -- 275mm, в поле Z -- 2.05mm. В разделе Locataion в поле X указываем -0.06m (Рис.~\ref{fig:ruler/modeling/16-cube}).
|
||||
Нажимаем 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
|
||||
@@ -1205,6 +1206,7 @@
|
||||
\end{figure}
|
||||
|
||||
|
||||
\newpage
|
||||
\subsubsection{Текстурирование}
|
||||
|
||||
Перед началом текстурирования модификаторы Subdivision Surface и Boolean нужно применить. Для этого выделяем их в разделе Modifier Properties и нажимаем сочетание клавиш Ctrl + A. Затем переходим в режим редактирования (клавиша Tab). Модификатор Simple Deform можно временно отключить, для этого нужно нажать на иконку компьютера в его настройках (Рис.~\ref{fig:ruler/texturing/1-apply}).
|
||||
@@ -1234,7 +1236,7 @@
|
||||
\label{fig:ruler/texturing/3-materials}
|
||||
\end{figure}
|
||||
|
||||
Переходим в режим редактирования (клавиша Tab). И в режиме выбора граней (клавиша 3) выделяем все грани на верхней стороне линейки. Затем в разделе Material Properties выбираем материал с текстурой лицевой стороны линейки и нажимаем Assign. Затем переключаемся на вид сверху (клавиша 7 на Num Pad), нажимаем клавишу U и выбираем пункт Project from View (Bounds), чтобы создать UV развёртку верхней поверхности линейки (Рис.~\ref{fig:ruler/texturing/4-top-uv}).
|
||||
Переходим в режим редактирования (клавиша 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
|
||||
@@ -1271,7 +1273,7 @@
|
||||
\label{fig:ruler/texturing/7-apply}
|
||||
\end{figure}
|
||||
|
||||
Нажимаем Shift + A и в разделе Mesh выбираем Plane, чтобы добавить плоскость, на которой будет расопложена текстура стола. В разделе Material Properties добавляем материал. В поле Base Color указываем Image Texture и указываем путь до текстуры стола. Переходим в режим редактирования (клавиша Tab) и подгоняем размеры текстуры (Рис.~\ref{fig:ruler/texturing/8-table}).
|
||||
Нажимаем Shift + A (либо открываем список Add в верхнем меню) и в разделе Mesh выбираем Plane, чтобы добавить плоскость, на которой будет расопложена текстура стола. В разделе Material Properties добавляем материал. В поле Base Color указываем Image Texture и указываем путь до текстуры стола. Переходим в режим редактирования (клавиша Tab) и подгоняем размеры текстуры (Рис.~\ref{fig:ruler/texturing/8-table}).
|
||||
|
||||
\begin{figure}[h!]
|
||||
\centering
|
||||
@@ -1294,7 +1296,7 @@
|
||||
|
||||
Переходим в раздел 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 interior.exr } (Рис.~\ref{fig:ruler/lighting/1-world}).
|
||||
Затем на панели редактирования материалов нужно переключиться на вкладку 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
|
||||
@@ -1303,7 +1305,7 @@
|
||||
\label{fig:ruler/lighting/1-world}
|
||||
\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:ruler/lighting/2-points}).
|
||||
Нажимаем 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
|
||||
@@ -1313,7 +1315,7 @@
|
||||
\end{figure}
|
||||
|
||||
\newpage
|
||||
Теперь добавим камеру. Для этого нажимаем сочетание клавиш Shift + A и выбираем пункт 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}).
|
||||
Теперь добавим камеру. Для этого нажимаем сочетание клавиш 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
|
||||
|
||||
252
lab2/main.py
Normal 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()
|
||||
BIN
lab2/report/img/comparison.png
Normal file
|
After Width: | Height: | Size: 56 KiB |
BIN
lab2/report/img/figure_1.png
Normal file
|
After Width: | Height: | Size: 112 KiB |
BIN
lab2/report/img/figure_2.png
Normal file
|
After Width: | Height: | Size: 40 KiB |
BIN
lab2/report/img/figure_3.png
Normal file
|
After Width: | Height: | Size: 51 KiB |
BIN
lab2/report/img/figure_4.png
Normal file
|
After Width: | Height: | Size: 139 KiB |
BIN
lab2/report/img/shadow-color.png
Normal file
|
After Width: | Height: | Size: 198 KiB |
BIN
lab2/report/img/shadow-half.jpg
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
lab2/report/img/shadow-types.png
Normal file
|
After Width: | Height: | Size: 93 KiB |
BIN
lab2/report/img/shadow.png
Normal file
|
After Width: | Height: | Size: 164 KiB |
52
lab2/report/plot_comparison.py
Normal 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
@@ -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
@@ -0,0 +1 @@
|
||||
!report
|
||||
6
lab3/report/.gitignore
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
*
|
||||
|
||||
!.gitignore
|
||||
!*.tex
|
||||
!*.png
|
||||
!*.jpg
|
||||
BIN
lab3/report/pic1.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
BIN
lab3/report/pic10.png
Normal file
|
After Width: | Height: | Size: 949 KiB |
BIN
lab3/report/pic11.png
Normal file
|
After Width: | Height: | Size: 1.2 MiB |
BIN
lab3/report/pic2.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
lab3/report/pic3.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
lab3/report/pic4.png
Normal file
|
After Width: | Height: | Size: 36 KiB |
BIN
lab3/report/pic5.png
Normal file
|
After Width: | Height: | Size: 208 KiB |
BIN
lab3/report/pic6.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
BIN
lab3/report/pic7.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
BIN
lab3/report/pic8.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
BIN
lab3/report/pic9.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
833
lab3/report/Лаб3. Тищенко.tex
Normal 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
@@ -0,0 +1 @@
|
||||
!report
|
||||
6
lab4/report/.gitignore
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
*
|
||||
|
||||
!.gitignore
|
||||
!*.tex
|
||||
!*.png
|
||||
!*.jpg
|
||||
BIN
lab4/report/pic1.png
Normal file
|
After Width: | Height: | Size: 50 KiB |
BIN
lab4/report/pic10.png
Normal file
|
After Width: | Height: | Size: 35 KiB |
BIN
lab4/report/pic11.png
Normal file
|
After Width: | Height: | Size: 30 KiB |
BIN
lab4/report/pic12.png
Normal file
|
After Width: | Height: | Size: 35 KiB |
BIN
lab4/report/pic13.png
Normal file
|
After Width: | Height: | Size: 6.9 KiB |
BIN
lab4/report/pic14.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
lab4/report/pic15.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
lab4/report/pic16.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
lab4/report/pic17.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
lab4/report/pic18.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
lab4/report/pic19.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
lab4/report/pic2.png
Normal file
|
After Width: | Height: | Size: 975 KiB |
BIN
lab4/report/pic20.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
lab4/report/pic21.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
lab4/report/pic22.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
lab4/report/pic23.png
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
BIN
lab4/report/pic24.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
lab4/report/pic25.png
Normal file
|
After Width: | Height: | Size: 74 KiB |
BIN
lab4/report/pic26.png
Normal file
|
After Width: | Height: | Size: 36 KiB |
BIN
lab4/report/pic27.png
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
lab4/report/pic28.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
lab4/report/pic29.png
Normal file
|
After Width: | Height: | Size: 57 KiB |
BIN
lab4/report/pic3.png
Normal file
|
After Width: | Height: | Size: 139 KiB |
BIN
lab4/report/pic30.png
Normal file
|
After Width: | Height: | Size: 102 KiB |
BIN
lab4/report/pic31.png
Normal file
|
After Width: | Height: | Size: 111 KiB |
BIN
lab4/report/pic32.png
Normal file
|
After Width: | Height: | Size: 54 KiB |
BIN
lab4/report/pic4.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
lab4/report/pic5.png
Normal file
|
After Width: | Height: | Size: 853 KiB |
BIN
lab4/report/pic6.png
Normal file
|
After Width: | Height: | Size: 34 KiB |
BIN
lab4/report/pic7.png
Normal file
|
After Width: | Height: | Size: 9.8 KiB |
BIN
lab4/report/pic8.png
Normal file
|
After Width: | Height: | Size: 840 KiB |
BIN
lab4/report/pic9.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
864
lab4/report/report.tex
Normal file
@@ -0,0 +1,864 @@
|
||||
|
||||
\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={Отчет},
|
||||
pdfauthor={Your name},
|
||||
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{Отчет о выполнении лабораторной работы №4 по дисциплине}\\[3pt]
|
||||
\normalsize{«Алгоритмические основы компьютерной графики»}\\[16pt]
|
||||
\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
|
||||
\section*{Введение}
|
||||
\addcontentsline{toc}{section}{Введение}
|
||||
|
||||
Графические движки представляют собой специализированное программное обеспечение, предназначенное для обработки и отображения трёхмерных данных в интерактивных приложениях. Они выступают базовой платформой для широкого круга цифровых продуктов — от видеоигр и симуляторов до мультимедийных проектов и систем виртуальной (VR) и дополненной (AR) реальности. Обеспечивая разработчиков обширным набором средств для построения детализированных трёхмерных сцен, создания визуальных эффектов и разработки удобных интерфейсов, графические движки существенно упрощают и ускоряют процесс производства.
|
||||
|
||||
Хотя чаще всего графические движки ассоциируются с игровой индустрией, их возможности применяются во множестве других областей. Среди основных направлений можно выделить:
|
||||
|
||||
\begin{itemize}
|
||||
\item \textbf{Профессиональные симуляторы}: используются при создании учебных комплексов для медицины, промышленности и транспорта, позволяя безопасно воспроизводить потенциально опасные или сложные ситуации.
|
||||
\item \textbf{Архитектурная визуализация и проектирование}: позволяют разрабатывать виртуальные 3D-модели зданий и интерьеров, демонстрировать проекты до их реализации и проводить интерактивные экскурсии.
|
||||
\item \textbf{Образовательные решения}: применяются для создания виртуальных лабораторий, учебных симуляций и иммерсивных образовательных сред, а также для наглядного воспроизведения исторических или научных процессов.
|
||||
\item \textbf{Кинематограф и цифровое искусство}: активно используются при создании анимационных картин, визуальных эффектов и интерактивных медиаформатов.
|
||||
\item \textbf{Научная визуализация}: дают возможность представлять в удобной форме сложные данные, моделировать физические, химические и биологические явления, а также анализировать большие массивы информации.
|
||||
\end{itemize}
|
||||
|
||||
Современные графические движки — это комплексные программные системы, сочетающие в себе технологии рендеринга, симуляции физических процессов, алгоритмы искусственного интеллекта и другие достижения компьютерных наук. Постоянное совершенствование этих решений делает виртуальные среды всё более реалистичными, динамичными и применимыми в различных сферах деятельности.
|
||||
|
||||
\vspace{1cm}
|
||||
\newpage
|
||||
\section{Постановка задачи}
|
||||
|
||||
{\bf Целью} данной работы является освоение принципов работы с графическим движком UNIGINE и закрепление практических навыков по созданию трёхмерных сцен.
|
||||
|
||||
{\bf Задачи:}
|
||||
\begin{itemize}
|
||||
\item Изучить функциональные возможности 3D-движка UNIGINE и его инструментарий для работы с объектами и сценами;
|
||||
\item Выполнить импорт моделей, подготовленных в рамках лабораторной работы №1;
|
||||
\item Построить полноценную сцену с использованием загруженных объектов.
|
||||
\end{itemize}
|
||||
\newpage
|
||||
\section{Описание сценариев физического моделирования}
|
||||
|
||||
\subsection{Сценарий 1: Падение и взаимодействие твёрдых тел}
|
||||
|
||||
В первом сценарии рассматриваются основные законы динамики при свободном падении и последующем взаимодействии нескольких объектов, различающихся массой, формой и физическими параметрами.
|
||||
|
||||
\begin{itemize}
|
||||
\item \textbf{Участвующие объекты}:
|
||||
\begin{itemize}
|
||||
\item Сломанная линейка
|
||||
\item Игральная фишка
|
||||
\item Пластиковый зажим для хлеба
|
||||
\end{itemize}
|
||||
Каждый из объектов представлен в количестве 2-ух штук.
|
||||
\item \textbf{Масса объектов}:
|
||||
\begin{itemize}
|
||||
\item Линейка: 0,02 кг
|
||||
\item Игральная фишка: 0,05 кг
|
||||
\item Зажим для хлеба: 0,01 кг
|
||||
\end{itemize}
|
||||
|
||||
\item \textbf{Начальные условия}:
|
||||
\begin{itemize}
|
||||
\item Исходное положение над поверхностью:
|
||||
\begin{itemize}
|
||||
\item Линейка №1: 1,55 м
|
||||
\item Линейка №2: 1,52 м
|
||||
\item Фишка №1: 1,50 м
|
||||
\item Фишка №2: 1,49 м
|
||||
\item Зажим №1: 1,51 м
|
||||
\item Зажим №2: 1,41 м
|
||||
\end{itemize}
|
||||
\item Начальная ориентация:
|
||||
\begin{itemize}
|
||||
\item Линейка: наклонена под углом 45° к поверхности, расположена плоской стороной к наблюдателю, нижний конец направлен вниз. \item Вторая линейка повернута под углом 40° к поверхности, отдалена на 5 см левее от первой линейки.
|
||||
\item Фишка: повернута на 150° относительно вертикали, расположена ребром вправо.
|
||||
\item Вторая фишка расположена зеркально первой, на расстоянии 7 см слева от нее.
|
||||
\item Зажим: расположен под углом –45° относительно нормали к поверхности, с лёгким поворотом по часовой стрелке.
|
||||
\item Второй зажим находится на 10 см ниже первого. Расположение зеркальное.
|
||||
\end{itemize}
|
||||
\end{itemize}
|
||||
|
||||
\item \textbf{Физические параметры среды и объектов}:
|
||||
\begin{itemize}
|
||||
\item Ускорение свободного падения: стандартное значение $g = 9,81\,\text{м/с}^2$.
|
||||
\item Коэффициенты трения:
|
||||
\begin{itemize}
|
||||
\item Линейка: 0,5
|
||||
\item Фишка: 0,7
|
||||
\item Зажим: 0,4
|
||||
\end{itemize}
|
||||
\item Коэффициенты упругости при столкновениях:
|
||||
\begin{itemize}
|
||||
\item Линейка: 0,7
|
||||
\item Фишка: 0,5
|
||||
\item Зажим: 0,3
|
||||
\end{itemize}
|
||||
\end{itemize}
|
||||
|
||||
\item \textbf{Наблюдаемая динамика движения}:
|
||||
\begin{itemize}
|
||||
\item Линейка: падает под углом, при касании поверхности сначала ударяется концом, затем заваливается и совершает несколько переворотов, пока не остановится.
|
||||
\item Фишка: падает устойчиво, слегка подпрыгивает после удара и катится по поверхности, постепенно замедляясь.
|
||||
\item Зажим: нестабильно вращается в воздухе, при падении меняет ориентацию и быстро приходит в состояние покоя.
|
||||
\end{itemize}
|
||||
\end{itemize}
|
||||
|
||||
\subsection{Сценарий 2: Поведение объектов в водной среде}
|
||||
|
||||
Вторая часть эксперимента посвящена моделированию гидродинамических процессов при погружении объектов в жидкость с учётом выталкивающей силы и сопротивления среды.
|
||||
|
||||
\begin{itemize}
|
||||
\item \textbf{Характеристики водной среды}:
|
||||
\begin{itemize}
|
||||
\item Объём жидкости: ограниченный резервуар с поверхностью воды на высоте 1 м и твёрдым дном.
|
||||
\item Визуальные эффекты: реалистичное преломление света, подводные тени и небольшие возмущения поверхности.
|
||||
\item Плотность воды: $1000 \,\text{кг}/\text{м}^3$.
|
||||
\end{itemize}
|
||||
|
||||
\item \textbf{Начальные условия}:
|
||||
\begin{itemize}
|
||||
\item Все объекты из сценария 1 располагаются над поверхностью воды в тех же позициях и с теми же углами ориентации.
|
||||
\end{itemize}
|
||||
|
||||
\item \textbf{Поведение объектов в воде}:
|
||||
\begin{itemize}
|
||||
\item Линейка: входит в воду узким концом, тонет, затем постепенно погружается, переворачиваясь и слегка колеблясь.
|
||||
\item Фишка: входит в воду почти вертикально, медленно тонет, слегка вращаясь. После полного погружения оседает в горизонтальном положении на дне.
|
||||
\item Зажим: медленно погружается на дно, не испытывая переворотов.
|
||||
\end{itemize}
|
||||
|
||||
\item \textbf{Физические эффекты, учитываемые в симуляции}:
|
||||
\begin{itemize}
|
||||
\item Выталкивающая сила: действие архимедовой силы, определяющей плавучесть объектов.
|
||||
\item Сопротивление жидкости: замедление движения объектов при погружении.
|
||||
\item Дополнительные визуальные эффекты: генерация турбулентности и волнений при взаимодействии объектов с водой.
|
||||
\end{itemize}
|
||||
\end{itemize}
|
||||
|
||||
|
||||
\newpage
|
||||
\section{Обзор среды разработки Unigine}
|
||||
|
||||
Unigine — это мощный инструментарий для создания интерактивных 3D-проектов, широко применяемый в сфере разработки видеоигр, систем виртуальной реальности, специализированных визуализаций и разнообразных 3D-тренажеров, охватывающих такие области, как образование, медицина, военная подготовка и транспорт.
|
||||
|
||||
Данная среда разработки функционирует на операционных системах Microsoft Windows и GNU/Linux, что обеспечивает гибкость для пользователей. Поддержка графических интерфейсов программирования (API), таких как DirectX и OpenGL, гарантирует совместимость с современными стандартами рендеринга. Unigine также обладает собственным объектно-ориентированным скриптовым языком — UnigineScript, синтаксически схожим с C++, что облегчает процесс создания и адаптации игровой или прикладной логики.
|
||||
|
||||
Платформа Unigine предоставляет обширные возможности для интеграции передовых визуальных эффектов, включая окклюзию окружающего пространства (Screen Space Ambient Occlusion - SSAO) и расчет глобального освещения в реальном времени, способствуя достижению высокой степени фотореалистичности. Встроенный модуль физической симуляции позволяет моделировать столкновения, динамику твердых тел, процедурное разрушение объектов, поведение текстильных материалов, плавучесть, а также управлять силовыми полями и даже осуществлять реверс времени.
|
||||
|
||||
Unigine также предлагает средства для формирования обширных ландшафтов и комплексных систем растительности, что особенно ценно при разработке симуляторов и виртуальных миров с открытой структурой.
|
||||
|
||||
Ключевым преимуществом является интуитивно понятный редактор виртуального пространства, который значительно упрощает процесс конструирования и модификации сцен. Этот визуальный инструмент позволяет оперативно настраивать параметры окружения, ускоряя итерации в разработке и создании прототипов.
|
||||
|
||||
\newpage
|
||||
\section{Архитектура проекта в UNIGINE}
|
||||
|
||||
Создание приложений в UNIGINE осуществляется в рамках проекта, который объединяет исходный код, графические и звуковые ресурсы, а также метаданные разрабатываемого продукта. Каждый проект может содержать одну или несколько детализированных 3D-сцен, именуемых мирами. Управление этими проектами осуществляется посредством UNIGINE SDK Browser, предоставляющего централизованный интерфейс для навигации по ресурсам и контроля над ними.
|
||||
|
||||
\subsection{Координатная система}
|
||||
|
||||
Трехмерное пространство виртуальной среды описывается декартовой системой координат, ориентированной согласно правилу правой руки: оси X и Y определяют горизонтальную плоскость, а ось Z указывает вертикально вверх.
|
||||
|
||||
При экспорте 3D-моделей и анимации из внешних графических редакторов ось Y интерпретируется как вектор, указывающий направление движения. Положительные углы вращения соответствуют повороту вектора против часовой стрелки в данной координатной системе, что согласуется с правилом буравчика (или правой руки). Этот подход обеспечивает унифицированный и бесшовный процесс обмена данными между различными инструментами моделирования и движком.
|
||||
|
||||
\subsection{Мир}
|
||||
|
||||
В рамках мира UNIGINE формируется виртуальная трехмерная сцена, служащая полотном для визуализации и интерактивных процессов. Эта сцена насыщена различными компонентами, именуемыми узлами или нодами, такими как 3D-модели, источники света, камеры и прочие элементы. Узлы размещаются в определенных локациях внутри сцены, формируя ее визуальную композицию.
|
||||
|
||||
Структура сцены в UNIGINE организована как иерархическое дерево узлов, известное как граф сцены. Это подразумевает, что каждый узел может включать дочерние узлы, создавая сложные взаимосвязи между объектами. Например, узел, представляющий транспортное средство, может содержать дочерние узлы для его колес, двигателя и других составляющих.
|
||||
|
||||
Каждый мир сохраняется в формате XML-файла с расширением `.world`. Этот файл содержит исчерпывающую информацию о мире, включая размещение и конфигурацию всех узлов, а также глобальные настройки, такие как параметры рендеринга и физического взаимодействия, применимые ко всей сцене.
|
||||
|
||||
При инициализации нового проекта в UNIGINE через SDK Browser автоматически генерируется стартовый мир с идентичным названием. Этот мир можно модифицировать, а также создавать дополнительные миры для проекта с использованием UnigineEditor, что позволяет разработчикам параллельно работать над несколькими сценами, оптимизируя процесс разработки и тестирования.
|
||||
|
||||
\subsection{Узел}
|
||||
|
||||
В UNIGINE все элементы, добавляемые в виртуальную сцену, называются узлами или нодами. Узлы подразделяются на различные типы, определяющие их внешний вид и функциональность. Движок предоставляет обширный набор встроенных типов узлов, охватывающий широкий спектр объектов и эффектов, удовлетворяющий большинство стандартных потребностей. Помимо этого, предусмотрена возможность создания пользовательских узлов. Функциональность любого узла может быть расширена путем добавления к нему компонентов, что позволяет прикреплять дополнительные свойства и поведенческие характеристики.
|
||||
|
||||
Каждый узел обладает матрицей преобразования, которая определяет его пространственное положение, ориентацию и размер в виртуальном мире, обеспечивая полный контроль над локализацией и вращением элементов. Некоторые узлы имеют визуальное представление, например, 3D-модели, декали (элементы декора) и различные эффекты. Другие узлы, такие как источники освещения или контроллеры игрового процесса, могут быть невидимыми, но тем не менее являются неотъемлемой частью виртуальной среды.
|
||||
|
||||
Параметры каждого узла сохраняются в файле `.world`, однако их также можно вынести в отдельный XML-файл с расширением `.node`. Это целесообразно, когда требуется создать множество идентичных узлов, ссылаясь на них из основного файла `.world` посредством специальных узлов типа "Node References", которые служат для создания множественных экземпляров одного и того же элемента.
|
||||
|
||||
\subsection{Объект}
|
||||
|
||||
Одним из наиболее значимых типов узлов является объект. Объекты представляют собой виртуальные аналоги сущностей из реального мира: это могут быть предметы (люди, деревья, транспортные средства и т.д.), элементы окружающей среды (небо, рельеф, водные поверхности) и многое другое. Объекты характеризуются одной или несколькими поверхностями, определяющими их визуальный облик. Они могут обладать коллизионной формой, определяющей занимаемый объем в 3D-пространстве, и физическим телом, участвующим в симуляции физических взаимодействий.
|
||||
|
||||
\subsection{Меш}
|
||||
|
||||
Меш (полигональная сетка) составляет фундаментальную геометрическую основу любого объекта в трехмерной сцене. Он представляет собой совокупность многоугольников, которые формируют очертания и внешний вид объекта.
|
||||
|
||||
Каждая полигональная сетка может включать одну или несколько поверхностей, определяющих визуальные характеристики объекта. Поверхности состоят из многоугольников; максимальное количество многоугольников на одной поверхности зависит от типа меша. Например, статические и скелетные меши способны содержать до 2 147 483 647 многоугольников на поверхность, тогда как динамические меши ограничены 65 535 многоугольниками на поверхность.
|
||||
|
||||
Меш поддерживает наличие двух UV-каналов, используемых для наложения текстур на поверхность объекта. Эти каналы обеспечивают точное позиционирование текстурных карт на геометрии меша. Кроме того, меш позволяет хранить информацию о цвете каждой вершины, что дает возможность создавать разнообразные визуальные эффекты и тонко настраивать цветовую палитру объектов.
|
||||
|
||||
В UNIGINE анимация объектов реализуется различными способами. Это включает в себя использование обтекаемых сеток (skinning), которые применяют скелетные деформации через "кости" для анимации, морф-цели (morph targets) для создания ключевых кадров деформации, а также динамические сетки, управляемые программно. Анимационные данные мешей сохраняются в собственных форматах UNIGINE с расширениями `.mesh` (для статических и скелетных мешей, включающих анимацию) и `.anim` (для внешних анимационных последовательностей).
|
||||
|
||||
\subsection{Поверхность и материал}
|
||||
|
||||
Поверхность — это именованный, непересекающийся подраздел геометрии объекта (то есть его полигональной сетки). Каждая поверхность может иметь свой уникальный материал или набор свойств, что позволяет индивидуально настраивать внешний вид и поведение каждой части объекта. Поверхности могут быть активированы или деактивированы независимо друг от друга.
|
||||
|
||||
Поверхности также могут быть организованы иерархически в рамках общей сетки объекта. Эта структура может быть использована, например, для управления уровнем детализации (LOD) объекта, позволяя переключаться между различными версиями объекта с разным количеством полигонов и детализацией поверхностей в зависимости от расстояния до наблюдателя или других факторов.
|
||||
|
||||
В UNIGINE материал представляет собой совокупность правил, определяющих визуальные характеристики поверхности объекта. Эти правила охватывают как поведение поверхности при взаимодействии с источниками освещения, так и параметры отражения, прозрачности и прочие атрибуты.
|
||||
|
||||
Материал базируется на нескольких ключевых компонентах:
|
||||
|
||||
\begin{itemize}
|
||||
\item \textbf{Шейдеры}: Программные модули, которые диктуют процесс рендеринга материала. В UNIGINE используются вершинные, фрагментные и геометрические шейдеры, которые оперируют данными на уровне пикселей и вершин, а также манипулируют геометрией объекта.
|
||||
\item \textbf{Текстуры}: Графические изображения, которые могут быть применены к материалу. Эти текстуры передаются шейдерам для определения детального визуального облика поверхности.
|
||||
\end{itemize}
|
||||
|
||||
\newpage
|
||||
\section{Симуляция физических явлений в Unigine}
|
||||
|
||||
В Unigine физическая симуляция занимает центральное место, предоставляя разработчикам обширный арсенал инструментов для создания реалистичных взаимодействий объектов в виртуальной среде. Движок включает в себя интегрированный модуль физического моделирования, позволяющий воспроизводить разнообразные физические явления. Ниже представлены основные аспекты физической симуляции, поддерживаемые Unigine:
|
||||
|
||||
\begin{itemize}
|
||||
\item \textbf{Обработка столкновений}: Unigine способен обнаруживать и корректно обрабатывать соударения между объектами. Это критически важно для имитации правдоподобных взаимодействий, таких как удары, падения и другие виды контактов.
|
||||
\item \textbf{Динамика твердых тел}: Платформа поддерживает полноценное моделирование физики твердых тел, что позволяет объектам вести себя достоверно при взаимодействии друг с другом и под действием внешних сил. Это включает учет таких свойств, как масса, инерция и коэффициенты трения.
|
||||
\item \textbf{Процедурное разрушение}: Unigine предоставляет возможность динамического разрушения объектов, что полезно для реализации эффектов взрывов, обрушений конструкций и других динамичных сценариев.
|
||||
\item \textbf{Моделирование текстильных материалов}: Движок поддерживает имитацию поведения текстильных материалов, что позволяет создавать убедительные эффекты для тканей, одежды и прочих гибких поверхностей.
|
||||
\item \textbf{Плавучесть объектов}: Unigine включает функционал для симуляции плавучести объектов, что находит применение при создании водных сред и интерактивных взаимодействий с жидкостями.
|
||||
\item \textbf{Поля сил}: Система поддерживает создание и управление полями сил, позволяя моделировать такие воздействия, как гравитационные поля, ветровые потоки и другие силовые эффекты на объекты.
|
||||
\item \textbf{Реверс времени}: Unigine обеспечивает возможность воспроизведения событий в обратном порядке, что может быть использовано для реализации эффектов замедления, приостановки и обратного хода времени.
|
||||
\end{itemize}
|
||||
|
||||
Физическое поведение объектов в UNIGINE формируется на основе концепций тел и их коллизионных форм, что позволяет точно имитировать различные физические свойства и взаимодействия. Для придания объекту физических свойств необходимо назначить ему соответствующее тело.
|
||||
|
||||
Тело (Body) — это ключевой компонент объекта, отвечающий за его физическое поведение. В UNIGINE доступны несколько типов тел:
|
||||
|
||||
\begin{itemize}
|
||||
\item \textbf{Жесткое тело (Rigid Body)}: Моделирует нерушимое, твердое поведение объекта. Взаимодействует с другими жесткими телами и внешними физическими силами.
|
||||
\item \textbf{Тряпичная кукла (RagDoll)}: Представляет собой деформируемый объект, гибко реагирующий на внешние воздействия. Используется для имитации мягких тканей или анатомических моделей.
|
||||
\item \textbf{Разрушаемое тело (Fracture)}: Позволяет объекту распадаться на фрагменты под действием силы или при столкновении. Примером может служить симуляция разрушаемых зданий или объектов.
|
||||
\item \textbf{Шнур (Rope)}: Гибкий объект, предназначенный для создания веревок, цепей или других подвижных элементов.
|
||||
\item \textbf{Ткань (Cloth)}: Позволяет создавать объекты, деформирующиеся под воздействием сил, имитируя текстильные материалы.
|
||||
\item \textbf{Вода (Water)}: Специализированное тело, имитирующее поведение жидкости, включая течение, взаимодействие с объектами и плавучесть.
|
||||
\item \textbf{Траектория (Path)}: Позволяет объекту следовать по заранее определенному пути, что полезно для анимации движения.
|
||||
\end{itemize}
|
||||
|
||||
Форма объекта определяет его коллизионную геометрию, то есть то, как объект будет взаимодействовать с окружающими элементами и физическими силами. UNIGINE поддерживает следующие геометрические примитивы для коллизионных форм: сфера (sphere), капсула (capsule), цилиндр (cylinder), куб (box), выпуклая оболочка (convex hull).
|
||||
|
||||
Каждая коллизионная форма может быть ассоциирована с физическим телом объекта, определяя его взаимодействия со средой. Это обеспечивает высокую точность в моделировании физического поведения объектов.
|
||||
\newpage
|
||||
|
||||
\section{Имплементация сцены}
|
||||
\subsection{Подготовка и создание виртуального мира}
|
||||
Для начала работы с движком UNIGINE нужно установить несколько ключевых программ: UNIGINE SDK и UNIGINE SDK Browser. В работе над данной лабораторной работой использовались версии SDK 2.19.1.2 и SDK Browser 2.0.27. Все необходимые для работы модули доступны для загрузки с официального веб-сайта: \url{https://unigine.com/get-unigine/}.
|
||||
|
||||
После завершения установки и успешной авторизации в системе следует создать новый проект. В процессе создания проекта возможно указать требуемые API, интегрированную среду разработки (IDE), параметры точности, версию SDK и тип версии. Для создания обоих сцен были выбраны одинаковые параметры, представленные на \hyperref[pic1]{рисунке 1}.
|
||||
|
||||
\begin{figure}[h!]
|
||||
\centering{
|
||||
\includegraphics[width=70mm]{Pic1.png}
|
||||
\caption{\centering{{Конфигурация создаваемого объекта}}}
|
||||
}
|
||||
\label{pic1}
|
||||
\end{figure}\par
|
||||
|
||||
По завершении создания проекта открываем редактор, нажимая на кнопку \texttt{Open Editor}, в панеле снизу у созданного мира. После нажатия кнопки откроется виртуальный мир, чей внешний вид представлен на \hyperref[pic2]{рисунке 2}.
|
||||
\begin{figure}[h!]
|
||||
\centering{
|
||||
\includegraphics[width=140mm]{Pic2.png}
|
||||
\caption{\centering{{Интерфейс редактора с инициализированным миром}}}
|
||||
}
|
||||
\label{pic2}
|
||||
\end{figure}\par
|
||||
|
||||
\newpage
|
||||
|
||||
\subsection{Подготовка и импорт 3D-моделей}
|
||||
|
||||
В ходе выполнения лабораторной работы №1 в Blender 3D были созданы реалистические модели трех объектов: игральной фишки, зажима для хлеба и обломанной линейки.
|
||||
|
||||
Для того, чтобы перенести эти объекты в Unigine, включая их текстурные карты нужно экспортировать их из Blender. Для этого нужно выполнить следующие действия:
|
||||
\begin{enumerate}
|
||||
\item Откройте меню "File".
|
||||
\item Выберите пункт "Export".
|
||||
\item Укажите формат FBX (.fbx) для сохранения модели.
|
||||
\end{enumerate}
|
||||
Общий процесс представлен на \hyperref[pic3]{рисунке 3.}\par
|
||||
Важным моментом является сохранение реальных пропорций экспортируемой модели. В случае обнаружения различий требуется изменить масштаб объекта и зафиксировать изменения через последовательность команд \texttt{Object $\rightarrow$ Apply $\rightarrow$ All Transformations}. После этого параметр масштаба устанавливается равным 1, что обеспечивает корректность дальнейшей работы с моделью.
|
||||
|
||||
\begin{figure}[h!]
|
||||
\centering{
|
||||
\includegraphics[width=100mm]{Pic3.png}
|
||||
\caption{\centering{{Процедура экспорта модели из Blender}}}
|
||||
}
|
||||
\label{pic3}
|
||||
\end{figure}\par
|
||||
|
||||
|
||||
Для импорта всех подготовленных моделей в Unigine выполните следующие шаги:
|
||||
\begin{enumerate}
|
||||
\item В окне Asset Browser создайте отдельные директории для каждого импортируемого объекта.
|
||||
\item Откройте соответствующую директорию.
|
||||
\item Кликните правой кнопкой мыши (ПКМ) и выберите опцию "Импортировать".
|
||||
\item Настройте параметры импорта согласно представленному изображению.
|
||||
\end{enumerate}
|
||||
\begin{figure}[h!]
|
||||
\centering{
|
||||
\includegraphics[width=100mm]{Pic4.png}
|
||||
\caption{\centering{{Конфигурация импорта модели в Unigine}}}
|
||||
}
|
||||
\label{pic4}
|
||||
\end{figure}\par
|
||||
|
||||
|
||||
Для размещения моделей непосредственно в рабочей области сцены необходимо нажать левую кнопку мыши (ЛКМ) на файле формата .fbx в Asset Browser и перетащить его на визуальное представление мира. Визуализация импортированной модели представлена на \hyperref[pic5]{рисунке 5}.
|
||||
\begin{figure}[h!]
|
||||
\centering{
|
||||
\includegraphics[width=100mm]{Pic5.png}
|
||||
\caption{\centering{{Конфигурация импорта модели в Unigine}}}
|
||||
}
|
||||
\label{pic5}
|
||||
\end{figure}\par
|
||||
Заметим, что зажим состоит из трех объектов. Для того чтобы это исправить, экспортируем модель в UNIGINE Mesh Object. Для этого в графе \texttt{World Nodes} нажать на вкладку модели и перейти по всплывающему меню: \texttt{Export to} $\rightarrow$ \texttt{Unigine mesh file (.mesh)}. Процесс выбора представлен на \hyperref[pic6]{рисунке 6}\par
|
||||
|
||||
\begin{figure}[h!]
|
||||
\centering{
|
||||
\includegraphics[width=100mm]{Pic6.png}
|
||||
\caption{\centering{{Процесс экспорта модели}}}
|
||||
}
|
||||
\label{pic6}
|
||||
\end{figure}\par
|
||||
|
||||
После этого экспортированную модель увидим в графе \texttt{Assets Browser}, что представлено на \hyperref[pic7]{рисунке 7}
|
||||
\begin{figure}[h!]
|
||||
\centering{
|
||||
\includegraphics[width=100mm]{Pic7.png}
|
||||
\caption{\centering{{Результат экспорта модели}}}
|
||||
}
|
||||
\label{pic7}
|
||||
\end{figure}\par
|
||||
При перетаскивании объекта на сцену увидим, что модель переносится без наложенных текстур. Для того, чтобы придать модели исходный вид нужно открыть папку с материалами, выбрать материал и перенести на ту часть объекта, которая должна быть окрашена в тот цвет который нам нужен. Процесс наложения материалов на объект представлен на \hyperref[pic8]{рисунке 8}.
|
||||
|
||||
\begin{figure}[h!]
|
||||
\centering{
|
||||
\includegraphics[width=100mm]{Pic8.png}
|
||||
\caption{\centering{{Процесс наложения текстур на модель}}}
|
||||
}
|
||||
\label{pic8}
|
||||
\end{figure}\par
|
||||
\newpage
|
||||
\subsection{Настройка физических свойств моделей}
|
||||
|
||||
Для обеспечения реалистичного взаимодействия объектов друг с другом и с окружающей средой требуется конфигурирование их физических атрибутов. Для этого выполните следующие действия:
|
||||
\begin{enumerate}
|
||||
\item Выделите целевой объект, используя левую кнопку мыши (ЛКМ).
|
||||
\item Перейдите на вкладку "Parameters" (Параметры).
|
||||
\item В разделе "Node" (Узел) выберите опцию "Dynamic" (Динамический), как показано на \hyperref[pic9]{рисунке 9}.
|
||||
\end{enumerate}
|
||||
\begin{figure}[h!]
|
||||
\centering{
|
||||
\includegraphics[width=90mm]{Pic9.png}
|
||||
\caption{\centering{{Активация динамических свойств объекта}}}
|
||||
}
|
||||
\label{pic9}
|
||||
\end{figure}\par
|
||||
|
||||
После этого нужно переключиться в вкладку \texttt{Physics} вкладки \texttt{Parameters}
|
||||
Для наших моделей также следует выбрать тип "Rigid body" (Твёрдое тело) и убрать отметку с опции "Shape-based" (На основе формы). С помощью этого можно будет задать параметры вручную:
|
||||
\begin{enumerate}
|
||||
\item Для игральной фишки используйте параметры, представленные на \hyperref[pic10]{рисунке 10}.
|
||||
\item Для зажима для хлеба примените конфигурацию, показанную на \hyperref[pic11]{рисунке 11.}
|
||||
\item Для обломанной линейки задайте параметры согласно \hyperref[pic12]{рисунку 12.}
|
||||
\end{enumerate}
|
||||
Эти параметры включают в себя значения массы и инерции по всем осям, что необходимо для корректного моделирования вращения и отскока объектов при столкновении с поверхностями и другими сущностями. Некоторые параметры остались без изменений, соответствуя значениям по умолчанию.
|
||||
\begin{figure}[h!]
|
||||
\begin{multicols}{2}
|
||||
\hfill
|
||||
\centering{\includegraphics[width=60mm]{pic10.png}}
|
||||
\caption{\centering{Параметры физического тела для игральной фишки}}
|
||||
\label{pic10}
|
||||
\hfill
|
||||
\includegraphics[width=68mm]{pic11.png}
|
||||
\hfill
|
||||
\caption{\centering{Параметры физического тела для зажима для хлеба}}
|
||||
\label{pic11}
|
||||
\end{multicols}
|
||||
\end{figure}
|
||||
|
||||
\begin{figure}[h!]
|
||||
\centering{
|
||||
\includegraphics[width=80mm]{Pic12.png}
|
||||
\caption{\centering{{Параметры физического тела для обломанной линейки}}}
|
||||
}
|
||||
\label{pic12}
|
||||
\end{figure}\par
|
||||
|
||||
|
||||
Далее для всех интерактивных объектов выберите опцию "Autogenerated" \ для определения их коллизионной формы. Ввиду сложной геометрии данных объектов, программное обеспечение автоматически подберет наиболее подходящую аппроксимирующую форму. Например, после выбора "Autogenerated" для обломанной линейки была автоматически назначена форма "Convex" (Выпуклая оболочка), как продемонстрировано на \hyperref[pic13]{рисунке 13}. Аналогичную процедуру выбора формы столкновения необходимо выполнить и для остальных моделей.
|
||||
|
||||
\begin{figure}[h!]
|
||||
\centering{
|
||||
\includegraphics[width=80mm]{Pic13.png}
|
||||
\caption{\centering{{Автоматический выбор формы столкновения для обломанной линейки}}}
|
||||
}
|
||||
\label{pic13}
|
||||
\end{figure}\par
|
||||
|
||||
\newpage
|
||||
\subsection{Пространственное размещение моделей}
|
||||
|
||||
На следующем этапе необходимо позиционировать объекты в виртуальном пространстве согласно разработанной структуре сцены. Для этого перейдите на вкладку Parameters->Node и задайте следующие пространственные параметры:
|
||||
\begin{figure}[h!]
|
||||
\begin{multicols}{2}
|
||||
\hfill
|
||||
\centering{\includegraphics[width=60mm]{pic14.png}}
|
||||
\caption{\centering{Позиция первой обломанной линейки}}
|
||||
\label{pic14}
|
||||
\hfill
|
||||
\includegraphics[width=68mm]{pic15.png}
|
||||
\hfill
|
||||
\caption{\centering{Позиция второй обломанной линейки}}
|
||||
\label{pic15}
|
||||
\end{multicols}
|
||||
\end{figure}
|
||||
|
||||
\begin{figure}[h!]
|
||||
\begin{multicols}{2}
|
||||
\hfill
|
||||
\centering{\includegraphics[width=60mm]{pic16.png}}
|
||||
\caption{\centering{Позиция первой игральной фишки}}
|
||||
\label{pic16}
|
||||
\hfill
|
||||
\includegraphics[width=68mm]{pic17.png}
|
||||
\hfill
|
||||
\caption{\centering{Позиция второй игральной фишки}}
|
||||
\label{pic17}
|
||||
\end{multicols}
|
||||
\end{figure}
|
||||
\begin{figure}[h!]
|
||||
\begin{multicols}{2}
|
||||
\hfill
|
||||
\centering{\includegraphics[width=60mm]{pic18.png}}
|
||||
\caption{\centering{Позиция первого зажима для хлеба}}
|
||||
\label{pic18}
|
||||
\hfill
|
||||
\includegraphics[width=68mm]{pic19.png}
|
||||
\hfill
|
||||
\caption{\centering{Позиция второго зажима для хлеба}}
|
||||
\label{pic19}
|
||||
\end{multicols}
|
||||
\end{figure}
|
||||
|
||||
|
||||
|
||||
\subsection{Активация физической симуляции}
|
||||
|
||||
Для активации физического поведения и взаимодействия объектов в сцене необходимо нажать центральную кнопку, расположенную в правом верхнем углу интерфейса редактора (\hyperref[pic20]{рисунок 20}).
|
||||
\begin{figure}[h!]
|
||||
\centering{
|
||||
\includegraphics[width=80mm]{Pic20.png}
|
||||
\caption{\centering{{Кнопка запуска физической симуляции}}}
|
||||
}
|
||||
\label{pic20}
|
||||
\end{figure}\par
|
||||
|
||||
|
||||
|
||||
\subsection{Конфигурация окружения}
|
||||
\subsubsection{Создание базовой поверхности}
|
||||
Чтобы наглядно отобразить физические характеристики моделей, необходимо подготовить подходящее окружение. В первой сцене используется неподвижная плоскость, позволяющая продемонстрировать взаимодействие объектов с твёрдой поверхностью. Во второй сцене создаётся водный объём, который показывает различия в поведении предметов при всплытии и погружении в зависимости от их массы и плотности материала.
|
||||
|
||||
|
||||
Для создания твердой поверхности выполните следующие действия:
|
||||
\begin{enumerate}
|
||||
\item Откройте меню "Create" (Создать).
|
||||
\item Выберите пункт "Primitive" (Примитив).
|
||||
\item Определите тип примитива как "Box" (Куб), как показано на рисунке 21.
|
||||
\item Кликните левой кнопкой мыши в произвольном месте сцены для размещения объекта.
|
||||
|
||||
\end{enumerate}
|
||||
\begin{figure}[h!]
|
||||
\centering{
|
||||
\includegraphics[width=100mm]{Pic21.png}
|
||||
\caption{\centering{{Процесс создания поверхности сцены}}}
|
||||
}
|
||||
\label{pic21}
|
||||
\end{figure}\par
|
||||
|
||||
|
||||
Когда все модели и сама плоскость были преобразованы в динамические объекты, необходимо перейти во вкладку \texttt{Parameters} и открыть раздел \texttt{Physics}. Далее требуется задать характеристики поверхности, на которую будут падать элементы сцены. Для этого выполняются следующие действия:
|
||||
\begin{enumerate}
|
||||
\item В параметре типа тела выбрать \texttt{Rigid body} (Твёрдое тело).
|
||||
\item Включить опцию \texttt{Immovable} (Неподвижный).
|
||||
\item Остальные параметры оставить без изменений, как показано на \hyperref[pic22]{рисунке 22}. Это позволит поверхности оставаться статичной, сохраняя при этом возможность корректного взаимодействия с динамическими объектами.
|
||||
\item В качестве формы коллизии задать \texttt{Box} (Куб), что отражено на \hyperref[pic23]{рисунке 23}.
|
||||
\end{enumerate}
|
||||
|
||||
\begin{figure}[h!]
|
||||
\centering{
|
||||
\includegraphics[width=70mm]{Pic22.png}
|
||||
\caption{\centering{{Выбор типа физического тела для поверхности}}}
|
||||
}
|
||||
\label{pic22}
|
||||
\end{figure}\par
|
||||
\begin{figure}[h!]
|
||||
\centering{
|
||||
\includegraphics[width=90mm]{Pic23.png}
|
||||
\caption{\centering{{Назначение формы столкновения для поверхности}}}
|
||||
}
|
||||
\label{pic23}
|
||||
\end{figure}\par
|
||||
|
||||
\subsubsection{Параметры водной среды}
|
||||
Во второй сцене требуется задать физические свойства воды. Для этого выполните следующие шаги:
|
||||
\begin{enumerate}
|
||||
\item Откройте меню \texttt{Create -> Water -> Physical Water}.
|
||||
\item Настройте параметры согласно схеме на \hyperref[pic21]{рисунке 21}.
|
||||
\end{enumerate}
|
||||
|
||||
\textbf{Physical Water} представляет собой кубическую область, внутри которой рассчитываются эффекты взаимодействия объектов с жидкостью. Обычно этот элемент используется вместе с узлами типа "Water" — добавление компонента позволяет явно определить участок сцены, где будут действовать законы гидродинамики.
|
||||
|
||||
Ниже приведены основные параметры настройки:
|
||||
\begin{itemize}
|
||||
|
||||
\item \textbf{Physical Mask}
|
||||
\par Маска \texttt{Physical Water} должна совпадать с маской физических объектов. Если значения различаются, область не будет оказывать влияние на модель.
|
||||
|
||||
\item\textbf{Size}
|
||||
\par Задает размеры области \texttt{Physical Water} по осям X, Y и Z (в единицах движка).
|
||||
|
||||
\item\textbf{Velocity}
|
||||
\par Определяет скорость течения воды внутри выделенной зоны по каждой оси.
|
||||
|
||||
\item\textbf{Density}
|
||||
\par Отвечает за плотность воды, которая влияет на поведение объектов:
|
||||
\par - Увеличение значения повышает силу Архимеда и способствует всплытию.
|
||||
\par - Уменьшение плотности приводит к более глубокому погружению тел.
|
||||
|
||||
\item\textbf{Linear Damping}
|
||||
\par Контролирует замедление поступательного движения в воде:
|
||||
\par - Чем выше параметр, тем быстрее уменьшается скорость перемещения.
|
||||
|
||||
\item\textbf{Angular Damping}
|
||||
\par Отвечает за снижение угловой скорости вращения:
|
||||
\par - Большие значения обеспечивают более быстрое затухание вращения.
|
||||
|
||||
\begin{figure}[h!]
|
||||
\centering{
|
||||
\includegraphics[width=90mm]{Pic24.png}
|
||||
\caption{\centering{{Настройка параметров водной среды}}}
|
||||
}
|
||||
\label{pic21}
|
||||
\end{figure}\par
|
||||
\end{itemize}
|
||||
\newpage
|
||||
\section{Итоги проделанной работы}
|
||||
По итогам работы были сгенерированы две видеозаписи, демонстрирующие реализованные сцены.
|
||||
\subsection{Анализ первой сцены}
|
||||
Кадры из первой сцены представлены на рис. 22-25. На них видно, что все объекты под действием гравитации совершили падение на поверхность и после этого стабилизировались.
|
||||
|
||||
\begin{figure}[h!]
|
||||
\centering{
|
||||
\includegraphics[width=90mm]{Pic25.png}
|
||||
\caption{\centering{Визуализация первой сцены}}
|
||||
}
|
||||
|
||||
\label{ris1}
|
||||
\end{figure}
|
||||
|
||||
\begin{figure}[h!]
|
||||
\centering{
|
||||
\includegraphics[width=90mm]{Pic26.png}
|
||||
\caption{\centering{Визуализация первой сцены (продолжение)}}
|
||||
}
|
||||
|
||||
\label{ris1}
|
||||
\end{figure}
|
||||
|
||||
\begin{figure}[h!]
|
||||
\centering{
|
||||
\includegraphics[width=90mm]{Pic27.png}
|
||||
\caption{\centering{Визуализация первой сцены (продолжение)}}
|
||||
}
|
||||
|
||||
\label{ris1}
|
||||
\end{figure}
|
||||
|
||||
\begin{figure}[h!]
|
||||
\centering{
|
||||
\includegraphics[width=90mm]{Pic28.png}
|
||||
\caption{\centering{Визуализация первой сцены (продолжение)}}
|
||||
}
|
||||
|
||||
\label{ris1}
|
||||
\end{figure}
|
||||
|
||||
\newpage
|
||||
\subsection{Анализ второй сцены}
|
||||
Кадры из второй сцены представлены на рис. 26-29. В этой сцене, помимо гравитационного воздействия, на объекты также влияла выталкивающая сила Архимеда. В результате, игральная фишка и обломанная линейка, обладающие большей плотностью, относительно быстро опустились на дно, в то время как зажим для хлеба, имеющий меньшую плотность, тонет медленнее всех.
|
||||
|
||||
\begin{figure}[h!]
|
||||
\centering{
|
||||
\includegraphics[width=90mm]{Pic29.png}
|
||||
\caption{\centering{Визуализация второй сцены }}
|
||||
}
|
||||
|
||||
\label{ris1}
|
||||
\end{figure}
|
||||
|
||||
\begin{figure}[h!]
|
||||
\centering{
|
||||
\includegraphics[width=90mm]{Pic30.png}
|
||||
\caption{\centering{Визуализация второй сцены (продолжение)}}
|
||||
}
|
||||
|
||||
\label{ris1}
|
||||
\end{figure}
|
||||
|
||||
\begin{figure}[h!]
|
||||
\centering{
|
||||
\includegraphics[width=90mm]{Pic31.png}
|
||||
\caption{\centering{Визуализация второй сцены (продолжение)}}
|
||||
}
|
||||
|
||||
\label{ris1}
|
||||
\end{figure}
|
||||
|
||||
\begin{figure}[h!]
|
||||
\centering{
|
||||
\includegraphics[width=90mm]{Pic32.png}
|
||||
\caption{\centering{Визуализация второй сцены (продолжение)}}
|
||||
}
|
||||
|
||||
\label{ris1}
|
||||
\end{figure}
|
||||
\newpage
|
||||
\hfill
|
||||
\newpage
|
||||
\hfill
|
||||
\newpage
|
||||
\section*{Заключение} {\addcontentsline {toc}{section}{Заключение}}
|
||||
В процессе выполнения лабораторной работы было проведено детальное знакомство с основными возможностями графического движка UNIGINE и изучены базовые этапы его использования.
|
||||
|
||||
На подготовительном этапе в виртуальную сцену были добавлены три объекта, созданные в Blender 3D: пластиковый зажим для хлеба, игральная фишка и линейка. Для корректного воспроизведения физических процессов моделям были назначены свойства жёстких тел (Rigid Body), определены подходящие формы коллизий и вручную заданы значения массы.
|
||||
|
||||
В рамках эксперимента были построены две демонстрационные сцены:
|
||||
\begin{enumerate}
|
||||
\item Падение объектов с разными физическими параметрами на твёрдую поверхность.
|
||||
\item Симуляция поведения тел различной плотности в жидкой среде.
|
||||
\end{enumerate}
|
||||
|
||||
Для отображения и расчёта гидродинамических эффектов применялись следующие элементы:
|
||||
\begin{itemize}
|
||||
\item визуализация поверхности воды,
|
||||
\item физический компонент воды с регулируемыми параметрами потока,
|
||||
\item статическая плоскость, выполняющая роль основания в первой сцене.
|
||||
\end{itemize}
|
||||
|
||||
\newpage
|
||||
{\addcontentsline {toc}{section}{Список литературы}}
|
||||
|
||||
\begin{thebibliography}{}
|
||||
\bibitem{lit1} UNIGINE documentation: \url{https://developer.unigine.com/en/docs/latest/} (дата обращения: 25.08.2025)
|
||||
|
||||
\end{thebibliography}
|
||||
\end{document}
|
||||