Opengl как нарисовать чайник

от admin

Opengl как нарисовать чайник

ФУНКЦИЯ GLUT ИЗОБРАЖЕНИЯ ЧАЙНИКА С ПОМОЩЬЮ КУБИЧЕСКИХ ПОВЕРХНОСТЕЙ

На заре развития методов компьютерной графики для описания нескольких трехмерных объектов были построены наборы данных (представления через многоугольные сетки), которые затем можно было использовать для проверки методов визуализации. Такие объекты включали поверхности автомобиля “Фольксваген” и чайник, разработанный в Университете штата Юта (США). Набор данных для чайника, построенного Мартином Ньюэллом (Martin Newell) в 1975 году, содержал 306 вершин, определяющих 32 бикубических участка поверхности Безье (раздел 8.11). Поскольку определение координат точек сложной поверхности является длительным процессом, эти наборы данных, особенно чайник в виде поверхностной сетки, стали широко использоваться.

Чтобы отобразить чайник в виде сетки из более тысячи бикубических участков поверхности, используется одна из следующих двух функций GLUT:

glutWireTeapot (size); ИЛИ

glutSolidTeapot (size); Поверхность чайника генерируется с использованием функций OpenGL построения кривых Безье (раздел 8.11). Параметр size устанавливает значение двойной точности с плавающей запятой — максимальный радиус тела чайника. Чайник центрирован в начале внешней системы координат, а его вертикальная ось идет вдоль оси у.

ФУНКЦИИ GLU ПОВЕРХНОСТЕЙ ВТОРОГО ПОРЯДКА

Чтобы сгенерировать поверхность второго порядка с использованием функций GLU, нужно присвоить имя квадрике, активизировать процедуру визуализации поверхностей второго порядка GLU, а также задать значения параметров поверхности. Кроме того, можно указать значения других параметров, чтобы контролировать внешний вид поверхности второго порядка GLU.

Приведенные ниже операторы иллюстрируют стандартную последовательность вызовов для отображения каркасной сферы с центром в начале внешней системы координат.

GLUquadricObj *spherel; spherel = gluNewQuadric ( ); gluQuadricDrawStyle (spherel, GLU_LINE); gluSphere (spherel, r, nLongitudes, nLatitudes); Название объекта второго порядка определяется в первом операторе, и в данном примере выбрано имя spherel. Затем это имя можно использовать в других функциях GLU для обращения к этой конкретной поверхности второго порядка. Затем с помощью функции gluNewQuadric активизируется процедура визуализации поверхностей второго порядка, после чего с помощью команды gluQuadricDrawStyle для поверхности spherel выбирается режим отображения GLU_LINE. Таким образом, сфера выводится на экран в каркасной форме с отрезками между каждой парой вершин поверхности. Параметру г присваивается значение двойной точности (радиус сферы), и сферическая поверхность делится на набор многоугольных граней с помощью равномерно размещенных линий широты и долготы. Целое число линий долготы и широты задается в виде значений параметров nLongitudes и nLatitudes.

Для отображения поверхностей GLU второго порядка доступны три других режима отображения. Если использовать символьную константу GLU_POINT как аргумент функции gluQuadricDrawStyle, поверхность второго порядка отобразится в виде точечного графика. В каждой вершине поверхности, сформированной пересечением линии широты и линии долготы, ставится точка. Другой вариант — использовать символьную константу GLU_SILHOUETTE. В результате получится каркасное изображение с общими краями между двумя компланарными многоугольными гранями. Наконец, при использовании символьной константы GLU_FILL многоугольные участки отображаются как затененные закрашенные области.

RedBook_OpenGL

Имейте в виду , что вы в любом случае должны согласовывать коэффициент итеративного ослабления и число шагов сдвига . Например , если коэффициент мал , а число шагов велико , то к последней итерации след от первой итерации может быть невидим на экране ( поскольку будет слишком ослаблен ). Если же коэффициент велик ( близок к 1.0), а число шагов небольшое – разница между изображением первой и последней итераций может быть настолько мала , что невозможно будет понять , где начало движения , а где его конец .

Рисунок 10-3. Размытое движение

Пример 10-5. Размытие движения с помощью буфера аккумулятора : файл motiblur.cpp

#define SPHERE_FACES 64

//Горизонтальный размер проекции

#define PROJ_SIZE 8

//Количество шагов сдвига/поворота

