Опубликован: 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 >


