OpenGL. Руководство по программированию (Библиотека программиста) (2006). Ву М., Девис Т., Нейдер Дж., Шрайнер Д (1124475), страница 21
Текст из файла (страница 21)
Также при разбиении используйте большие многоугольники там, где поверхность практически ровная, и маленькие— в областях с большой кривизной. ° Для высококачественных изображений нужно более детальное разбиение на границах, чем внутри. Если поверхность поворачивается относительно глаза, границы тоже меняются. Границы появляются, когда векторы нормали перпендикулярны к вектору, направленному от поверхности к точке обзора.
Это означает, что их вектор — нулевой. Алгоритм разбиения может выполнить дополнительное разбиение, если вектор в этой точке стремится к нулю. 90 Глава 2 ь Управление состоянием и рисование геометрических объектов ° Старайтесь избегать т-образных пересечений в моделях (рис. 2.16). Как видно из рисунка, нет гарантии, что отрезки АВ и ВС рисуются теми же пикселами, что и отрезок АС. Иногда это происходит, иногда нет; в зависимости от преобразований и положения это может привести к периодическому появлению разрывов на поверхности.
Неподходящее Нормальное Рнс. 2.16. Нежелательные Т-образные пересечения ° При построении замкнутой поверхности убедитесь, что используете однако вые числа для координат начала и конца контура, иначе на поверхности воз никнут разрывы из-за ошибок округления. Ниже приведен пример непра вильного кода для рисования двухмерной окружности: /* Не используйте этот кол '/ №Оет(пе Р1 3.14159265 №г)ет1пе Е06Е5 3 В /* рисуем окружность '/ а1веа!п(6( Е1МЕ 5ТР1Р); Рог (з = В; 1 <= Е06Е5; !.ьь) Х(уегтех2((соз((2*Р1'))/Е06Е5), з(п((2*Р1'))/Е06Е5)); а(Епе(); Ребра сомкнутся, только если компьютер в силах вычислить одинаковое зна четше для синуса и косинуса нуля и значения (2'Р1*Е06Е5/Е06Е5).
При все доверии к вычислениям с плавающей запятой, авторы желают вам только луч щего... Для исправления этого кода нужно при г - Е()СЕЯ подставить для си нуса и косинуса значение О, а не 2'Р1*Е06Е5/ЕООЕ5. (Или просто можно ис пользовать 6Е Е1МЕ ЕООР, а не 6Е 11МЕ 5ТМ1Р, и прерывать цикл по услови т < Е06Е5.) Пример: построение икосаэдра с1тобея проиллюстрировать некоторые из изложенных выше советов по аппро симации поверхностей, рассмотрим код рисования икосаэдра.
Икосаэдр, будуч Платоновым телом из 20 треугольных граней и 12 вершин, является хороше приблизительной аппроксимацией сферы. Программа из листинга 2.16 определяет вершины и треугольники, составляющи икосаэдр, а затем его рисует. Несколько советов по построению полигональных моделей поверхностей 91 Листинг 2.16. Рисование икосаэдра Воет(пе Х .525731112119133696 Вает(пе 2 .850650808352039932 зтзс!с 6ьт]оат чаата[12)[Э] (-Х, 0.0, 2», (Х, 9.0, 2), (-Х, О.О, -2), (О.В, 2, Х), (О.О, 2, -Х», (О.О, -2, Х», (2, Х, 0.9», (-2, Х, 0.0), (2, -Х, 0.0), )' зтат(с 6ьц(п1 11пачсез[20] [3] = ( (1,4,0), (4,9,0), (4,5,9», (8,5,4), (1,8,4», (1,10,8), (10,3,8), (8,3,5), (3,2,5), (Э,7,2», (Э,10,7), (10,6,7), (6,11,7), (6,0,11), (6,1,0], (10,1,6), (11,0,9), (2,11,9), (5,2,9), (11,2,7] (Х, 8.0, -2».
(0.0, -2, -Х», (-2, -Х. 0.9) !пт [; 818ей(п(66 тя1Ан6665); Гог (! = 9; ! < 20; (н-) ( /* информация о цвете должна быть здесь */ 8]уег!ехэтч(йчаата[С(па!сев[(][О]][0]); 81чегтехЭ(ч(йчбата [ 1! пе! сев [! ] [ 1] ] [9] ): 8]уегтехэтч (йчбата [1! па! сев [! 1 [2] 1 [9] ); 8!Ело(); Странные числа Х и 2 были выбраны таким образом, чтобы расстояние от начала координат до любой вершины составляло 1,0.
Координаты всех 12 вершин определены в массиве одЫа[~ Ц, причем нулевая вершина — ( — Х, 0.0, Х), первая — (Х, 0.0, У) и т. д. Массив 1[лг[(сезЦ Ц определяет, как вершины связываются в треугольники. Например, первый треугольник состоит из нулевой, четвертой и первой вершин. Нри указании вершин в приведенном порядке все треугольники приобретут одинаковую ориентацию.
Строку с информацией о цвете следует заменить командой, определяющей цвет !-й грани. Если на ато место не вставить никакого кода, все грани будут нарисованы одним цветом и нельзя будет разглядеть трехмерный объект. Альтернативой определения цвета для каждой грани является определение векторов нормалей и использование освещения, как описано в следующем разделе. Вычисление векторов нормали к поверхности Если поверхность освещена, необходимо определить вектор нормали к поверх- ности. Вычисление нормализованного векторного произведения двух векторов ПРИМЕЧАНИЕ Во всех примерах, приведенных в этом разделе, нужно сохранять вычисленные значения вершин и нормалей до тех пор, пока поверхность не нарисована, так как эти вычисления не нужно выполнять при каждом рисовании поверхности. Для сохранения подойдут как собственные структуры данных, так и списки отображения (см.
главу 7). 92 Глава 2 ° Управление состоянием и рисование геометрических объектов к поверхности дает вектор нормали. На плоской поверхности икосаэдра все три вершины, определяющие поверхность, имеют одинаковые векторы нормалей. В зтом случае достаточно вычислить одну нормаль для каждого набора из трех вершин, Код в листинге 2.17 может заменить строку «информация о цветес.е в листинге 2.16. Листинг 2.17.
Определение векторов нормали к поверхности 0СГ1овС б1(3], б2[3], поги(З], Го. Ц = В; 1 < 3; )++) ( б1[1] = чс[аса[стпбтсев(т][в]][]] — хоота[стоб[сев(!][ ц ][1]; б2[)] = чбвса [ с!пб[сев [(] [ Ц ] [1] — чбата[Стпб[сев[]][2]][1]; поте<Гевар<об(б1, б2, посв); а1иогва13[ч(поте); Процедура погмсгоезргоб() вычисляет нормализованное векторное произведе- ние двух векторов, как показано в листинге 2.18.
Листинг 2.18. Вычисление нормализованного векторного произведения двух векторов чо[б погва1!се(Г[оаС ч(3]) ( аСГ]овС б = вйгС(ч [О] "ч [0] -ч(ц *ч [ц+ч [2]*ч [2] ): (б == 0.0) ( еггог("вектор нулевой дпнны")! гесогп; ч(0) /= б; ч[ Ц /= б; ч(2] /= б; ) чотб погвсговвргоб( [1овС ч1[3\, (1оаС ч1(3], г1оаС ооС (3]) ( оиС[0] =ч1[ц'ч1[2] — ч[(2] "чс(ц; ой! [ц =ч1(2] 'ч2 [О] — чс[0] 'ч2 [2]; бог [2) =ч1(0] *ч2 (ц — ч1[ц *ч2 [О]; погав1тсе(ооС); Если икосаздр используется для аппроксимации закрашенной сферы, вы можете захотеть определить векторы нормалей, перпендикулярные к истинной поверхности сферы, а не к граням.
Для сферы получение векторов нормалей делается просто: по любой точке в направлении от центра к соответствующей вершине. Так как информация о вершинах определена для икосаздра с единичным радиусом, векторы нормалей такие же. В следующем коде сглаженная затененная сфера аппроксимируется икосаэдром (полагаем, что освещение включено, как описано в главе 5): а[Вез!о(0С та[аис[ЕЗ): Гог (! = О; ! < 2О; !++) ( а1иогвэ[ЗГч(ахов!а[Стоб[сев(т][0]](В]); асуегеехЗ(ч(ачбвСв[Стпбтсев( ц [0]][9]); Несколько советов по построению полигонапьных моделей поверхностей 93 В(иогва13(ч(йчдаСа[1(пд!сея[!][1]][О]): В]чеггехЗ(ч(йчдага[1!пд!сея[(][1]][0]): В(ногае(3(ч(йчдага[1!пд(сея[(] 12]][О]); Е1чеггехЗ(ч(йчдага[ 1!пд(сея[(][2]][0]); ] 31Епд() ', Повышение качества модели Двадпатигранная аппроксимация сферы не выглядит хорошо, поэтому обратимся к простому способу увеличения точности аппроксимации.
Представьте икосаэдр вписанным в сферу и разделенным на треугольники, как показано на рис. 2.17. Поместим на поверхность новые вершины путем нормализации (разделим их на коэффициент для получения единичной длины). Этот процесс разбиения повторяется до достижения необходимой точности. Три объекта на рис. 2.17 состоят из 20, 80 и 820 аппроксимирующих треугольников. -.163...
Рис. 2.17. Разукрупненне с целью улучшения полнгональной аппроксимации поверхности Листинг 2.19 демонстрирует получение из 20-гранного икосаздра 80-грашюй поверхности. Листинг 2.19. Разбиение граней на треугольники чо(д дгангг!апх1е((1оаг 'ч1, Моет *чг, (1еаг *чЗ) ( 61аек!п(66 та[ЯМ6ЕЕ5); 61ногва13(ч(ч1); 61уеггехЗ(ч(ч1); 61Могва13(ч(чг); 61НеггехЗ(ч(чг).
61ногва13 Гч(ч3); К1НеггехЗ(ч(чЗ); В1Епд(); ) ЧЕ1О ьцьд!ч!де((1оа[ *ч1, (1оаг 'ч2, (1оа1 'чЗ) ( 6Е(1оат ч12[3], ч23[3], ч)1[3]; 66!пг (; Гог (! =О; ! < 3; (в+) ( ч12[!1 = (ч1[!]+ч2[(])/г.о; ч23[з1 = (ч2[!]вч)[(])/2,0; продолжение ег 94 Глава 2 ч Управление состоянием и рисование геометрических объектов Листинг 2.19 (продолжение) ч31[[] = (чЗ[[]+ч1[[])/2.0; погва[[се(ч12); погва[[се(ч23); погва[ссе(ч31); бгаитг]апа[е(ч1, ч12, ч31); бгаи(г]апк1е(ч2, ч23, ч12): бгаи(г[апк[е(чЗ, ч31, ч23); бгаи(г]апя[е(ч12, ч23, ч31); аког (! = 0; ! < 20: [++) ( ацьб[ч[бе(ачбаса[с!пб[сеа[[][0]][0], ачбата[С[пб]се![]][1]][0), ачбата[С[по]се»[]][2]][0]): ) Теперь выполним рекурсивное разбиение треугольников до требуемой точности.
Для чего в листинг 2.19 внесем небольшие изменения, и зто будет уже листинг 2.20. Если значение «глубины» (вложенности) равно О, разбиение не выполняется и треугольники рисуются «как есть». Если глубина равна 1, разбиение выполняется один раз и т. д. Листинг 2.20. Рекурсивное разбиение чо!б аоьб[ч]бе(тсоаС «чс, Ссра( *ч2, С[оаС чЗ, [опа берСП) ( ОСЕ[па! ч12[3], ч23[3], ч31[3]; ОС]пС ]; !! (берСП == 0) ( бгаи[г]эпе[е(ч1, ч2, чЗ); гесогп; сог (! = 0; !' < 3; ! н.) ( ч12[!] = (ч1[[]+ч2[]])(2 0; ч23[з] = (ч2[[]+чЗ[!])/2,0; ч31[[] = (чЗ[]]+ч1[!])/2.8; погва[[се(ч12); погва1[се(ч23): погвас]се(ч31); »ЬЬб[ч[бе(ч1, ч12, ч31, берто-1); »оЬб[ч[бе(ч2, ч23, ч12, берСП-1); аоьб[ч[бе(чЗ, ч31, ч23, берСП-1); ацьб!ч]бе(ч12, ч23, ч31, берта-1); Обобщенное разбиение Рассмотренная технология рекурсивного разбиения пригодится и для других ви дов поверхностей. Обычно рекурсия прекращается, если достигается заданн Несколько советов по попроенню полнгональных моделей поверхностей 95 глубина или выполняется некоторое условие на кривизну (сильно искривленные части поверхности выглядят лучше при большом разбиении).