где a, b – параметры отрезка
glBegin(GL_LINES);
glVertex3f(bFan+2,15,0);
glVertex3f(bFan,rFan,0);
glEnd();
1.
Винт
Винт вентилятора
составлен из трех основных частей
§
Лопасть
вентилятора
|
|
где bFan
– половина ширины лопасти в основании, lFan – длина лопасти, N – разбиение лопасти
|
Фрагмент
кода программы лопасти вентилятора
double bFan=5;
double lFan=15;
glBindTexture(GL_TEXTURE_2D,texture4);
float N=30;
float NNN=100;
int i=0;
while(i<N)
{
glBegin(GL_QUADS);
glTexCoord2d(i/N,0);
glNormal3f(-2*lFan*bFan*i/(N*N)*sin(i*M_PI/(1.5*N)),
2*bFan*bFan/(N*log(NNN))*(log(i+26)*i*sin(i*M_PI/(1.5*N))-log(i+25)*(i+1)*sin((i+1)*M_PI/(1.5*N))),
2*bFan*lFan*log(i+25)/(N*log(NNN)));
glVertex3f(-bFan*log(i+25)/log(NNN),lFan*i/N,-bFan*(i)/N*sin(i*M_PI/(N*1.5)));
glTexCoord2d(i/N,1);
glNormal3f(-2*lFan*bFan*i/(N*N)*sin(i*M_PI/(1.5*N)),
2*bFan*bFan/(N*log(NNN))*(log(i+26)*i*sin(i*M_PI/(1.5*N))-log(i+25)*(i+1)*sin((i+1)*M_PI/(1.5*N))),2*bFan*lFan*log(i+25)/(N*log(NNN)));
glVertex3f(bFan*log(i+25)/log(NNN),lFan*i/N,bFan*(i)/N*sin(i*M_PI/(N*1.5)));
glTexCoord2d((i+1.0)/N,1);
glNormal3f(-2*lFan*bFan*i/(N*N)*sin(i*M_PI/(1.5*N)),
2*bFan*bFan/(N*log(NNN))*(log(i+26)*i*sin(i*M_PI/(1.5*N))-log(i+25)*(i+1)*sin((i+1)*M_PI/(1.5*N))),2*bFan*lFan*log(i+25)/(N*log(NNN)));
glVertex3f(bFan*log((i+26))/log(NNN),lFan*(i+1)/N,bFan*(i+1)/N*sin((i+1)*M_PI/(N*1.5)));
glTexCoord2d((i+1.0)/N,0);
glNormal3f(-2*lFan*bFan*i/(N*N)*sin(i*M_PI/(1.5*N)),
2*bFan*bFan/(N*log(NNN))*(log(i+26)*i*sin(i*M_PI/(1.5*N))-log(i+25)*(i+1)*sin((i+1)*M_PI/(1.5*N))),2*bFan*lFan*log(i+25)/(N*log(NNN)));
glVertex3f(-bFan*log((i+26))/log(NNN),lFan*(i+1)/N,
*(i+1)/N*sin((i+1)*M_PI/(N*1.5)));
glEnd();
i++;
}
§
Цилиндр,
объединяющий лопасти вентилятора в винт
|
|
где M –
разбиение цилиндра
|
Фрагмент
кода программы цилиндра, объединяющего лопасти вентилятора в винт
M=30;
int qRoll=0;
glBindTexture(GL_TEXTURE_2D,texture2);
while (qRoll<M)
{
glBegin(GL_QUADS);
glTexCoord2d(0,qRoll/M);
glNormal3f(0,sin((2*M_PI*qRoll)/M),cos((2*M_PI*qRoll)/M));
glVertex3f(-1,sin((2*M_PI*qRoll)/M),cos((2*M_PI*qRoll)/M));
glTexCoord2d(0,(qRoll+1.0)/M);
glNormal3f(0,sin((2*M_PI*(qRoll+1))/M),cos((2*M_PI*(qRoll+1))/M));
glVertex3f(-1,sin((2*M_PI*(qRoll+1))/M),cos((2*M_PI*(qRoll+1))/M));
glTexCoord2d(1,(qRoll+1.0)/M);
glNormal3f(0,sin((2*M_PI*(qRoll+1))/M),cos((2*M_PI*(qRoll+1))/M));
glVertex3f(1,sin((2*M_PI*(qRoll+1))/M),cos((2*M_PI*(qRoll+1))/M));
glTexCoord2d(1,qRoll/M);
glNormal3f(0,sin((2*M_PI*qRoll)/M),cos((2*M_PI*qRoll)/M));
glVertex3f(1,sin((2*M_PI*qRoll)/M),cos((2*M_PI*qRoll)/M));
glEnd();
qRoll++;
}
§
Крышка на цилиндр
Фрагмент
кода программы цилиндра, объединяющего лопасти вентилятора в винт
int M=30;
int qFan=0;
glBegin(GL_POLYGON);
{
glNormal3f(1,0,0);
if(qFan<M/4)
{
glTexCoord2d(0,1-qFan*4/M);
}
if((qFan>=M/4)&&(qFan<M/2))
{
glTexCoord2d((qFan-M/4)*4/M,0);
}
if((qFan>=M/2)&&(qFan<3*M/4))
{
glTexCoord2d(1,(qFan-M/2)*4/M);
}
if(qFan>=3*M/4)
{
glTexCoord2d(1-(qFan-3*M/4)*4/M,1);
}
glVertex3f(1,sin((2*M_PI*qFan)/M),cos((2*M_PI*qFan)/M));
qFan++;
}
glEnd();
2.
Стойка
Стойка вентилятора
составлена из трех основных частей
§
Верхняя часть
корпуса (полусфера)
|
|
где rFan
– наибольший радиус в фигуре, iM, M – разбиения полусферы
|
Фрагмент
кода программы верхней части корпуса (полусферы)
M=30;
int iM=30;
double phi, psi;
q=0;
int i=0;
while (q<M)
{
while (i<iM)
{
glBindTexture(GL_TEXTURE_2D, texture2);
glBegin(GL_QUADS);
phi=(-(M_PI*(i))/iM); psi=((M_PI*(q))/M);
glNormal3f(-3*rFan*sin(phi),rFan*cos(phi)*sin(psi),rFan*cos(phi)*cos(psi));
glTexCoord2d((sin(phi)+1)/2,(cos(psi)+1)/2);
glVertex3d(*rFan*sin(phi)+bFan,rFan*cos(phi)*sin(psi),
rFan*cos(phi)*cos(psi));
phi=(-(M_PI*(i+1))/iM);
psi=((M_PI*(q))/M);
glNormal3f(-3*rFan*sin(phi),rFan*cos(phi)*sin(psi),rFan*cos(phi)*cos(psi));
glTexCoord2d((sin(phi)+1)/2,(cos(psi)+1)/2);
glVertex3d(*rFan*sin(phi)+bFan,rFan*cos(phi)*sin(psi),
rFan*cos(phi)*cos(psi));
phi=(-(M_PI*(i+1))/iM);
psi=((M_PI*(q+1))/M);
glNormal3f(-3*rFan*sin(phi),rFan*cos(phi)*sin(psi),rFan*cos(phi)*cos(psi));
glTexCoord2d((sin(phi)+1)/2,(cos(psi)+1)/2);
glVertex3d(*rFan*sin(phi)+bFan,rFan*cos(phi)*sin(psi),
rFan*cos(phi)*cos(psi));
phi=(-(M_PI*(i))/iM);
psi=((M_PI*(q+1))/M);
glNormal3f(-3*rFan*sin(phi),rFan*cos(phi)*sin(psi),rFan*cos(phi)*cos(psi));
glTexCoord2d((sin(phi)+1)/2,(cos(psi)+1)/2);
glVertex3d(*rFan*sin(phi)+bFan,rFan*cos(phi)*sin(psi),
rFan*cos(phi)*cos(psi));
glEnd();
i++;
}
i=0;
q++;
}
§
Цилиндрический
элемент стойки
|
Этот элемент стойки вентилятора состоит из цилиндров и
кругов (крышки для цилиндров). Все они вызываются с помощью функции OpenGL – glCallList. Большая часть кода элементов
вентилятора считывается программой лишь однажды, в СallLists, а вызов уже происходит
неоднократно, по мере необходимости, в функции RenderGLScene(). Этот способ
наиболее эффективен как для скорости работы программы, так и для
редактирования готового кода программы, благодаря чему одинаковые примитивы
(цилиндр, круг, квадрат, линии и т.д.) было легко использовать вызовом CallList и, применяя элементарные
преобразования – поворот, перемещение, масштабирование объектов, видоизменять
необходимым образом для получения данных элементов тела.
Элементы цилиндр и круг были описаны выше, поэтому не будем
повторяться.
|
Этот элемент тела строится через функцию CallList, в которой задан квадрат,
вызываемый 4 раза и масштабированный по разным координатам по разному.
|
Фрагмент
кода программы ножек стойки вентилятора
//--- Квадрат
square=basis_leg+1;
glNewList(square,GL_COMPILE);
glBindTexture(GL_TEXTURE_2D,texture1);
glBegin(GL_QUADS);
glNormal3f(1,0,0);
glTexCoord2d(0,0);
glVertex3f(1,-1,-1);
glTexCoord2d(1,0);
glVertex3f(1,1,-1);
glTexCoord2d(1,1);
glVertex3f(1,1,1);
glTexCoord2d(0,1);
glVertex3f(1,-1,1);
glEnd();
glEndList();
//---
Ножка вентилятора
leg=square+1;
glNewList(leg,GL_COMPILE);
glCallList(square);
glRotatef(90,0,0,1);
glCallList(square);
glRotatef(90,0,0,1);
glCallList(square);
glRotatef(90,0,0,1);
glCallList(square);
glEndList();
3.
Пульт управления
Пульт управления
вентилятором составлен из четырех основных частей
§
Основание пульта
|
Элемент строится из цилиндра с разбиением уменьшенным до 4х.
|
Фрагмент
кода программы основания пульта
M=4;
float qLeg=0;
glBindTexture(GL_TEXTURE_2D,texture5);
while (qLeg<M)
{
glBegin(GL_QUADS);
glNormal3f(0,sin(M_PI/4+qLeg*M_PI/2),cos(M_PI/4+qLeg*M_PI/2));
glTexCoord2d(0,qLeg/M);
glVertex3f(-1,sin((2*M_PI*qLeg)/M),cos((2*M_PI*qLeg)/M));
glTexCoord2d(0,(qLeg+1.0)/M);
glVertex3f(-1,sin((2*M_PI*(qLeg+1))/M),cos((2*M_PI*(qLeg+1))/M));
glTexCoord2d(1,(qLeg+1.0)/M);
glVertex3f(1,sin((2*M_PI*(qLeg+1))/M),cos((2*M_PI*(qLeg+1))/M));
glTexCoord2d(1,qLeg/M);
glVertex3f(1,sin((2*M_PI*qLeg)/M),cos((2*M_PI*qLeg)/M));
glEnd();
qLeg=qLeg+1.0;
}
§
Крышки для пульта
|
Элемент состоит из квадрата, фрагмент кода которого
содержался еще в описании ножки стойки вентилятора.
|
§
Кнопки на пульте
|
Элемент состоит из цилиндра и круга, примитивов описанных ранее.
|
Описание освещения
фигуры
Освещение тела происходит
в OpenGL благодаря включению функции SetupLighting() с необходимыми параметрами и
условиями, а также за счет правильной расстановки нормалей к примитивам, из
которого состоит тело. Чтобы задаваемые нормали нормировались автоматически
необходимо включить функцию – glEnable(GL_NORMALIZE);
Подробней остановимся на
нахождении нормалей к отдельным элементам тела.
Всего нормали были
найдены и прописаны в код программы для 6 примитивов, элементов тела.
1.
Лопасть
Для определения нормалей
лопасти, поскольку она представляет собой некую поверхность, была использована
аналитическая формула для нахождения уравнения поверхности по трём точкам и
формула для нахождения нормали к поверхности, что находится через частные
производные уравнения поверхности.
- уравнение поверхности, D не считаем, поскольку оно не влияет
на выбор нормали.
Исходя из записи
уравнения поверхности и формулам, выписанные для коэффициентов в этой формуле
получим:
Проведя расчет по данным
формулам, получим что:
Для одинаково верного
отображения освещения лопасти вентилятора как с одной, так и с другой стороны
пришлось прибегнуть к подключению двустороннего освещения с помощью функции
glLightModelf(GL_LIGHT_MODEL_TWO_SIDE, k), где к =1 для включения и к =0 для её вылючения.
2.
Цилиндр
Чтобы определить нормаль
для цилиндра нужно координату, что изменяется линейно оставить нулевой, а две
другие координаты будут совпадать с соответствующими координатами цилиндра
ввиду того, что в основании цилиндра лежит окружность.
В итоге получим
координаты нормали:
(0,sin((2*M_PI*qRoll)/M),cos((2*M_PI*qRoll)/M));
3.
Круг
Нормаль для круга
определяется как перпендикуляр к этой поверхности.
4.
Квадрат
Нормаль для квадрата
определяется аналогичным образом как и для круга.
5.
Параллелепипед
У параллелепипеда нормаль
определяется перпендикуляром к каждой грани и значит для всей грани нормаль
будет одна и направлена наружу.
6.
Полусфера
Нормаль для полусферы
определяется координатами самой фигуры, поэтому просто переписаны координаты из
glVertex3f в glNormal3f.
Графическое
представление тела с освещением
Описание наложения
текстуры на тело
Для наложения текстур на
тела, поверхности применяется функция SetupTextures(); В своей работе я использовал 4 вида текстуры, различных
размеров. Текстура накладывается на цилиндр, параллелепипед, лопасть, квадрат.
Способ наложения примитивно прост. По порядку разберёмся с каждой из фигур.
§
Цилиндр.
Для того, чтобы наложить
текстуру на фигуру необходимо было абстрактно раскрутить цилиндр в ровную
поверхность, прямоугольник и сопоставить координаты полученного прямоугольника
с координатами текстуры, как показанно на рисунках.
§
Параллелепипед.
По аналогии с цилиндром
абстрактно раскучиваем параллелепипед и наложим текстуру.
§
Лопасть.
На лопасть текстура
накладывается также исходя из особенности посторения. Поскольку лопасть
получается путем видоизменения прямоугольника, т.е. строится из прямоугольником
накладывающихся сторонами друг на друга и поворачивающихся по мере наложения на
некий угол, то на лопасть текстура накладывается по аналогии с прямоугольником,
как это было показано на цилиндре.
§
Квадрат.
Текстура на квадрат
накладывается один к одному с существующими координатами.
Графическое
представление тела с текстурой
Описание
представления поверхности
Поверхность строится перебором координат x и y в
пределах от -N до N и вычислением для каждой пары (x,y) значения z.
Нормаль к поверхности в
точке находятся через честные производные функции по x, y, z
Примечание: Поскольку при
обходе циклов по i и j они оба обращаются в ноль, то для
того, чтобы избежать выход из области действительных значений координат в
выражения для вектора нормали по х и по у вписаны незначительные для конечного
результата добавки.
Текстура на поверхность
накладывается целиком и растягивается по размерам поверхности. Наложение
происходит соотношением координат поверхности и координат текстуры так, что
каждому QUAD, из которого строится поверхность,
соотносится часть растрового изображения, разбивая его, свои образом, на сетку.
Координаты текстуры для точки :
Графическое
представление поверхности
Список используемой
литературы
1.
А.В. Боресков.
Графика Трехмерной Компьютерной Игры на Основе OpenGL. М.: «Диалог-МИФИ»,2004
2.
Ю.М. Боянковский,
А.В. Игнатенко, А.И. Фролов. Графическая библиотека OpenGL. уч.-мет.пособие. Москва,2003
3.
NeHe
Tutorials
Похожие работы на - Модель трехмерной сцены и библиотека OpenGL
| |