#define TIME_JITTER_STEPS 10

//Угол на который за время сдвигов //должна повернуться модель

#define FULL_ROT 0

//Фактор сжатия модели

#define SCALE_FACTOR 1.0

glMaterialfv(GL_FRONT,GL_AMBIENT,mat_ambient); glMaterialfv(GL_FRONT,GL_SPECULAR,mat_specular); glMaterialf(GL_FRONT,GL_SHININESS,50.0); glLightfv(GL_LIGHT0,GL_POSITION,light_position); glLightModelfv(GL_LIGHT_MODEL_AMBIENT,lm_ambient);

glEnable(GL_RESCALE_NORMAL); glEnable(GL_DEPTH_TEST); glShadeModel(GL_SMOOTH);

void displayObjects(GLfloat xoffset,GLfloat yrot)

GLfloat torus1_diffuse[]=<1.0,0.0,0.0,1.0>; GLfloat torus2_diffuse[]=<1.0,0.7,0.7,1.0>; GLfloat sphere_diffuse[]=<1.0,1.0,1.0,1.0>;

glRotatef(yrot,0.0,1.0,0.0); glScalef(SCALE_FACTOR,SCALE_FACTOR,SCALE_FACTOR); glMaterialfv(GL_FRONT,GL_DIFFUSE,torus1_diffuse); glutSolidTorus(0.3,0.55,SPHERE_FACES,SPHERE_FACES); glMaterialfv(GL_FRONT,GL_DIFFUSE,torus2_diffuse); glutSolidTorus(0.35,0.45,SPHERE_FACES,SPHERE_FACES); glMaterialfv(GL_FRONT,GL_DIFFUSE,sphere_diffuse); glutSolidSphere(0.4,SPHERE_FACES,SPHERE_FACES);

GLfloat correctedProjSize=PROJ_SIZE-3; int step;

GLfloat oneStepTrans=correctedProjSize/TIME_JITTER_STEPS; GLfloat oneStepRot=FULL_ROT/TIME_JITTER_STEPS;

void reshape(int w,int h)

int main (int argc, char **argv)

glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB|GLUT_DEPTH|GLUT_ACCUM); glutInitWindowSize(620,620); glutInitWindowPosition(100,100);

glutCreateWindow(«Motion blur with Accumulator»); init();

glutMainLoop(); return 0;

10.3.3 Глубина поля

Фотографии , сделанные с помощью камеры , имеют превосходный фокус только для объектов , лежащих в одной плоскости параллельной фотопленке на определенном расстоянии . Чем дальше объект от этой плоскости , тем более он размыт . Глубина поля для камеры – это область вокруг плоскости фокуса , где объекты сравнительно слабо выпадают из фокуса .

При обычных условиях , все , что вы рисуете с помощью OpenGL, находится в фокусе ( если только у вас хороший монитор – в противном случае абсолютно все выглядит размытым ). Буфер аккумуляции может быть использован для приближения к виду реальной фотографии , где объекты выглядят все более и более размытыми по мере удаления от плоскости фокуса . Это ( как и во многих других случаях ) не точная имитация того , что происходит внутри камеры , но результат похож на тот , который получается при помощи камеры .

Чтобы достигнуть этого результата , нарисуйте сцену несколько раз , вызывая glFrustum() с разными аргументами . Выбирайте аргументы таким образом , чтобы точка наблюдения перемещалась ( на незначительное расстояние ) вокруг своей оригинальной позиции , и , чтобы прямоугольник , лежащий в плоскости фокуса , был одинаковым для всех проекций ( как показано на рисунке 10-4). Результаты всех

визуализаций должны быть усреднены обычным путем с помощью буфера аккумуляции .

Рисунок 10-4. Перемещение объема видимости для эффекта глубины поля

На рисунке 10-5 изображено 5 чайников , нарисованных с применением эффекта глубины поля . Золотой чайник ( второй слева ) находится в фокусе , а остальные

