Студопедия — Построение модели солнечной системы
Студопедия Главная Случайная страница Обратная связь

Разделы: Автомобили Астрономия Биология География Дом и сад Другие языки Другое Информатика История Культура Литература Логика Математика Медицина Металлургия Механика Образование Охрана труда Педагогика Политика Право Психология Религия Риторика Социология Спорт Строительство Технология Туризм Физика Философия Финансы Химия Черчение Экология Экономика Электроника

Построение модели солнечной системы






Для того, чтобы создать примитивную, но управляемую модель солнечной системы нужно уметь правильно пользоваться стеком матриц моделирования. Команда glPushMatrix запоминает состояние текущей (верхней в стеке) матрицы моделирования. Это действие следует трактовать как запоминание текущего состояния координатного пространства. Если вслед за этим следует команда glTranslated (или glRotated), то она изменяет состояние пространства, умножая текущую матрицу моделирования на матрицу преобразования сдвига (или вращения) и вновь записывая результат в текущую (верхнюю в стеке) матрицу моделирования. Чтобы вспомнить предыдущее состояние пространства (то есть матрицу моделирования), надо дать команду glPopMatrix. Она сдвигает весь стек матриц вверх. При этом содержимое верхней матрицы уничтожается и заменяется тем, что было в матрице, лежащей под ней. Это следует понимать как возврат к предыдущему состоянию пространства.

Для изображения Солнца и планет можно использовать функцию glutWireSphere (double radius). Она состоит из последовательности команд, собирающих примитив из точек, то есть команд типа glVertex, и изображает каркас сферы заданного радиуса с центром в нуле координатного пространства. Положение нуля зависит от текущего состояния пространства. В нашей модели Солнце (с радиусом равным единице) должно всегда располагаться в центре сцены OpenGL. Оно может лишь вращаться вокруг своей оси. Земля должна вращаться как вокруг своей оси, так и вокруг Солнца. Луна должна вращаться вокруг своей оси, вокруг Земли и (вместе с нею) вокруг Солнца. Задачу лучше решать по частям. Сначала добиться изображения вращающегося Солнца, Затем добавить вращающуюся вокруг него Землю. После этого следует добавить вращение Земли вокруг своей оси. Луну следует создать в последнюю очередь.

Используем локальную систему координат (привязанную к объекту). Для определения порядка следования команд, изображающих Землю и Солнце, надо представить наблюдателя в начале этой системы координат, связанной с Землей. Пусть сначала и Земля и Солнце расположены в начале координат. Первая команда glRotate вращает локальную систему (Землю) относительно Солнца (годовое вращение Земли). Вторая команда glTranslate сдвигает Землю. Это означает задание радиуса планетарной орбиты. Земля помещается на орбиту в том месте, которое соответствует времени года. Третья команда glRotate вращает локальную систему координат вокруг локальной оси. Это означает поворот планеты вокруг своей оси — суточное вращение Земли.

Важно, что все эти действия надо производить при каждой перерисовке, последовательность которых управляется таймером. Начальное (исходное) состояние пространства при каждой перерисовке должно быть одинаковым. Этого также можно добиться двумя способами. В первом: матрица моделирования устанавливается в единичное значение в начале каждой перерисовки. Во втором: в начале каждой перерисовки единичное значение матрицы помещается в стек, а в конце — вновь восстанавливается. При этом предполагается, что единичное значение было заранее установлено, например, в функции OnSize. Функция перерисовки имеет вид:

glClear (GL_COLOR_BUFFER_BIT);

glColor3f (1, 1, 1);

glPushMatrix(); // Запоминаем единичное значение в стеке

glutWireSphere(1); // Рисуем Солнце

glRotated (gYear, 0, 1, 0); // Вращаем систему координат

glTranslated (2, 0, 0); // Смещаем Землю (вправо)

glRotated (gDay, 0, 0, 1); // Вращаем Землю в смещенной системе

 

glutWireSphere(0.3); // Рисуем Землю

glPopMatrix(); // Восстанавливаем единичное значение из стека

glutSwapBuffers();

