Опубликован: 13.07.2010 | Доступ: свободный | Студентов: 891 / 20 | Оценка: 4.40 / 4.20 | Длительность: 77:34:00
Тема: Программирование
Специальности: Программист, Архитектор программного обеспечения
Теги:
Самостоятельная работа 22:
Свет и материалы в OpenGL
< Самостоятельная работа 21 || Самостоятельная работа 22: 123456789101112 || Самостоятельная работа 23 >
Освещенный мир сфер (SphereWorld)
В заключение выполним еще одно упражнение. В предыдущей лабораторной работе мы рассматривали пример, где рисовался мир сфер в каркасном режиме. Здесь в качестве поучительной иллюстрации приведем тот же пример, но с использованием в сцене источников света и материалов.
-
Наполните этот файл следующим кодом
// SphereWorld.h // Упражнение 11: "11) Освещенный мир сфер" //********************************************************** // Прототипы void SetLightSphereWorld(); void ChangeSizeSphereWorld(int width, int height); void SpecialKeysSphereWorld(int key); void RenderSceneSphereWorld(void); void DrawInhabitants(GLint nShadow); void DrawGround(void); //********************************************************** // Глобальные переменные typedef struct{ GLTVector3 vLocation; GLTVector3 vUp; GLTVector3 vForward; } GLTFrame; #define NUM_SPHERES 30 GLTFrame spheres[NUM_SPHERES]; GLTFrame frameCamera; // Данные для источников света и материалов GLfloat fLightPos[4] = { -100.0f, 100.0f, 50.0f, 1.0f }; GLfloat fNoLight[] = { 0.0f, 0.0f, 0.0f, 0.0f }; GLfloat fLowLight[] = { 0.25f, 0.25f, 0.25f, 1.0f }; GLfloat fBrightLight[] = { 1.0f, 1.0f, 1.0f, 1.0f }; // Матрица проектировария тени GLTMatrix mShadowMatrix; //********************************************************** // Вспомогательный код void gltApplyActorTransform(GLTFrame *pFrame); void gltApplyCameraTransform(GLTFrame *pCamera); void gltDrawTorus(GLfloat majorRadius, GLfloat minorRadius, GLint numMajor, GLint numMinor); void gltInitFrame(GLTFrame *pFrame); void gltMoveFrameForward(GLTFrame *pFrame, GLfloat fStep); void gltRotateFrameLocalY(GLTFrame *pFrame, GLfloat fAngle); #define GLT_PI_DIV_180 0.017453292519943296 #define gltDegToRad(x) ((x)*GLT_PI_DIV_180) void gltGetMatrixFromFrame(GLTFrame *pFrame, GLTMatrix mMatrix); void gltRotateVector(const GLTVector3 vSrcVector, const GLTMatrix mMatrix, GLTVector3 vOut); void gltRotationMatrix(float angle, float x, float y, float z, GLTMatrix mMatrix); void gltLoadIdentityMatrix(GLTMatrix m); //********************************************************** // Установка света и материалов void SetLightSphereWorld() { int iSphere; // Точки плоскости размещения тени GLTVector3 vPoints[3] = {{ 0.0f, -0.4f, 0.0f }, { 10.0f, -0.4f, 0.0f }, { 5.0f, -0.4f, -5.0f }}; // Установка параметров света glLightModelfv(GL_LIGHT_MODEL_AMBIENT, fNoLight); glLightfv(GL_LIGHT0, GL_AMBIENT, fLowLight); glLightfv(GL_LIGHT0, GL_DIFFUSE, fBrightLight); glLightfv(GL_LIGHT0, GL_SPECULAR, fBrightLight); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); // Вычисляем матрицу тени gltMakeShadowMatrix(vPoints, fLightPos, mShadowMatrix); // Задаем согласование цветов материала glEnable(GL_COLOR_MATERIAL); glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE); glMateriali(GL_FRONT, GL_SHININESS, 128); gltInitFrame(&frameCamera); // Инициализируем камеру // Вычисляем случайно места для размещения сфер for(iSphere = 0; iSphere < NUM_SPHERES; iSphere++) { // Инициализация фрейма для очередной сферы gltInitFrame(&spheres[iSphere]); // Корректируем координаты сфер spheres[iSphere].vLocation[0] = (float)((rand() % 400) - 200) * 0.1f; spheres[iSphere].vLocation[1] = 0.0f; spheres[iSphere].vLocation[2] = (float)((rand() % 400) - 200) * 0.1f; } } //********************************************************** // Рисуем основание как ленты треугольников void DrawGround(void) { GLfloat fExtent = 20.0f; GLfloat fStep = 1.0f; GLfloat y = -0.4f; GLint iStrip, iRun; for(iStrip = -fExtent; iStrip <= fExtent; iStrip += fStep) { glBegin(GL_TRIANGLE_STRIP); glNormal3f(0.0f, 1.0f, 0.0f); // Нормаль для всех вершин for(iRun = fExtent; iRun >= -fExtent; iRun -= fStep) { glVertex3f(iStrip, y, iRun); glVertex3f(iStrip + fStep, y, iRun); } glEnd(); } } //********************************************************** // Рисуем случайным образом сферы и тор (или их тени) void DrawInhabitants(GLint nShadow) { static GLfloat yRot = 0.0f; GLint i; if(nShadow == 0) yRot += 0.5f; else // Черный цвет glColor3f(0.0f, 0.0f, 0.0f); // Рисуем зелеными случайно расположенные сферы if(nShadow == 0) glColor3f(0.0f, 1.0f, 0.0f); for(i = 0; i < NUM_SPHERES; i++) { glPushMatrix(); gltApplyActorTransform(&spheres[i]); glutSolidSphere(0.3f, 17, 9); glPopMatrix(); } glPushMatrix(); glTranslatef(0.0f, 0.1f, -2.5f); if(nShadow == 0) glColor3f(0.0f, 0.0f, 1.0f); glPushMatrix(); glRotatef(-yRot * 2.0f, 0.0f, 1.0f, 0.0f); glTranslatef(1.0f, 0.0f, 0.0f); glutSolidSphere(0.1f, 17, 9); glPopMatrix(); if(nShadow == 0) { // Устанавливаем для тора зеркальные свойства glColor3f(1.0f, 0.0f, 0.0f);// Красный цвет тора glMaterialfv(GL_FRONT, GL_SPECULAR, fBrightLight); } glRotatef(yRot, 0.0f, 1.0f, 0.0f); gltDrawTorus(0.35, 0.15, 61, 37); glMaterialfv(GL_FRONT, GL_SPECULAR, fNoLight); glPopMatrix(); } //********************************************************** // Рендеринг сцены void RenderSceneSphereWorld(void) { // Очистка буфера цвета и глубины glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glPushMatrix(); gltApplyCameraTransform(&frameCamera); // Позиция источника света до преобразований glLightfv(GL_LIGHT0, GL_POSITION, fLightPos); // Рисуем основание коричневым цветом glColor3f(0.60f, .40f, .10f); DrawGround(); // Вначале рисуем тени объектов // при выключенных глубине и освещении glDisable(GL_DEPTH_TEST); glDisable(GL_LIGHTING); glPushMatrix(); glMultMatrixf(mShadowMatrix); DrawInhabitants(1); glPopMatrix(); // Включаем проверку глубины и освещение glEnable(GL_LIGHTING); glEnable(GL_DEPTH_TEST); // Теперь рисуем сами объекты (сферы и тор) DrawInhabitants(0); glPopMatrix(); // Переключаем буфер и обновляем экран glutSwapBuffers(); glutPostRedisplay(); } //********************************************************** // Управление клавишами void SpecialKeysSphereWorld(int key) { if(key == GLUT_KEY_UP) gltMoveFrameForward(&frameCamera, 0.1f); if(key == GLUT_KEY_DOWN) gltMoveFrameForward(&frameCamera, -0.1f); if(key == GLUT_KEY_LEFT) gltRotateFrameLocalY(&frameCamera, 0.1); if(key == GLUT_KEY_RIGHT) gltRotateFrameLocalY(&frameCamera, -0.1); } //********************************************************** void ChangeSizeSphereWorld(int width, int height) { // Устанавливаем индивидуальные настройки освещения // и материала SetLightSphereWorld(); glEnable(GL_DEPTH_TEST); // Включить тест глубины glEnable(GL_CULL_FACE); // Отображать только лицевую сторону glFrontFace(GL_CCW); // Считать лицевым обход против часовой стрелки glCullFace(GL_BACK); // Цвет фона окна угрюмо - серый glClearColor(fLowLight[0], fLowLight[1], fLowLight[2], fLowLight[3]); // Предотвращаем деление на нуль if(height == 0) height = 1; // Устанавливаем поле просмотра с размерами окна glViewport(0, 0, width, height); // Устанавливает матрицу преобразования в режим проецирования glMatrixMode(GL_PROJECTION); glLoadIdentity(); // Устанавливаем размеры отсекающего объема перспективы GLfloat aspectRatio = (GLfloat)width / (GLfloat)height; // Для соблюдения пропорций gluPerspective(35.0f, aspectRatio, 1.0f, 50.0f); // Отсекающая перспектива // Восстановливает матрицу преобразования в исходный режим вида glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } //********************************************************** //********************************************************** // Вспомогательный код //********************************************************** //********************************************************** //////////////////////////////////////////////////////////////////// // Apply an actors transform given it's frame of reference void gltApplyActorTransform(GLTFrame *pFrame) { GLTMatrix mTransform; gltGetMatrixFromFrame(pFrame, mTransform); glMultMatrixf(mTransform); } ////////////////////////////////////////////////////////////////// // Apply a camera transform given a frame of reference. This is // pretty much just an alternate implementation of gluLookAt using // floats instead of doubles and having the forward vector specified // instead of a point out in front of me. void gltApplyCameraTransform(GLTFrame *pCamera) { GLTMatrix mMatrix; GLTVector3 vAxisX; GLTVector3 zFlipped; zFlipped[0] = -pCamera->vForward[0]; zFlipped[1] = -pCamera->vForward[1]; zFlipped[2] = -pCamera->vForward[2]; // Derive X vector gltVectorCrossProduct(pCamera->vUp, zFlipped, vAxisX); // Populate matrix, note this is just the rotation and is transposed mMatrix[0] = vAxisX[0]; mMatrix[4] = vAxisX[1]; mMatrix[8] = vAxisX[2]; mMatrix[12] = 0.0f; mMatrix[1] = pCamera->vUp[0]; mMatrix[5] = pCamera->vUp[1]; mMatrix[9] = pCamera->vUp[2]; mMatrix[13] = 0.0f; mMatrix[2] = zFlipped[0]; mMatrix[6] = zFlipped[1]; mMatrix[10] = zFlipped[2]; mMatrix[14] = 0.0f; mMatrix[3] = 0.0f; mMatrix[7] = 0.0f; mMatrix[11] = 0.0f; mMatrix[15] = 1.0f; // Do the rotation first glMultMatrixf(mMatrix); // Now, translate backwards glTranslatef(-pCamera->vLocation[0], -pCamera->vLocation[1], -pCamera->vLocation[2]); } #define GLT_PI 3.14159265358979323846 // For best results, put this in a display list // Draw a torus (doughnut) at z = fZVal... torus is in xy plane void gltDrawTorus(GLfloat majorRadius, GLfloat minorRadius, GLint numMajor, GLint numMinor) { GLTVector3 vNormal; double majorStep = 2.0f*GLT_PI / numMajor; double minorStep = 2.0f*GLT_PI / numMinor; int i, j; for (i=0; i < numMajor; ++i) { double a0 = i * majorStep; double a1 = a0 + majorStep; GLfloat x0 = (GLfloat) cos(a0); GLfloat y0 = (GLfloat) sin(a0); GLfloat x1 = (GLfloat) cos(a1); GLfloat y1 = (GLfloat) sin(a1); glBegin(GL_TRIANGLE_STRIP); for (j=0; j<=numMinor; ++j) { double b = j * minorStep; GLfloat c = (GLfloat) cos(b); GLfloat r = minorRadius * c + majorRadius; GLfloat z = minorRadius * (GLfloat) sin(b); // First point glTexCoord2f((float)(i)/(float)(numMajor), (float)(j)/(float)(numMinor)); vNormal[0] = x0*c; vNormal[1] = y0*c; vNormal[2] = z/minorRadius; gltNormalizeVector(vNormal); glNormal3fv(vNormal); glVertex3f(x0*r, y0*r, z); glTexCoord2f((float)(i+1)/(float)(numMajor), (float)(j)/(float)(numMinor)); vNormal[0] = x1*c; vNormal[1] = y1*c; vNormal[2] = z/minorRadius; glNormal3fv(vNormal); glVertex3f(x1*r, y1*r, z); } glEnd(); } } // Initialize a frame of reference. // Uses default OpenGL viewing position and orientation void gltInitFrame(GLTFrame *pFrame) { pFrame->vLocation[0] = 0.0f; pFrame->vLocation[1] = 0.0f; pFrame->vLocation[2] = 0.0f; pFrame->vUp[0] = 0.0f; pFrame->vUp[1] = 1.0f; pFrame->vUp[2] = 0.0f; pFrame->vForward[0] = 0.0f; pFrame->vForward[1] = 0.0f; pFrame->vForward[2] = -1.0f; } ///////////////////////////////////////////////////////// // March a frame of reference forward. This simply moves // the location forward along the forward vector. void gltMoveFrameForward(GLTFrame *pFrame, GLfloat fStep) { pFrame->vLocation[0] += pFrame->vForward[0] * fStep; pFrame->vLocation[1] += pFrame->vForward[1] * fStep; pFrame->vLocation[2] += pFrame->vForward[2] * fStep; } ///////////////////////////////////////////////////////// // Rotate a frame around it's local Y axis void gltRotateFrameLocalY(GLTFrame *pFrame, GLfloat fAngle) { GLTMatrix mRotation; GLTVector3 vNewForward; gltRotationMatrix((float)gltDegToRad(fAngle), 0.0f, 1.0f, 0.0f, mRotation); gltRotationMatrix(fAngle, pFrame->vUp[0], pFrame->vUp[1], pFrame->vUp[2], mRotation); gltRotateVector(pFrame->vForward, mRotation, vNewForward); memcpy(pFrame->vForward, vNewForward, sizeof(GLTVector3)); } /////////////////////////////////////////////////////////////////// // Derives a 4x4 transformation matrix from a frame of reference void gltGetMatrixFromFrame(GLTFrame *pFrame, GLTMatrix mMatrix) { GLTVector3 vXAxis; // Derived X Axis // Calculate X Axis gltVectorCrossProduct(pFrame->vUp, pFrame->vForward, vXAxis); // Just populate the matrix // X column vector memcpy(mMatrix, vXAxis, sizeof(GLTVector3)); mMatrix[3] = 0.0f; // y column vector memcpy(mMatrix+4, pFrame->vUp, sizeof(GLTVector3)); mMatrix[7] = 0.0f; // z column vector memcpy(mMatrix+8, pFrame->vForward, sizeof(GLTVector3)); mMatrix[11] = 0.0f; // Translation/Location vector memcpy(mMatrix+12, pFrame->vLocation, sizeof(GLTVector3)); mMatrix[15] = 1.0f; } // Rotates a vector using a 4x4 matrix. Translation column is ignored void gltRotateVector(const GLTVector3 vSrcVector, const GLTMatrix mMatrix, GLTVector3 vOut) { vOut[0] = mMatrix[0] * vSrcVector[0] + mMatrix[4] * vSrcVector[1] + mMatrix[8] * vSrcVector[2]; vOut[1] = mMatrix[1] * vSrcVector[0] + mMatrix[5] * vSrcVector[1] + mMatrix[9] * vSrcVector[2]; vOut[2] = mMatrix[2] * vSrcVector[0] + mMatrix[6] * vSrcVector[1] + mMatrix[10] * vSrcVector[2]; } /////////////////////////////////////////////////////////////////////////////// // Creates a 4x4 rotation matrix, takes radians NOT degrees void gltRotationMatrix(float angle, float x, float y, float z, GLTMatrix mMatrix) { float vecLength, sinSave, cosSave, oneMinusCos; float xx, yy, zz, xy, yz, zx, xs, ys, zs; // If NULL vector passed in, this will blow up... if(x == 0.0f && y == 0.0f && z == 0.0f) { gltLoadIdentityMatrix(mMatrix); return; } // Scale vector vecLength = (float)sqrt( x*x + y*y + z*z ); // Rotation matrix is normalized x /= vecLength; y /= vecLength; z /= vecLength; sinSave = (float)sin(angle); cosSave = (float)cos(angle); oneMinusCos = 1.0f - cosSave; xx = x * x; yy = y * y; zz = z * z; xy = x * y; yz = y * z; zx = z * x; xs = x * sinSave; ys = y * sinSave; zs = z * sinSave; mMatrix[0] = (oneMinusCos * xx) + cosSave; mMatrix[4] = (oneMinusCos * xy) - zs; mMatrix[8] = (oneMinusCos * zx) + ys; mMatrix[12] = 0.0f; mMatrix[1] = (oneMinusCos * xy) + zs; mMatrix[5] = (oneMinusCos * yy) + cosSave; mMatrix[9] = (oneMinusCos * yz) - xs; mMatrix[13] = 0.0f; mMatrix[2] = (oneMinusCos * zx) - ys; mMatrix[6] = (oneMinusCos * yz) + xs; mMatrix[10] = (oneMinusCos * zz) + cosSave; mMatrix[14] = 0.0f; mMatrix[3] = 0.0f; mMatrix[7] = 0.0f; mMatrix[11] = 0.0f; mMatrix[15] = 1.0f; } /////////////////////////////////////////////////////////////////////////////// // Load a matrix with the Idenity matrix void gltLoadIdentityMatrix(GLTMatrix m) { static GLTMatrix identity = { 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f }; memcpy(m, identity, sizeof(GLTMatrix)); }Листинг 23.34. Код файла SphereWorld.h, моделирующего мир сфер
// 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); // Функция установки отсекающего объема void CrystalAndSpotExecuteMenu(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) Самолет с равномерным освещением" #include "JetShiny.h" // Упражнение 8: "8) Самолет с зеркальным отражением" #include "CrystalAndSpot.h" // Упражнение 9: "9) Рисование кристалла и прожектора" #include "JetShadow.h" // Упражнение 10: "10) Модель самолета и его тени" #include "SphereWorld.h" // Упражнение 11: "11) Освещенный мир сфер" //********************************************************** // Функция обратного вызова обработки выбора пользователя 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; case 8: ChangeSizeJetShiny(w, h); break; case 10: ChangeSizeJetShadow(w, h); break; case 11: ChangeSizeSphereWorld(w, h); break; } // Вызвать принудительно визуализацию glutPostRedisplay(); } //**************************************************** // Функция обратного вызова обработки выбора пользователя в подменю void CrystalAndSpotExecuteMenu(int choice) { xRot = yRot = 0; ChangeSizeCrystalAndSpot(w, h); switch(choice){ case 0: iShade = MODE_FLAT; break; case 1: iShade = MODE_SMOOTH; break; case 2: iTess = MODE_VERYLOW; break; case 3: iTess = MODE_MEDIUM; break; case 4: default: iTess = MODE_VERYHIGH; } // Устанавливаем режим и вызываем принудительно // функцию визуализации, где размещен // вызов функции рисования кристалла и прожектора ::choice = 9; // Вызвать принудительно визуализацию 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; case 8: RenderSceneJetShiny(); break; case 9: RenderSceneCrystalAndSpot(); break; case 10: RenderSceneJetShadow(); break; case 11: RenderSceneSphereWorld(); 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; case 8: ChangeSizeJetShiny(width, height); break; case 9: ChangeSizeCrystalAndSpot(width, height); break; case 10: ChangeSizeJetShadow(width, height); break; case 11: ChangeSizeSphereWorld(width, height); break; } } //********************************************************** // Обработчик события таймера void TimerFunc(int value) { glutPostRedisplay(); // Перерисовка сцены switch(::choice) { case 11: glutTimerFunc(3, TimerFunc, 1); break; default: glutTimerFunc(30, TimerFunc, 1); } } //********************************************************** // Управление с клавиатуры стрелками // для задания новых значений матрицы поворота void SpecialKeys(int key, int x, int y) { switch(::choice) { default: 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); } break; case 11: SpecialKeysSphereWorld(key); } // Вызвать принудительно визуализацию с помощью 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); // Для управления с клавиатуры // Создаем подменю для рисования кристалла и прожектора int CrystalAndSpot_menu = glutCreateMenu(CrystalAndSpotExecuteMenu); glutAddMenuEntry("Плоское затенение поверхностей", 0); glutAddMenuEntry("Гладкое (градиентное) затенение", 1); glutAddMenuEntry("Низкая тесселяция (крупные грани)", 2); glutAddMenuEntry("Средняя тесселяция (больше граней)", 3); glutAddMenuEntry("Высокая аппроксимация (много граней)", 4); // Создание меню и добавление опций выбора 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); glutAddMenuEntry("8) Самолет с зеркальным отражением", 8); glutAddSubMenu("9) Рисование кристалла и прожектора", CrystalAndSpot_menu); glutAddMenuEntry("10) Модель самолета и его тени", 10); glutAddMenuEntry("11) Освещенный мир сфер", 11); glutAttachMenu(GLUT_RIGHT_BUTTON);// Присоединяем // Конец создания меню glutMainLoop(); // Цикл сообщений графического окна }Листинг 23.35. Код подключения мира сфер в файле LightAndMaterial.cpp
-
Запустите приложение и выполните упражнение 11, результат должен быть примерно таким
-
Поуправляйте сценой с помощью клавиш-стрелок и попытайтесь разобраться с кодом
< Самостоятельная работа 21 || Самостоятельная работа 22: 123456789101112 || Самостоятельная работа 23 >