размываются в разной степени в зависимости от дистанции до плоскости фокуса ( золотого чайника ). Код , используемый для рисования этого изображения , приводится в примере 10-6. Сцена рисуется 8 раз , каждый раз со слегка сдвинутым объемом видимости ( сдвиг осуществляется с помощью функции accPerspective() ). Как вы можете помнить , из метода сглаживании сцены , 5- ый и 6- ой аргументы сдвигают объем видимости в направлениях x и y соответственно . Однако для эффекта глубины поля нам нужно сдвигать объем видимости таким образом , чтобы он оставался на плоскости фокуса . Плоскость фокуса – это величина глубины , определяемая 9- ым ( последним ) аргументом accPerspective() ( например z =5.0). Количество размытия определяется умножением величин сдвига по x и y (7- го и 8- го аргументов ) на константу . Определение такой константы не представляет сложности – экспериментируйте с ней до тех пор , пока изображение не будет иметь тот вид , который вам нужен . ( Обратите внимание на то , что в примере 10-6 4- ый и 5- ый аргументы accPerspective() установлены в 0.0. Таким образом , сглаживание сцены не производится .)

Рисунок 10-5. Чайники с эффектом глубины поля

Пример 10-6. Эффект глубины поля : файл dof.cpp

#include <glut.h> #include «jitter.h»

#define ACSIZE 8 #define JIT j8

glLightfv(GL_LIGHT0,GL_AMBIENT,ambient); glLightfv(GL_LIGHT0,GL_DIFFUSE,diffuse); glLightfv(GL_LIGHT0,GL_POSITION,position);

glFrontFace(GL_CW); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0);

glEnable(GL_AUTO_NORMAL); glEnable(GL_NORMALIZE); glEnable(GL_DEPTH_TEST);

teapotList=glGenLists(1); glNewList(teapotList,GL_COMPILE); glutSolidTeapot(0.5); glEndList();

void renderTeapot(GLfloat x,GLfloat y,GLfloat z,

GLfloat ambr,GLfloat ambg,GLfloat ambb, GLfloat difr,GLfloat difg,GLfloat difb, GLfloat specr,GLfloat specg,GLfloat specb, GLfloat shine)

mat[0]=ambr;mat[1]=ambg;mat[2]=ambb;mat[3]=1.0; glMaterialfv(GL_FRONT,GL_AMBIENT,mat); mat[0]=difr;mat[1]=difg;mat[2]=difb; glMaterialfv(GL_FRONT,GL_DIFFUSE,mat); mat[0]=specr;mat[1]=specg;mat[2]=specb; glMaterialfv(GL_FRONT,GL_SPECULAR,mat); glMaterialf(GL_FRONT,GL_SHININESS,shine); glCallList(teapotList);

GLint viewport[4]; int jitter;

//Рубиновый, золотой, серебряный, изумрудный и голубой

renderTeapot(-1.1,-0.5,-4.5, 0.1745,0.01175,0.01175, 0.61424,0.04136,0.04136, 0.727811,0.626959,0.626959, 0.6);

renderTeapot(-0.5,-0.5,-5.0, 0.24725,0.1995,0.0745, 0.75164,0.60648,0.22648, 0.628281,0.555802,0.366065,

0.25); glAccum(GL_ACCUM,0.125); glPopMatrix();

void reshape(int w,int h)

int main(int argc, char **argv)

glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB|GLUT_DEPTH|GLUT_ACCUM); glutInitWindowSize(620,620); glutInitWindowPosition(100,100); glutCreateWindow(«Depth-of-Field Effect»);

glutMainLoop(); return 0;

10.3.4 Мягкие тени

Чтобы аккумулировать мягкие тени , получающиеся от нескольких источников света , визуализируйте их с одним включенным источником за раз и аккумулируйте вместе .

Читать:
Сколько полигонов в современных играх

Этот процесс можно комбинировать с пространственным сдвигом для одновременного сглаживания сцены .

Если вам нужно снять 9 или 16 кадров для сглаживания изображения , вы возможно решите , что лучшие решение – это взять точки , распределенные по пикселю с равными промежутками . Удивительно , но это не обязательно так . По правде говоря , иногда является хорошей идеей взять точки на соседних пикселях . Иногда вам потребуется равномерное распределение точек , а иногда – нормальное , уплотняющееся вблизи центра пикселя . Кроме того , в таблице 10-5 приводится несколько наборов разумных величин сдвига , которые могут использоваться в некоторых случаях . Все величины в этой таблице лежат внутри пикселя , а большинство из них еще и равномерно распределены .

Таблица 10-5. Примеры величин сдвига

3 [0.5033922635,0.8317967229],[0.7806016275,0.2504380877], [0.2261828938,0.4131553612]

6 [0.4646464646,0.4646464646],[0.1313131313,0.7979797979], [0.5353535353,0.8686868686], [0.8686868686,0.5353535353], [0.7979797979,0.1313131313],[0.2020202020,0.2020202020]