Добейтесь раздельного управления всеми величинами (независимого выполнения всех преобразований). Дальнейшее усложнение сцены (изображение вращающегося Солнца и введение Луны) потребует от вас более интенсивной работы со стеком матриц моделирования. Вращение спутника Земли должно быть независимым от других движений.

int gSun, gYear, gDay, gMoon; // Углы вращения

 

void OnPaint()

{

glClear (GL_COLOR_BUFFER_BIT);

glColor3f (1, 1, 1);

 

glPushMatrix(); // Запоминаем единичное значение в стеке

glRotated (gSun, 1, 1, 1); // Вращаем систему координат

glutWireSphere(1); // Draw the Sun

 

// Операция со стеком

//....

glRotated (gYear, 0, 1, 0); // Вращаем систему координат

glTranslated (2, 0, 0); // Смещаем вправо (Землю)

 

// Операция со стеком

//....

glRotated (gDay, 0, 0, 1); // Вращаем в смещенной системе

 

glutWireSphere(0.3); // Draw the Earth

 

// Операция со стеком

//....

glRotated (gMoon, 1, 0, 0); // Вращаем систему координат

glTranslated (0, 0.45, 0); // Смещаем вверх (луну)

 

glutWireSphere(0.08); // Draw the moon

glPopMatrix(); // Восстанавливаем единичное значение из стека

glutSwapBuffers();

}

 

void OnKey (unsigned char ch, int x, int y)

{

switch (ch)

{

case 27: exit(0); break;

case 'Y': /* Годовое вращение */ break;

case 'D': /* Дневное вращение */ break;

case 'M': /* Месячное вращение (для луны) */ break;

case 'S': /* Вращение Солнца */ break;

case 'Y': /* Годовое вращение */ break;

}

glutPostRedisplay();

}

 

void Init()

{

glClearColor (0, 0, 0, 0); // Вселенная черна как ночь

glShadeModel (GL_FLAT);

}

void OnIdle()

{

// Все типы вращений

OnPaint();

}

void OnSize (int w, int h)

{

glViewport (0, 0, w, h);

glMatrixMode (GL_PROJECTION);

glLoadIdentity ();

 

// gluPerspective(60., float(w)/ h, 1.0, 20.); // Или так

glFrustum (-1.0, 1.0, -1.0, 1.0, 2., 20.0); // Или так

//========= Размещаем наблюдателя (свой глаз)

gluLookAt (0, 0, 5, 0, 0, 0, 0, 1, 0);

 

glMatrixMode(GL_MODELVIEW);

glLoadIdentity();

}

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

Смешивание цветов (Blending)

Вы уже знаете, что цвет в OpenGL может быть задан четырьмя компонентами (red, green, blue, alpha). До сих пор мы не использовали четвертую компоненту. Она управляет режимом смешивания цветов (blending). С ее помощью можно управлять прозрачностью объектов сцены OpenGL. По умолчанию этот режим выключен (равносильно команде glDisable (GL_BLEND)). Если его включить, то значение alpha используется при вычислении цвета пиксела. При этом учитывается цвет вновь поступившего пиксела и цвет пиксела, который уже присутствует в буфере кадра (framebuffer). Смешивание работает в момент, когда сцена уже прошла фазу растеризации (преобразована в множество фрагментов), но перед тем, как получить и записать в буфер кадра окончательный цвет пиксела.

Если режим смешивания выключен, то каждый новый фрагмент замещает тот, который уже существует в буфере кадра. В этом случае говорят, что новый фрагмент непрозрачен. Если режим включен, то значение alpha определяет степень использования цвета нового фрагмента в процессе комбинирования его с цветом существующего. Это влияет на степень непрозрачности (opacity) нового слоя изображения. Часто оперируют величиной transparency, которая дополняет opacity до единицы и называется прозрачностью. Так, если мы изоражаем объект, расположенный за зеленым стеклом, непрозрачность (opacity) которого 10% (а прозрачность 90%), то при вычислении комбинированного цвета пиксела естественно взять 10% (зеленого) цвета стекла и 90% цвета объекта. Эта логика обобщается и на случай нескольких последовательно соединенных пропускающих свет поверхностей.

