Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Системы автоматизированного проектирования. Моделирование в машиностроении. Учебное пособие

.pdf
Скачиваний:
0
Добавлен:
08.09.2026
Размер:
2 Мб
Скачать
☆
ps : TPaintStruct; begin BeginPaint(Handle, ps); glClear( GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT ); glPushMatrix; glRotatef (Angle, 0.0, 0.0, 1.0); glCallList(obj); glPopMatrix; SwapBuffers(DC); EndPaint(Handle, ps); end;
Результат работы программы изображен на рисунке 5.16.
Рисунок 5.16 – Пример работы приложения (наложение текстуры на
сферу)
5.4.4 Задание на выполнение работы
Проверить работу программного кода и выполнить изменения в нем, по
указанию преподавателя.
Содержание отчета: – название работы; – цель работы; – перечень используемых команд; – экранные формы; – листинг программы.
61
5.4.5 Контрольные вопросы
Что такое текстура? Как определяется качество поверхности при наложении текстуры? Какие виды текстуры бывают? Как наложить текстуру на объект?
5.5 В – сплайн, Nurbs, Безье поверхности
5.5.1 Цель работы
Целью работы является приобретение навыков построения кубических
В-сплайнов используя функции графической библиотеки OpenGL.
5.5.2 Моделирование кривых поверхностей
5.5.2.1 Параметрическое представление сплайнов
Для того чтобы использовать сложные кривые на практике, обычно ис-
пользуется их параметрическое представление. Таким образом, любая из то-
чек на какой-либо части кривой, лежащая между двумя заданными последо­вательными точками Pi и Pi + 1, которая будет иметь координаты (x(t); y(t)) , значение t будет меняться от 0.0 до 1.0, в том случае, если строится часть кривой от Pi до Pi+1.
В том случае, если есть заданные точки P0(x0, y0), P1(x1, y1), … Pn(xn, yn),
то часть кривой B-сплайна между точками Pi и Pi+1 определяется как после­довательностью точек с координатами (x(t), y(t)), при 0,0 ≤ t ≤ 1,0:
x(t) = a0+ a1t + a2t2 + a3t3;
y(t) = b0+ b1t + b2t2 + b3t3. (5.4)
Эти уравнения содержат следующие коэффициенты:
a0 = (xi-1 + 4xi + xi+1)/6; a1 = (-xi-1 + xi+1)/2;
a2 = (xi-1 – 2xi + xi+1)/2; (5.5)
a3 = (-xi-1 + 3xi - 3xi+1 + xi+2)/6.
Коэффициенты b
, … b
0
вычисляются аналогично по значениям yi-1, …
3
yi+2. Для производительности алгоритма важно, что ai и bi вычисляются только один раз для каждого сегмента кривой.
62
5.5.2.2 Свойства сплайнов Кривые типа B-сплайна обладают свойством непрерывности даже вто-
рых производных x²(t) и y²(t) в точках стыковки двух соседних сегментов
кривой. Для определения свойств кривой в точках стыковки двух сегментов
рассмотрим функцию x(t) и ее первую и вторую производные для значений t =0 и t = 1.
Функция y(t) будет обладать аналогичными свойствами.
x(0) = a0 = (xi-1 + 4xi + xi+1)/6;
x(1) = a1 + a2 + a3 + a2 = (xi + 4xi+1 + xi+2)/6. (5.6)
То есть значение x(0) не равно в точности x-координате xi точки Pi: оно зависит от позиций точек Pi-1 и Pi+1. Для трех последовательных точек на кривой A, B и C точка B принадлежит сегменту AB и одновременно сегменту
BC (рисунок 5.17).
Для первого сегмента A = Pi, B = Pi+1, C = Pi+2. Тогда x~B = x(1) = (xA
+ 4xB + xC)/6, где x~B – вычисленное значение координаты x для точки B.
Рисунок 5.17 - Фрагменты сплайна
Для второго сегмента A = Pi-1, B = Pi, C = Pi+1 и x~B = x(0) = (xA + 4xB + xC)/6. Одинаковые результаты означают непрерывность функции x(t) в точке B. Продифференцировав x(t) дважды, найдем x'(t) и x²(t):
x'(t) = a1 + 2a2t + 3a3t2; x²(t) = 2a2 + 6a3t (5.7)
Подставляя в них значения t = 0 и t = 1, находим:
x'(0) = a1 = (-xi-1 + xi+1)/2; x'(1) = a1 + 2a2 + 3a3 = (-xi + xi+2)/2;
x²(0) = 2a
= xi-1 - 2xi + xi+1; x²(1) = 2a2 + 6a3 = xi - 2xi+1 + xi+2. (5.8)
2
Тогда значение первой производной в точке B, вычисленное для пер­вого сегмента кривой, (x')~B = x'(1) = (-xA + xC)/2 совпадает со значением
63
первой производной в той же точке, вычисленное для следующего сегмента,

n0im
0j
j,i
P)v(
m
j
B)u(
n
i
B)v,u(p
in
u
i
u
ini
n
in
u
i
u
n i
u
n
i
B
)1(
)!(!
!
)1()()(
(x')~B = x'(0).
Точно так же и значение второй производной в точке B, вычисленное для первого сегмента кривой, (x²)~B = x²(1) = xA - 2xB + xC совпадает со зна­чением второй производной в той же точке, вычисленное для следующего сегмента (x²)~B = x² (0).
Таким образом, не только сама кривая, но и ее первые две производ­ные непрерывны в каждой точке кривой, то есть вся кривая является очень
гладкой.
Для расчета любого сегмента кривой между точками Pi и Pi+1 исполь­зуются также точки Pi-1 и Pi+2. Тогда если есть точки P0, P1, … P
n-1
и P
, то
n
первый сегмент кривой будет располагаться между точками P1 и P2, а по­следний – между точками Pn-2 и Pn-1. То есть начальной и конечной точками кривой будут P1 и P
, а не P0 и P
n-1
. Поэтому для замкнутой кривой следует
n
три точки в начале или в конце последовательности задавать дважды.
5.5.2.3 Поверхность Безье
Поверхность Безье — параметрическая поверхность, используемая в
компьютерной графике, автоматизированном проектировании, и моделиро­вании. Это одно из распространенных пространственных обобщений кривой
Безье.
При кусочном моделировании для задания и изменения формы куска, представляющего собой пространственную решетку из сплайнов или много­угольников, применяется сеть контрольных точек. Эти точки управления, также известные как контрольные вершины оказывают на гибкую поверх­ность куска подобное магнитному влияние, при котором поверхность растя­гивается в том или ином направлении. Кроме того, куски можно и дальше подразделять на элементы для достижения большего разрешения и «сши­вать» друг с другом, тем самым создавая сложные объёмные поверхности. Так же, как и сплайновые, кусочные модели используются при создании ор-
ганических форм.
Поверхность Безье порядка (n,m) задается (n + 1)* (m + 1) контроль­ными точками Pi, j. Точки поверхности рассчитываются следующей пара­метризацией:
, (5.9)
где u,v (0,1) В – многочлены Бернштейна:
(5.10)
64
Наиболее часто используются бикубические поверхности Безье
,
ij
w)u,v(
qk,ij
N
m
1j
n
1i
ij
p
ij
w)u,v(
qk,ij
N
m
1j
n
1i
ij
w)u(
k,j
N)v(
q,i
N
m
1j
n
1i
ij
p
ij
w)u(
k,j
N)v(
j,i
N
m
1j
n
1i
)v,u(r
max
vv
min
v,
max
uu
min
u
uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, XPMan, StdCtrls, ExtCtrls, OpenGL;
(n=m=3), задающиеся шестнадцатью контрольными точками.
5.5.2.4 NURBS поверхность
NURBS поверхность, как и поверхность Безье, строится на сетке вер-
шин совокупности точек рij, условно расположенных в виде п рядов по т то­чек в каждом ряду. Индексы вершины P
означают то, что данная точка рас-
i,j
положена j-й по счету в i-м ряду (первый индекс равен номеру ряда, второй — номеру точки в ряду). В данном случае нумеровать ряды удобнее от 1 до n, а точки в них - от 1 до т. Пусть все вершины р сплайны Njk(u) u-направления имеют порядок k, а В-сплайны N
равны w
i,j
. Пусть В -
i,j
(v) v-
i,q
направления имеют порядок q. Радиус-вектор NURBS поверхности опреде­ляется равенством:
(5.11)
где N
(v,u)=N
ij,qk
(v)N
i,j
(u) – базисные функции,
j,k
n – число рядов, вершин, m – число вершин в каждом ряду.
5.5.3 Ход работы
Создайте в среде программирования Delphi новый проект. Переместите в каталог с программой файлы DGLUT.dcu, DGLUT.pas.
Расположим компоненты на форме так же как представлено на рисун-
ке 5.18.
В разделе uses программы подключаем библиотеку OpenGL:
65
Рисунок 5.18 - Пример размещения компонентов на форме
private
{ Private declarations }
DC: HDC; // контекст воспроизведения hrc: HGLRC; // ссылка на контекст воспроизведения OpenGL
var Form1: TForm1; DrawingArray: array[0..64,0..2] of real; count_points: integer=0; ScreenW, ScreenH: double; //extended devX,devY: real; lineX, lineY: real; Mcoord_X: real = 0; Mcoord_Y: real =0; captured: integer= -1;
В разделе private инициализировать следующие переменные:
В разделе объявления глобальных переменных инициализировать сле-
дующие переменные:
66
Подключаем библиотеку DGLUT:
implementation uses DGLUT; {$R *.dfm}
procedure TForm1.SetDCPixelFormat; var nPixelFormat: Integer; pfd: TPixelFormatDescriptor; begin FillChar(pfd, SizeOf(pfd), 0); pfd.dwFlags:=PFD_DRAW_TO_WINDOW or
PFD_SUPPORT_OPENGL or PFD_DOUBLEBUFFER;
nPixelFormat:=ChoosePixelFormat(DC, @pfd); SetPixelFormat(DC, nPixelFormat, @pfd); end;
procedure TForm1.FormCreate(Sender: TObject); begin DC:=GetDC(Handle); SetDCPixelFormat(DC); hrc:=wglCreateContext(DC); wglMakeCurrent(canvas.Handle, hrc); glTranslated(0.0, -0.5, 0.0); SwapBuffers(Canvas.Handle);
// установка цвета очистки экрана (RGBA)
glClearColor(255, 255, 255, 1); // установка порта вывода glViewPort (0, 0, form1.ClientWidth, form1.ClientHeight); glMatrixMode(GL_PROJECTION);
// очистка матрицы
glLoadIdentity; ScreenW := form1.ClientWidth; ScreenH := form1.ClientHeight; gluOrtho2D(0.0, ScreenW, 0.0, ScreenH);
Задаем формат пиксела:
Перейдите к конструктору и сделайте двойной щелчок клавишей мыши на форме – создастся процедура обработчика события загрузки формы
FormCreate. В ней поместим следующий код:
67
// сохранение коэфицентов, которые нам необходимы для перевода
координат указателя в оконной системе, в координаты
// принятые в нашей OpenGL сцене
devX :=ScreenW / form1.ClientWidth; devY :=ScreenH / form1.ClientHeight;
// установка объектно-видовой матрицы
glMatrixMode(GL_MODELVIEW); RadioGroup1.ItemIndex:=0;
end;
procedure Draw; var N: integer; X,Y: double; eps, i, j, nn, first: integer; xA, xB, xC, xD, yA, yB, yC, yD, t: double; a0, a1, a2, a3, b0, b1, b2, b3: double; begin
// количество сегментов при расчете сплайна
N := 30; // вспомогательные переменные для расчета сплайна
// nn = count_points+1 означает, что берем все созданные контрольные
// точки + ту, которая следует за мышью, для создания интерактивно-
сти приложения
eps := 4; nn := count_points + 1; wglMakeCurrent(form1.Canvas.Handle, unit1.Form1.hrc); glEnable(GL_POINT_SMOOTH);
// очистка буфера цвета и буфера глубины
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT); glClearColor(255, 255, 255, 1);
// очищение текущей матрицы
glLoadIdentity();
// установка черного цвета
glColor3f(0, 0, 0);
// помещаем состояние матрицы в стек матриц
glPushMatrix(); {glPointSize(4.0); glBegin(GL_POINTS); glVertex2d(0, 0); glEnd(); } glPointSize(1.0);
Процедура отрисовки, вызываемая событием таймера:
68
// выполняем перемещение в пространстве по осям X и Y // выполняем цикл по контрольным точкам
for i:=0 to nn-1 do begin
// сохраняем координаты точки
X := DrawingArray[i, 0]; Y := DrawingArray[i, 1];
// если точка выделена (перетаскивается мышью) // для ее отрисовки будут использоваться более толстые линии
if i=captured then glLineWidth(3.0);
// начинаем отрисовку точки (квадрат)
glBegin(GL_LINE_LOOP); glVertex2d(X - eps, Y - eps); glVertex2d(X + eps, Y - eps); glVertex2d(X + eps, Y + eps); glVertex2d(X - eps, Y + eps); glEnd();
// если была захваченная точка - необходимо вернуть толщину линий // возвращаем прежнее значение
if i=captured then glLineWidth(1.0); end;
// начинает отрисовку кривой
glBegin(GL_LINE_STRIP); for i:=1 to nn-2 do begin
// реализация представленного в теоретическом описании алгоритма
для калькуляции сплайна
first := 1; xA := DrawingArray[i - 1, 0]; xB := DrawingArray[i, 0]; xC := DrawingArray[i + 1, 0]; xD := DrawingArray[i + 2, 0];
yA := DrawingArray[i - 1, 1]; yB := DrawingArray[i, 1]; yC := DrawingArray[i + 1, 1]; yD := DrawingArray[i + 2, 1];
a3 := (-xA + 3 * (xB - xC) + xD) / 6.0; a2 := (xA - 2 * xB + xC) / 2.0; a1 := (xC - xA) / 2.0; a0 := (xA + 4 * xB + xC) / 6.0;
69
b3 := (-yA + 3 * (yB - yC) + yD) / 6.0; b2 := (yA - 2 * yB + yC) / 2.0; b1 := (yC - yA) / 2.0; b0 := (yA + 4 * yB + yC) / 6.0;
// отрисовка сегментов
for j:=0 to N do begin
// параметр t на отрезке от 0 до 1
t := j / N; // генерация координат X := (((a3 * t + a2) * t + a1) * t + a0); Y := (((b3 * t + b2) * t + b1) * t + b0);
// и установка вершин
if first=1 then begin first:=0; glVertex2d(X, Y); end else glVertex2d(X, Y); end; end; glEnd();
// завершаем рисование
SwapBuffers(form1.Canvas.Handle); end;
procedure TForm1.Timer1Timer(Sender: TObject); begin Draw; end;
инициализации окна он будет генерировать событие, называемое тиком тай-
мера, раз в 30 миллисекунд – добавьте элемент таймер и установите время тика 30 миллисекунд (рисунок 5.19), а так же добавьте ему событие для об­работки тика.
Для реализации визуализации будет использоваться таймер – после
Обработка события Timer:
70
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]