8 [0.5625,0.4375],[0.0625,0.9375],[0.3125,0.6875],[0.6875,0.8125], [0.8125,0.1875], [0.9375,0.5625],[0.4275,0.0625],[0.1875,0.3125]

9 [0.1666666666,0.2777777777],[0.8333333333,0.3888888888], [0.1666666666,0.6111111111], [0.8333333333,0.7222222222], [0.8333333333,0.0555555555]

12 [0.0833333333,0.125], [0.75,0.625],[0.25,0.875],[0.5833333333,0.375], [0.9166666666,0.375], [0.0833333333,0.625],[0.5833333333,0.875]

16 [0.625,0.5625],[0.375,0.9375], [0.625,0.3125],[0.125,0.5625],[0.125,0.8125],[0.375,0.1875], [0.875,0.9375],[0.875,0.6875],[0.125,0.3125],[0.625,0.8125]

Глава 11. Тесселяция и квадрические поверхности

Библиотека OpenGL (GL) разработана для низкоуровневых операций , одновременно являющихся конвейерными и имеющими доступ к аппаратному ускорению . Библиотека утилит OpenGL (GLU) дополняет OpenGL, предоставляя высокоуровневые операции . Некоторые из операций GLU ( такие как мипмаппинг функцией gluBuild*DMipmaps() , масштабирование изображений функцией gluScaleImage() , операции матричных преобразований функциями gluOrtho2D() , gluPerspective() , gluLookAt() , gluProject() , gluUnProject() и gluUnProject4() ) рассматриваются в других главах .

Некоторые будут рассмотрены далее .

Для оптимизации быстродействия , ядро OpenGL визуализирует только выпуклые полигоны , однако GLU содержит функции для тесселяции ( разбиения ) вогнутых полигонов на выпуклые , которые могут обрабатываться OpenGL. Там , где OpenGL оперирует простыми примитивами , такими как точки , линии и закрашенные полигоны , GLU может создавать объекты более высокого уровня , такие , как поверхности сфер , цилиндры или конусы .

11.1 Тесселяция полигонов

OpenGL может непосредственно отображать только простые выпуклые полигоны . Полигон является простым , если его ребра пересекаются только в вершинах , если в каждой точке находится только одна вершина , и в каждой вершине соединяются только два ребра . Если вашему приложению требуется отображение вогнутых полигонов , полигонов с дырами или полигонов с пересекающимися ребрами , такие полигоны должны быть предварительно разделены на простые выпуклые полигоны до того , как

их можно будет отобразить . Такое разбиение называется тесселяцией , и GLU предоставляет ряд функций для осуществления тесселяции . Эти функции принимают информацию о контурах , описывающих трудный для отображения полигон , в качестве аргумента и возвращают комбинацию треугольников , фигур из треугольников , треугольных вееров или линий .

На рисунке 11-1 показаны контуры нескольких полигонов , нуждающихся в тесселяции : слева – направо показаны вогнутый полигон , полигон с дырой и полигон с пересекающимися ребрами .

Рисунок 11-1. Контуры , нуждающиеся в тесселяции

Если вы считаете , что полигон нуждается в тесселяции , выполните следующие шаги :

1. Создайте новый объект тесселяции с помощью функции gluNewTess() .

2. Несколько раз используйте gluTessCallback() для регистрации функций обратного вызова , производящих операции во время тесселяции . Самый сложный случай при работе с возвратно — вызываемыми функция возникает , когда алгоритм тесселяции обнаруживает пересечение и должен вызвать функцию , зарегистрированную для события GLU_TESS_COMBINE.

3. Задайте свойства тесселяции с помощью функции gluTessProperty() . Наиболее важным свойством является правило оборота , определяющее какие регионы должны быть закрашены , а какие – остаться незакрашенными .

4. Создайте и визуализируйте тесселированные полигоны , задав контуры одного или более закрытых полигонов . Если данные объекта являются статическими , инкапсулируйте тесселированные полигоны в списке отображения . ( Если вам не нужно пересчитывать тесселяцию снова и снова , использование списков отображения более эффективно .)

5. Если вам требуется тесселировать что — либо еще , вы можете использовать существующий объект тесселяции . Если вы закончили с тесселяцией , вы можете удалить объект функцией gluDeleteTess() .