Рассмотрим простейший пример смешивания цветов. Изобразим два плоских квадрата частично наложенных друг на друга. Пусть один будет желтым, а другой цвета cyan. По нажатию левой кнопки мыши будем изменять порядок поступления команд рисования квадратов. Это позволит увидеть как смешивается желтый источник с циановой мишенью и наоборот. Степень непрозрачности (opacity) обоих квадратов выберем одинаковой по 0.75. Метод смешивания зададим с помощью двух констант:

glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

В этом варианте обратите внимание на то, что цвета квадратов смешиваются не только друг с другом, но и с цветом фона. Попробуйте хотя бы частично избавиться от этого. Другие варианты сочетания констант, задающих метод смешивания, вы исследуете самостоятельно. Количество вариантов огромно, если учесть то, что можно исследовать эффект смешивания при разных значениях непрозрачности источника и мишени. Бездумный перебор вариантов вас разочарует, так как далеко не все комбинации имеют смысл. В качестве отправной точки для анализа сообщим, что самый простой вариант (отсутствие смешивания) дает такое сочетание коэффициентов: glBlendFunc (GL_ONE, GL_ZERO);.

bool bYellow = true; // Флаг: источник желтый

 

void Yellow() // Желтый квадрат

{

glBegin (GL_QUADS);

glColor4d(1, 1, 0, 0.75);

glVertex2d(0.1, 0.7);

glVertex2d(0.1, 0.1);

glVertex2d(0.7, 0.1);

glVertex2d(0.7, 0.7);

glEnd();

}

 

void Cyan() // Циановый квадрат

{

glBegin (GL_QUADS);

glColor4d(0, 1, 1, 0.75);

glVertex2d(0.3, 0.9);

glVertex2d(0.3, 0.3);

glVertex2d(0.9, 0.3);

glVertex2d(0.9, 0.9);

glEnd();

}

 

void Init()

{

glEnable (GL_BLEND); // Включаем режим смешивания цветов

glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

glShadeModel (GL_FLAT);

glClearColor (0, 0, 0, 0);

}

 

void OnPaint()

{

glClear(GL_COLOR_BUFFER_BIT);

 

if (bYellow)

{

Cyan(); Yellow();

}

else

{

Yellow(); Cyan();

}

glutSwapBuffers();

}

 

void OnSize (int w, int h)

{

glViewport(0, 0, w, h);

glMatrixMode(GL_PROJECTION);

glLoadIdentity();

 

if (w <= h)

gluOrtho2D (0, 1, 0, double(h)/w);

else

gluOrtho2D (0, double(w)/h, 0, 1);

}

 

void OnMouse(int button, int state, int x, int y)

{

if (state == GLUT_DOWN)

bYellow =!bYellow; // Меняем местами источник и мишень

}

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

double gx, gy, gz = 7.; // Для перемещения наблюдателя в пространстве

 

void Init()

{

glEnable(GL_DEPTH_TEST);

glEnable(GL_CULL_FACE); // Для уменьшения работы (не рисуем обратно-ориентированные грани)

 

glEnable (GL_LIGHTING);

glEnable (GL_LIGHT0);

glEnable(GL_AUTO_NORMAL);

glEnable(GL_NORMALIZE);

 

float spec[] = { 1, 1, 1, 0 };

 

glMaterialfv(GL_FRONT, GL_SPECULAR, spec);

glMateriali(GL_FRONT, GL_SHININESS, 20);

 

glEnable (GL_BLEND);

glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

}

 

void OnPaint()

{

glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

 

glPushMatrix ();

 

gluLookAt (gx, gy, gz, 0, 0, 0, 0, 1, 0);

 

glFrontFace(GL_CCW);

 

float dif[] = { 0.75f, 0.75f, 0, 1 };

glMaterialfv(GL_FRONT, GL_DIFFUSE, dif); // Gold

glTranslated (0, 0, -0.5);

glutSolidTorus (0.275, 0.85);

 

float blue[] = {0, 0.75f, 0.75f, 0.85f };

glMaterialfv(GL_FRONT, GL_DIFFUSE, blue); // Blue

glTranslated (-0.7, 0, 1);

glutSolidCylinder (0.3, 2);

 

glFrontFace(GL_CW);

float green[] = {0, 1, 0, 0.85f };

glMaterialfv(GL_FRONT, GL_DIFFUSE, green); // Green

 

glTranslated (1.4, 0, 0);

glutSolidTeapot(0.6);

 

glPopMatrix ();

glutSwapBuffers();

}

 

