Опубликован: 13.07.2010 | Доступ: свободный | Студентов: 891 / 20 | Оценка: 4.40 / 4.20 | Длительность: 77:34:00
Тема: Программирование
Специальности: Программист, Архитектор программного обеспечения
Теги:
Самостоятельная работа 22:
Свет и материалы в OpenGL
< Самостоятельная работа 21 || Самостоятельная работа 22: 123456789101112 || Самостоятельная работа 23 >
Модель самолета с равномерным освещением (JetLight)
Вернемся к нормалям. Нормали как направленные отрезки (векторы), перпендикулярные к многоугольникам, сообщают OpenGL, в каком направлении располагается лицевая сторона вершины и как правильно вычислять отраженный от поверхности цвет. Единичный вектор нормали гарантирует, что освещение объекта будет вычисляться правильно.
- Заполните файл следующим кодом
// Упражнение 7: "7) Самолет с равномерным освещением" #include <math.h> //********************************************************** // Прототипы void JetLight(); void SetLightJetLight(); void RenderSceneJetLight(void); void ChangeSizeJetLight(int, int); // При изменении размеров окна //********************************************************** // Вспомогательный код typedef GLfloat GLTVector3[3]; // Новый тип - вектор void gltGetNormalVector(const GLTVector3 vP1, const GLTVector3 vP2, const GLTVector3 vP3, GLTVector3 vNormal); void gltSubtractVectors(const GLTVector3 vFirst, const GLTVector3 vSecond, GLTVector3 vResult); void gltVectorCrossProduct(const GLTVector3 vU, const GLTVector3 vV, GLTVector3 vResult); void gltNormalizeVector(GLTVector3 vNormal); GLfloat gltGetVectorLength(const GLTVector3 vVector); GLfloat gltGetVectorLengthSqrd(const GLTVector3 vVector); void gltScaleVector(GLTVector3 vVector, const GLfloat fScale); //********************************************************** // Рисовать самолет void JetLight() { GLTVector3 vNormal; // Для вектора нормали // Очищаем буфер цвета и глубины glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Сохранить матрицу преобразования и выполнить // последовательность поворотов glPushMatrix(); glRotatef(xRot, 1.0f, 0.0f, 0.0f); glRotatef(yRot, 0.0f, 1.0f, 0.0f); // Устанавливаем цвет материала серый для всех граней самолета glColor3ub(128, 128, 128); // Рисуем самолет glBegin(GL_TRIANGLES); // Конус носа ///////////////////////////// glNormal3f(0.0f, -1.0f, 0.0f); glVertex3f(0.0f, 0.0f, 60.0f); glVertex3f(-15.0f, 0.0f, 30.0f); glVertex3f(15.0f,0.0f,30.0f); {// Блок кода GLTVector3 vPoints[3] = {{ 15.0f, 0.0f, 30.0f}, { 0.0f, 15.0f, 30.0f}, { 0.0f, 0.0f, 60.0f}}; gltGetNormalVector(vPoints[0], vPoints[1], vPoints[2], vNormal); glNormal3fv(vNormal); glVertex3fv(vPoints[0]); glVertex3fv(vPoints[1]); glVertex3fv(vPoints[2]); } {// Блок кода GLTVector3 vPoints[3] = {{ 0.0f, 0.0f, 60.0f }, { 0.0f, 15.0f, 30.0f }, { -15.0f, 0.0f, 30.0f }}; gltGetNormalVector(vPoints[0], vPoints[1], vPoints[2], vNormal); glNormal3fv(vNormal); glVertex3fv(vPoints[0]); glVertex3fv(vPoints[1]); glVertex3fv(vPoints[2]); } // Тело самолета ////////////////////////// { GLTVector3 vPoints[3] = {{ -15.0f, 0.0f, 30.0f }, { 0.0f, 15.0f, 30.0f }, { 0.0f, 0.0f, -56.0f }}; gltGetNormalVector(vPoints[0], vPoints[1], vPoints[2], vNormal); glNormal3fv(vNormal); glVertex3fv(vPoints[0]); glVertex3fv(vPoints[1]); glVertex3fv(vPoints[2]); } { GLTVector3 vPoints[3] = {{ 0.0f, 0.0f, -56.0f }, { 0.0f, 15.0f, 30.0f }, { 15.0f,0.0f,30.0f }}; gltGetNormalVector(vPoints[0], vPoints[1], vPoints[2], vNormal); glNormal3fv(vNormal); glVertex3fv(vPoints[0]); glVertex3fv(vPoints[1]); glVertex3fv(vPoints[2]); } glNormal3f(0.0f, -1.0f, 0.0f); glVertex3f(15.0f,0.0f,30.0f); glVertex3f(-15.0f, 0.0f, 30.0f); glVertex3f(0.0f, 0.0f, -56.0f); /////////////////////////////////////////// // Левое крыло // Большой треугольник для основания крыла { GLTVector3 vPoints[3] = {{ 0.0f,2.0f,27.0f }, { -60.0f, 2.0f, -8.0f }, { 60.0f, 2.0f, -8.0f }}; gltGetNormalVector(vPoints[0], vPoints[1], vPoints[2], vNormal); glNormal3fv(vNormal); glVertex3fv(vPoints[0]); glVertex3fv(vPoints[1]); glVertex3fv(vPoints[2]); } { GLTVector3 vPoints[3] = {{ 60.0f, 2.0f, -8.0f}, {0.0f, 7.0f, -8.0f}, {0.0f,2.0f,27.0f }}; gltGetNormalVector(vPoints[0], vPoints[1], vPoints[2], vNormal); glNormal3fv(vNormal); glVertex3fv(vPoints[0]); glVertex3fv(vPoints[1]); glVertex3fv(vPoints[2]); } { GLTVector3 vPoints[3] = {{60.0f, 2.0f, -8.0f}, {-60.0f, 2.0f, -8.0f}, {0.0f,7.0f,-8.0f }}; gltGetNormalVector(vPoints[0], vPoints[1], vPoints[2], vNormal); glNormal3fv(vNormal); glVertex3fv(vPoints[0]); glVertex3fv(vPoints[1]); glVertex3fv(vPoints[2]); } // Другое крыло верхней секции { GLTVector3 vPoints[3] = {{0.0f,2.0f,27.0f}, {0.0f, 7.0f, -8.0f}, {-60.0f, 2.0f, -8.0f}}; gltGetNormalVector(vPoints[0], vPoints[1], vPoints[2], vNormal); glNormal3fv(vNormal); glVertex3fv(vPoints[0]); glVertex3fv(vPoints[1]); glVertex3fv(vPoints[2]); } /////////////////////////////////////////// // Хвост glNormal3f(0.0f, -1.0f, 0.0f); glVertex3f(-30.0f, -0.50f, -57.0f); glVertex3f(30.0f, -0.50f, -57.0f); glVertex3f(0.0f,-0.50f,-40.0f); // Верхняя левая сторона { GLTVector3 vPoints[3] = {{ 0.0f,-0.5f,-40.0f }, {30.0f, -0.5f, -57.0f}, {0.0f, 4.0f, -57.0f }}; gltGetNormalVector(vPoints[0], vPoints[1], vPoints[2], vNormal); glNormal3fv(vNormal); glVertex3fv(vPoints[0]); glVertex3fv(vPoints[1]); glVertex3fv(vPoints[2]); } // Верхняя правая сторона { GLTVector3 vPoints[3] = {{ 0.0f, 4.0f, -57.0f }, { -30.0f, -0.5f, -57.0f }, { 0.0f,-0.5f,-40.0f }}; gltGetNormalVector(vPoints[0], vPoints[1], vPoints[2], vNormal); glNormal3fv(vNormal); glVertex3fv(vPoints[0]); glVertex3fv(vPoints[1]); glVertex3fv(vPoints[2]); } // Оборотная нижняя часть { GLTVector3 vPoints[3] = {{ 30.0f,-0.5f,-57.0f }, { -30.0f, -0.5f, -57.0f }, { 0.0f, 4.0f, -57.0f }}; gltGetNormalVector(vPoints[0], vPoints[1], vPoints[2], vNormal); glNormal3fv(vNormal); glVertex3fv(vPoints[0]); glVertex3fv(vPoints[1]); glVertex3fv(vPoints[2]); } { GLTVector3 vPoints[3] = {{ 0.0f,0.5f,-40.0f }, { 3.0f, 0.5f, -57.0f }, { 0.0f, 25.0f, -65.0f }}; gltGetNormalVector(vPoints[0], vPoints[1], vPoints[2], vNormal); glNormal3fv(vNormal); glVertex3fv(vPoints[0]); glVertex3fv(vPoints[1]); glVertex3fv(vPoints[2]); } { GLTVector3 vPoints[3] = {{ 0.0f, 25.0f, -65.0f }, { -3.0f, 0.5f, -57.0f}, { 0.0f,0.5f,-40.0f }}; gltGetNormalVector(vPoints[0], vPoints[1], vPoints[2], vNormal); glNormal3fv(vNormal); glVertex3fv(vPoints[0]); glVertex3fv(vPoints[1]); glVertex3fv(vPoints[2]); } { GLTVector3 vPoints[3] = {{ 3.0f,0.5f,-57.0f }, { -3.0f, 0.5f, -57.0f }, { 0.0f, 25.0f, -65.0f }}; gltGetNormalVector(vPoints[0], vPoints[1], vPoints[2], vNormal); glNormal3fv(vNormal); glVertex3fv(vPoints[0]); glVertex3fv(vPoints[1]); glVertex3fv(vPoints[2]); } glEnd(); // О самолете // Восстановить матрицу glPopMatrix(); // Переключить буфер glutSwapBuffers(); } //********************************************************** // Задать параметры освещения и согласования цветов материала void SetLightJetLight() { GLfloat ambientLight[] = { 0.3f, 0.3f, 0.3f, 1.0f };// Фоновый слабобелый GLfloat diffuseLight[] = { 0.7f, 0.7f, 0.7f, 1.0f };// Рассеяный среднебелый GLfloat light_position[] = {1.0, 1.0, 1.0, 0.0};// Расположение источника glShadeModel(GL_SMOOTH); GLfloat diffuseMaterial[] = {0.5, 0.5, 0.5, 1.0}; glMaterialfv(GL_FRONT, GL_DIFFUSE, diffuseMaterial);// Начальное значение диффузного материала glLightfv(GL_LIGHT0,GL_AMBIENT,ambientLight); glLightfv(GL_LIGHT0,GL_DIFFUSE,diffuseLight); glLightfv(GL_LIGHT0, GL_POSITION, light_position); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); // Режим согласования цветов назначаем для фонового и рассеянного glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE); // Включаем поддержку согласования цветов glEnable(GL_COLOR_MATERIAL); } //********************************************************** // Функция обратного вызова для рисования сцены void RenderSceneJetLight(void) { // Сбрасываем буфер цвета и буфер глубины glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Рисуем сцену JetLight(); // Прокачка сообщений glFlush(); } //********************************************************** void ChangeSizeJetLight(int width, int height) { // Устанавливаем индивидуальные настройки освещения SetLightJetLight(); glEnable(GL_DEPTH_TEST); // Включить тест глубины glEnable(GL_CULL_FACE); // Отображать только лицевую сторону glFrontFace(GL_CCW); // Считать лицевым обход против часовой стрелки glClearColor(0.0f, 0.0f, 1.0f, 1.0f);// Цвет фона окна // Предотвращаем деление на нуль if(height == 0) height = 1; // Устанавливаем поле просмотра с размерами окна glViewport(0, 0, width, height); // Устанавливает матрицу преобразования в режим проецирования glMatrixMode(GL_PROJECTION); glLoadIdentity(); // Устанавливаем размеры отсекающего объема перспективы GLfloat aspectRatio = (GLfloat)width / (GLfloat)height; // Для соблюдения пропорций gluPerspective(45.0f, aspectRatio, 1.0f, 250.0f); // Отсекающая перспектива // Восстановливает матрицу преобразования в исходный режим вида glMatrixMode(GL_MODELVIEW); glLoadIdentity(); // Отодвинем сцену в отрицательную сторону оси 0z glTranslatef(0.0f, 0.0f, -180.0f); } //********************************************************** // Вспомогательный код //********************************************************** void gltGetNormalVector(const GLTVector3 vP1, const GLTVector3 vP2, const GLTVector3 vP3, GLTVector3 vNormal) { GLTVector3 vV1, vV2; gltSubtractVectors(vP2, vP1, vV1); gltSubtractVectors(vP3, vP1, vV2); gltVectorCrossProduct(vV1, vV2, vNormal); gltNormalizeVector(vNormal); } //********************************************************** void gltSubtractVectors(const GLTVector3 vFirst, const GLTVector3 vSecond, GLTVector3 vResult) { vResult[0] = vFirst[0] - vSecond[0]; vResult[1] = vFirst[1] - vSecond[1]; vResult[2] = vFirst[2] - vSecond[2]; } //********************************************************** void gltVectorCrossProduct(const GLTVector3 vU, const GLTVector3 vV, GLTVector3 vResult) { vResult[0] = vU[1]*vV[2] - vV[1]*vU[2]; vResult[1] = -vU[0]*vV[2] + vV[0]*vU[2]; vResult[2] = vU[0]*vV[1] - vV[0]*vU[1]; } //********************************************************** void gltNormalizeVector(GLTVector3 vNormal) { GLfloat fLength = 1.0f / gltGetVectorLength(vNormal); gltScaleVector(vNormal, fLength); } //********************************************************** GLfloat gltGetVectorLength(const GLTVector3 vVector) { return (GLfloat)sqrt(gltGetVectorLengthSqrd(vVector)); } //********************************************************** GLfloat gltGetVectorLengthSqrd(const GLTVector3 vVector) { return (vVector[0]*vVector[0]) + (vVector[1]*vVector[1]) + (vVector[2]*vVector[2]); } //********************************************************** void gltScaleVector(GLTVector3 vVector, const GLfloat fScale) { vVector[0] *= fScale; vVector[1] *= fScale; vVector[2] *= fScale; }Листинг 23.24. Код файла JetLight.h
- Добавьте в файл LightAndMaterial.cpp код, подключающий новое упражнение
// LightAndMaterial.cpp : Defines the entry point for the console application. // //********************************************************** // Подключение стандартного файла с библиотекой OpenGL #include "stdafx.h" //********************************************************** // Прототипы функций void ExecuteMenu(int); // Контекстное меню первого уровня void TimerFunc(int); // Обработчик события таймера void SpecialKeys(int, int, int); // Обработка нажатия клавиш void RenderScene(void); // Функция рендеринга void ChangeSize(int, int); // Функция установки отсекающего объема // Глобальная переменная выбранного варианта основного меню int choice = 1; // Глобальные переменные для создания вращения // в градусах GLfloat xRot = 0.0f; GLfloat yRot = 0.0f; GLfloat zRot = 0.0f; GLint w, h; // Ширина и высота экрана //********************************************************** // Подключение файлов с упражнениями #include "ColorCube.h" // Упражнение 1: "1) Куб цвета" #include "Jet.h" // Упражнение 2: "2) Самолет без освещения" #include "LightSphere.h" // Упражнение 3: "3) Рисование освещенной сферы" #include "MultiMaterial.h" // Упражнение 4: "4) Рисование с разными материалами" #include "ColorSphere.h" // Упражнение 5: "5) Способ согласования цветов" #include "JetNight.h" // Упражнение 6: "6) Самолет с нулевым освещением" #include "JetLight.h" // Упражнение 7: "7) Самолет с равномерным освещением" //********************************************************** // Функция обратного вызова обработки выбора пользователя void ExecuteMenu(int choice) { // Сбрасываем углы вращения прежнего варианта xRot = yRot = zRot = 0; // Выключаем освещение glDisable(GL_LIGHTING); // Выключаем режим согласования цветов glDisable(GL_COLOR_MATERIAL); // Запоминаем выбор в глобальную переменную ::choice = choice; switch(::choice) { case 1: ChangeSizeColorCube(w, h); break; case 2: ChangeSizeJet(w, h); break; case 3: ChangeSizeLightSphere(w, h); break; case 4: ChangeSizeMultiMaterial(w, h); break; case 5: ChangeSizeColorSphere(w, h); break; case 6: ChangeSizeJetNight(w, h); break; case 7: ChangeSizeJetLight(w, h); break; } // Вызвать принудительно визуализацию glutPostRedisplay(); } //********************************************************** // Функция обратного вызова для рисования сцены void RenderScene(void) { // Сохранить прежние настройки OpenGL в стеке атрибутов glPushAttrib(GL_LIGHTING_BIT); switch(::choice) { case 1: RenderSceneColorCube(); break; case 2: RenderSceneJet(); break; case 3: RenderSceneLightSphere(); break; case 4: RenderSceneMultiMaterial(); break; case 5: RenderSceneColorSphere(); break; case 6: RenderSceneJetNight(); break; case 7: RenderSceneJetLight(); break; } // Восстановить прежние настройки OpenGL из стека атрибутов glPopAttrib(); } //********************************************************** // Вызывается библиотекой GLUT при изменении размеров окна void ChangeSize(int width, int height) { w = width; h = height; switch(::choice) { case 1: ChangeSizeColorCube(width, height); break; case 2: ChangeSizeJet(width, height); break; case 3: ChangeSizeLightSphere(width, height); break; case 4: ChangeSizeMultiMaterial(width, height); break; case 5: ChangeSizeColorSphere(width, height); break; case 6: ChangeSizeJetNight(width, height); break; case 7: ChangeSizeJetLight(width, height); break; } } //********************************************************** // Обработчик события таймера void TimerFunc(int value) { glutPostRedisplay(); // Перерисовка сцены glutTimerFunc(30, TimerFunc, 1); // Заряжаем новый таймер } //********************************************************** // Управление с клавиатуры стрелками // для задания новых значений матрицы поворота void SpecialKeys(int key, int x, int y) { if(key == GLUT_KEY_UP) // Стрелка вверх xRot -= 5.0f; if(key == GLUT_KEY_DOWN)// Стрелка вниз xRot += 5.0f; if(key == GLUT_KEY_LEFT)// Стрелка влево yRot -= 5.0f; if(key == GLUT_KEY_RIGHT)// Стрелка вправо yRot += 5.0f; xRot = (GLfloat)((const int)xRot % 360); yRot = (GLfloat)((const int)yRot % 360); // Для упражнения 5 смены материала if(key == GLUT_KEY_F1) // Меняем красный { diffuseMaterial[0] += 0.1; *diffuseMaterial = *diffuseMaterial > 1.0 ? 0.0 : *diffuseMaterial; glColor4fv(diffuseMaterial); } if(key == GLUT_KEY_F2) // Меняем зеленый { diffuseMaterial[1] += 0.1; *(diffuseMaterial + 1) = diffuseMaterial[1] > 1.0 ? 0.0 : diffuseMaterial[1]; glColor4fv(diffuseMaterial); } if(key == GLUT_KEY_F3) // Меняем синий { diffuseMaterial[2] += 0.1; *(diffuseMaterial + 2) = diffuseMaterial[2] > 1.0 ? 0.0 : diffuseMaterial[2]; glColor4fv(diffuseMaterial); } // Вызвать принудительно визуализацию с помощью RenderScene() glutPostRedisplay(); } //********************************************************** void main(int argc, char* argv[]) { glutInit(&argc, argv); // Двойная буферизация, цветовая модель RGB, буфер глубины glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); glutInitWindowSize(300, 300); // Начальные размеры окна glutCreateWindow("Свет и материалы"); // Заголовок окна glutDisplayFunc(RenderScene); // Обновление сцены при разрушении окна glutReshapeFunc(ChangeSize); // При изменении размера окна glutTimerFunc(100, TimerFunc, 1); // Создали таймер glutSpecialFunc(SpecialKeys); // Для управления с клавиатуры // Создание меню и добавление опций выбора glutCreateMenu(ExecuteMenu); glutAddMenuEntry("1) Куб цвета", 1); glutAddMenuEntry("2) Самолет без освещения", 2); glutAddMenuEntry("3) Рисование освещенной сферы", 3); glutAddMenuEntry("4) Рисование с разными материалами", 4); glutAddMenuEntry("5) Способ согласования цветов (F1, F2, F3)", 5); glutAddMenuEntry("6) Самолет с нулевым освещением", 6); glutAddMenuEntry("7) Самолет с равномерным освещением", 7); glutAttachMenu(GLUT_RIGHT_BUTTON);// Присоединяем // Конец создания меню glutMainLoop(); // Цикл сообщений графического окна }Листинг 23.25. Код подключения модели самолета с равномерным освещением в файле LightAndMaterial.cpp
- Запустите приложение и выполните упражнение 7, результат должен быть примерно таким
Если поуправлять поворотами модели с помощью клавиш-стрелок, то будет меняться цвет граней самолета по мере того, как их векторы нормалей будут менять свой угол по отношению к источнику света и точке наблюдения. OpenGL "на лету" будет эти цвета пересчитывать.
< Самостоятельная работа 21 || Самостоятельная работа 22: 123456789101112 || Самостоятельная работа 23 >