Замечание: Тесселяция, описанная здесь, появилась в GLU версии 1.2. Если у вас более старая версия GLU, вы должны использовать функции, описанные в разделе «Описание ошибок GLU». Чтобы запросить версию используемой GLU, используйте функцию gluGetString(GLU_VERSION), которая возвращает строку с номером версии GLU. Если в вашей GLU нет функции gluGetString(), значит это GLU версии 1.0 – в этой версии такая функция отсутствует.

11.1.1 Создание объекта тесселяции

Во время описания и тесселяции сложного полигона с ним ассоциируются некоторые данные , например , вершины , ребра и функции обратного вызова . Для выполнения тесселяции , ваша программа сначала должна создать объект тесселяции с помощью функции gluNewTess() .

GLUtesselator* gluNewTess (void);

Создает новый объект тесселяции и возвращает указатель на него . Если создать объект не удается , возвращается нулевой указатель .

Для всех тесселяций может использоваться один и тот же объект . Сам объект необходим исключительно потому , что функциям библиотеки могут потребоваться собственные тесселяции , и они должны иметь возможность выполнять их , не вмешиваясь в какие — либо тесселяции , выполняемые вашей программой . Несколько объектов полезно иметь также и в случае , если вы используете разные наборы возвратно вызываемых функций для разных тесселяций . Однако типичная программа создает только один объект и использует его для всех тесселяций . Освобождать объект , в общем — то , не имеет смысла , так как он требует очень небольшого объема памяти . С другой стороны , аккуратность еще никому не вредила .

11.1.2 Возвратно-вызываемые функции тесселяции

После того , как вы создали объект тесселяции , вы должны предоставить серию возвратно — вызываемых функций , которые будут вызываться в определенные моменты во время тесселяции . После определения этих функций , вы задаете контуры одного или нескольких полигонов с использованием функций GLU. После передачи описания контуров , механизм тесселяции вызывает ваши функции по необходимости .

Любые опущенные возвратно — вызываемые функции просто не вызываются в процессе тесселяции , и любая информация , которую они могут возвращать в вашу программу будет потеряна . Все возвратные функции задаются с помощью gluTessCallback() .

void gluTessCallback (GLUtesselator * tessobj , GLenum type , void (* fn )());

Ассоциирует возвратно — вызываемую функцию fn с объектом тесселяции tessobj . Тип возвратной функции определяется аргументом type , который может быть равен

GLU_TESS_BEGIN, GLU_TESS_BEGIN_DATA, GLU_TESS_EDGE_FLAG, GLU_TESS_EDGE_FLAG_DATA, GLU_TESS_VERTEX, GLU_TESS_VERTEX_DATA, GLU_TESS_END, GLU_TESS_END_DATA, GLU_TESS_COMBINE, GLU_TESS_COMBINE_DATA, GLU_TESS_ERROR или GLU_TESS_ERROR_DATA. 12

C# + OpenGL — работа с материалами

В графическом программирование материалы занимают достаточно важную роль. Материал может рассеивать, отражать и излучать свет.

Свойства материала можно изменять при помощи специальной функции:

Первый параметр определяет грань, для которой устанавливаются свойства. Он может принимать одно из следующих значений:

Второй параметр определяет свойство материала, которое будет установлено, и может принимать следующие значения:

Чтобы создать эффект металлической поверхности, нужно увеличить параметр Gl.GL_SHININESS.

Третий параметр определяет цвет в виде массива. В случае Gl.GL_SHININESS указывает на число типа float, которое должно быть в диапазоне от 0 до 128.

Изобразим чайник красного цвета, отражающий свет:

Наш чайник готов.

Рисунок 1. Чайник с заданными параметрами и свойствами.

Cocoa и чайник OpenGL не нарисованы правильно

Я смешал рамки cocoa, GLUT и OpenGL, чтобы нарисовать чайник.
Обычно я делаю это на простом C, но мне нужно перепутать кнопки Cocoa и продукты с OpenGL, это коричественный код C:

И это результат:

enter image description here

Затем я подклассифицирую NSOpenGLView и делаю то же самое из этого кода на C, просто с разными размерами, но счетчики и огни одинаковы:

И это результат:

enter image description here

Это довольно уродливо и, учитывая, что я использовал те же самые показатели и огни, я думаю, что я делаю что-то неправильно в том, что сделано с Cocoa и OpenGL.

Похожие статьи