void OnSize (int w, int h)

{

if (!h)

return;

glViewport(0, 0, w, h);

glMatrixMode(GL_PROJECTION);

glLoadIdentity();

gluPerspective(30, (double) w/ h, 1, 30);

glMatrixMode(GL_MODELVIEW);

glLoadIdentity();

}

void OnSpecialKey (int key, int x, int y)

{

switch (key)

{

case GLUT_KEY_LEFT: gx +=.5; break;

case GLUT_KEY_RIGHT: gx -=.5; break;

case GLUT_KEY_DOWN: gy -=.5; break;

case GLUT_KEY_UP: gy +=.5; break;

}

glutPostRedisplay();

}

 

void OnMouse(int button, int state, int x, int y)

{

if (state == GLUT_DOWN)

{

gz = - gz;

}

}

Для того, чтобы понять эффект, производимый командой glEnable(GL_CULL_FACE) надо провести эксперимент. Нажимая клавишу стрелка-вниз убедитесь в том, что обратная сторона цилиндра не генерируется. Затем закомментируйте команду и вновь просмотрите обратную сторону цилиндра. Тороид и чайник — это вещи в себе. Для чайника (при включенном режиме GL_CULL_FACE) необходимо изменить ориентацию граней, из которых он состоит. Смотри команду glFrontFace(GL_CW). Аббревиатура CW скрывает описатель clock-wise, а команда означает, что фронтальными считаются поверхности, заданные обходом вершин по часовой стрелке. Для других объектов мы восстанавливаем обычное направление обхода вершин граней командой glFrontFace(GL_CCW). CCW соответствует counter clock-wise, а команда означает, что фронтальными считаются поверхности, заданные обходом вершин против часовой стрелки. Чайник требует также включить режим автоматического масштабирования нормалей. При этом, как вы помните, все векторы нормалей изменяются так, чтобы их длина была равна 1. Это делает команда glEnable(GL_NORMALIZE). Она нужна для правильной работы формулы учета освещенности, но сильно тормозит процесс генерации сцены. В этом легко убедиться методом сравнения. Пример также позволяет показать как тонко можно регулировать цветовую гамму сцены, изменяя многочисленные параметры в формуле учета освещенности. Вставьте, например, в функцию Init (перед вызовом glEnable (GL_BLEND)) следующие строки и сравните результат с тем, что было.

//=== При освещении общим светом все материалы максимально отражают синюю компоненту цвета

float amb[] = { 0, 0, 1, 1 };

glMaterialfv(GL_FRONT, GL_AMBIENT, amb);







Дата добавления: 2015-10-19; просмотров: 536. Нарушение авторских прав; Мы поможем в написании вашей работы!



Кардиналистский и ординалистский подходы Кардиналистский (количественный подход) к анализу полезности основан на представлении о возможности измерения различных благ в условных единицах полезности...

Обзор компонентов Multisim Компоненты – это основа любой схемы, это все элементы, из которых она состоит. Multisim оперирует с двумя категориями...

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

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

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

Тема 2: Анатомо-топографическое строение полостей зубов верхней и нижней челюстей. Полость зуба — это сложная система разветвлений, имеющая разнообразную конфигурацию...

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

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

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

Типовые ситуационные задачи. Задача 1. Больной К., 38 лет, шахтер по профессии, во время планового медицинского осмотра предъявил жалобы на появление одышки при значительной физической   Задача 1. Больной К., 38 лет, шахтер по профессии, во время планового медицинского осмотра предъявил жалобы на появление одышки при значительной физической нагрузке. Из медицинской книжки установлено, что он страдает врожденным пороком сердца....

Studopedia.info - Студопедия - 2014-2024 год . (0.012 сек.) русская версия | украинская версия