Добавил:
ivanov666
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз:
Предмет:
Файл:Системы автоматизированного проектирования. Моделирование в машиностроении. Учебное пособие
.pdf
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
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]
