#include #include //====== Подключение заголовков библиотек OpenGL #include #include #include //====== Макроподстановка для изображения одной линии #define Line(x1,y1,x2,y2) \ glBegin(GL_LINES); \ glVertex2d ((x1),(y1)); \ glVertex2d ((x2),(y2)); \ glEnd(); //====== Реакция на сообщение WM_PAINT void __stdcall OnDraw() { //====== Стираем буфер кадра (framebuffer) glClear (GL_COLOR_BUFFER_BIT); //====== Выбираем черный цвет рисования glColor3f (0., 0., 0.); //=== В 1-м ряду рисуем 3 линии с разной штриховкой glEnable (GL_LINE_STIPPLE); glLineWidth (2.); glLineStipple (1, 0x0101); // dot Line (50., 125., 150., 125.); glLineStipple (1, 0x00FF); // dash Line (150., 125., 250., 125.); glLineStipple (1, 0x1C47); // dash/dot/dash Line (250., 125., 350., 125.); //====== Во 2-м ряду то же, но шире в 6 раз glLineWidth (6.); glLineStipple (1, 0x0101); // dot Line (50., 100., 150., 100.); glLineStipple (1, 0x00FF); // dash Line (150., 100., 250., 100.); glLineStipple (1, 0x1C47); // dash/dot/dash Line (250., 100., 350., 100.); //=== Во 3-м ряду 7 линий являются частями //=== полосы (strip). Учетверенный узор не прерывается glLineWidth (2.); glLineStipple (4, 0x1C47); // dash/dot/dash glBegin (GL_LINE_STRIP); for (int i = 1; i < 8; i++) glVertex2d (50.*i, 75.); glEnd(); //=== Во 4-м ряду 6 независимых, отдельных линий //=== Тот же узор, но он каждый раз начинается заново for (i = 1; i < 7; i++) { Line (50*i, 50, 50*(i+1), 50); } //====== Во 5-м ряду 1 линия с тем же узором glLineStipple (4, 0x1C47); // dash/dot/dash Line (50., 25., 350., 25.); glDisable (GL_LINE_STIPPLE); glFlush (); } //====== Реакция на WM_SIZE void __stdcall OnSize (int w, int h) { glViewport (0, 0, (GLsizei) w, (GLsizei) h); glMatrixMode (GL_PROJECTION); glLoadIdentity(); //====== Режим ортографической проекции gluOrtho2D (0.0, double(w), 0.0, double(h)); } //====== Настройки void Init() { //====== Цвет фона - белый glClearColor (1., 1., 1., 0.); //====== Нет интерполяции цвета при растеризации glShadeModel (GL_FLAT); } void main() { //=== Установка pixel-формата и подготовка окна OpenGL auxInitDisplayMode (AUX_SINGLE | AUX_RGB); auxInitPosition (200, 200, 550, 250); auxInitWindow("My Stipple Test"); Init(); auxReshapeFunc (OnSize); // Кого вызывать при WM_SIZE auxMainLoop(OnDraw); // Кого вызывать при WM_PAINT } GLubyte gSpade[] = // Узор - пики { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xf8, 0x1f, 0x00, 0x00, 0xf8, 0x01, 0xc0, 0x03, 0x80, 0x00, 0x70, 0x0e, 0x00, 0x00, 0x20, 0x04, 0x00, 0x00, 0x30, 0x0c, 0x00, 0x00, 0x10, 0x08, 0x00, 0x00, 0x18, 0x18, 0x00, 0x07, 0xc4, 0x23, 0xe0, 0x0f, 0xf8, 0x1f, 0xf0, 0x38, 0x1c, 0x38, 0x1c, 0x30, 0x00, 0x00, 0x0c, 0x60, 0x00, 0x00, 0x06, 0x60, 0x00, 0x00, 0x06, 0x60, 0x00, 0x00, 0x06, 0x60, 0x00, 0x00, 0x06, 0x60, 0x00, 0x00, 0x06, 0x30, 0x00, 0x00, 0x0c, 0x30, 0x00, 0x00, 0x0c, 0x18, 0x00, 0x00, 0x18, 0x0e, 0x00, 0x00, 0x70, 0x03, 0x00, 0x00, 0xc0, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x70, 0x0e, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x0c, 0x30, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00 }; GLubyte gStrip[] = // Другой узор - полоса { 0x66, 0x66, 0x66, 0x66, 0x33, 0x33, 0x33, 0x33, 0x66, 0x66, 0x66, 0x66, 0x33, 0x33, 0x33, 0x33, 0x66, 0x66, 0x66, 0x66, 0x33, 0x33, 0x33, 0x33, 0x66, 0x66, 0x66, 0x66, 0x33, 0x33, 0x33, 0x33, 0x66, 0x66, 0x66, 0x66, 0x33, 0x33, 0x33, 0x33, 0x66, 0x66, 0x66, 0x66, 0x33, 0x33, 0x33, 0x33, 0x66, 0x66, 0x66, 0x66, 0x33, 0x33, 0x33, 0x33, 0x66, 0x66, 0x66, 0x66, 0x33, 0x33, 0x33, 0x33, 0x66, 0x66, 0x66, 0x66, 0x33, 0x33, 0x33, 0x33, 0x66, 0x66, 0x66, 0x66, 0x33, 0x33, 0x33, 0x33, 0x66, 0x66, 0x66, 0x66, 0x33, 0x33, 0x33, 0x33, 0x66, 0x66, 0x66, 0x66, 0x33, 0x33, 0x33, 0x33, 0x66, 0x66, 0x66, 0x66, 0x33, 0x33, 0x33, 0x33, 0x66, 0x66, 0x66, 0x66, 0x33, 0x33, 0x33, 0x33, 0x66, 0x66, 0x66, 0x66, 0x33, 0x33, 0x33, 0x33, 0x66, 0x66, 0x66, 0x66, 0x33, 0x33, 0x33, 0x33, }; void __stdcall OnDraw() { //====== Стираем окно glClear (GL_COLOR_BUFFER_BIT); //====== Цвет фона (синеватый) glColor3f (0.3f, 0.3f, 1.); //=== Рисуем сначала unstippled rectangle (без узора) //=== Rect - это тоже полигон glRectf (20., 20., 115., 120.); glColor3f (1., 0., 0.); // Меняем цвет на красный glEnable (GL_POLYGON_STIPPLE); // Включаем штриховку glPolygonStipple (gStrip); // Задаем узор glRectf (120., 20., 215., 120.); // Рисуем glColor3f (0., 0., 0.); // Меняем цвет на черный glPolygonStipple (gSpade); // Меняем узор glRectf (220., 20., 315., 120.); glPolygonStipple (gStrip); // Меняем узор glColor3f (0., 0.6f, 0.3f); glRectf (320., 20., 415., 120.); //=== Готовимся заполнить более сложный, невыпуклый //=== (non convex) полигон glPolygonStipple (gSpade); glColor3d (0.6, 0.f, 0.3f); //====== Шесть вершин по три координаты float c[6][3] = { 420.,120.,0., 420.,70.,0., 470.,20.,0., 520., 70.,0., 520.,120.,0., 470.,100.,0. }; //=== Здесь мы специально выбираем non convex полигон, //=== чтобы увидеть как плохо с ним обходится OpenGL glBegin(GL_POLYGON); for (int i=0; i<6; i++) glVertex3fv(c[i]); glEnd(); glDisable (GL_POLYGON_STIPPLE); glFlush (); } void __stdcall OnDraw() { glClear (GL_COLOR_BUFFER_BIT); glColor3d (1., 0.4, 1.); //=== 2 угла, характеризующие звезду и //=== 2 характерные точки double pi = 4. * atan(1.), a1 = pi / 10., a2 = 3. * a1, x1 = cos(a1), y1 = sin(a1), x2 = cos(a2), y2 = sin(a2); //=== Мировые координаты вершин нормированной звезды double c[5][3] = { 0., 1., 0., -x2, -y2, 0., x1, y1, 0., -x1, y1, 0., x2, -y2, 0., }; //====== Оконные координаты for (int i=0; i<5; i++) { c[i][0] = 250 + 100*c[i][0]; c[i][1] = 100 + 100*c[i][1]; } //=== Режим заполнения полигона - скелетный glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); //=== Задаем вершины полигона glBegin(GL_POLYGON); for (i=0; i<5; i++) glVertex3dv(c[i]); glEnd(); glFlush(); } void __stdcall OnDraw() { glClear (GL_COLOR_BUFFER_BIT); glColor3d (1., 0.4, 1.); //====== Вогнутый шестиугольник, но мы зададим его //====== в виде двух четырехугольников float c[6][3] = { 200.,200.,0., 200.,100.,0., 250.,20.,0., 300.,100.,0., 300.,200.,0., 250.,100.,0., }; glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); glBegin(GL_QUADS); glVertex3fv(c[5]); glVertex3fv(c[0]); glVertex3fv(c[1]); glVertex3fv(c[2]); glVertex3fv(c[5]); glVertex3fv(c[2]); glVertex3fv(c[3]); glVertex3fv(c[4]); glEnd(); glFlush (); } //====== Углы поворотов изображения вокруг осей X и Y double gdAngleX, gdAngleY; //====== Сдвиги вдоль координат double gdTransX, gdTransY, gdTransZ = -4.; void __stdcall OnDraw() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //=== Будем пользоваться услугами матрицы моделирования glMatrixMode (GL_MODELVIEW); glLoadIdentity (); //=== Задаем смещение координат точек будущих примитивов glTranslated(gdTransX, gdTransY, gdTransZ); //=== Задаем вращение координат точек будущих примитивов glRotated(gdAngleY, 0.,1.,0.); glRotated(gdAngleX, 1.,0.,0.); //====== Координаты точек куба (центр его в нуле) static float v[8][3] = { -1, 1., -1., // 4 точки задней грани задаются 1., 1., -1., // в порядке против часовой стрелки 1., -1., -1., -1, -1., -1., -1, 1., 1., // 4 фронтальные точки -1., -1., 1., 1., -1., 1., 1, 1., 1. }; //====== 6 нормалей для 6-ти граней куба static double norm[6][3] = { 0., 0., -1., // Rear 0., 0., 1., // Front -1., 0., 0., // Left 1., 0., 0., // Right 0., 1., 0., // Top 0., -1., 0. // Bottom }; //====== Индексы вершин граней static GLuint id[6][4] = { 0,1,2,3, // Rear (обход CCW - counterclockwise) 4,5,6,7, // Front 0,3,5,4, // Left 7,6,2,1, // Right 0,4,7,1, // Top 5,3,2,6, // Bottom }; glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); glColor3d (1., 0.4, 1.); glBegin(GL_QUADS); //====== Долго готовились - быстро рисуем for (int i = 0; i < 6; i++) { glNormal3dv(norm[i]); for (int j = 0; j < 4; j++) glVertex3fv(v[id[i][j]]); } glEnd(); glFlush (); } glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); int Lights; glGetIntegerv(GL_MAX_LIGHTS, &Lights); __asm nop auxMouseFunc(AUX_LEFTBUTTON, AUX_MOUSELOC, OnLMouseMove); auxMouseFunc(AUX_RIGHTBUTTON, AUX_MOUSELOC, OnRMouseMove); auxMouseFunc(AUX_LEFTBUTTON, AUX_MOUSEDOWN, OnButtonDown); auxMouseFunc(AUX_RIGHTBUTTON, AUX_MOUSEDOWN, OnButtonDown); static void __stdcall OnButtonDown(AUX_EVENTREC *pEvent) { //====== Запоминаем координаты мыши giX = pEvent->data[AUX_MOUSEX]; giY = pEvent->data[AUX_MOUSEY]; } static void __stdcall OnLMouseMove(AUX_EVENTREC *pEvent) { //====== Узнаем текущие координаты int x = pEvent->data[AUX_MOUSEX]; int y = pEvent->data[AUX_MOUSEY]; //====== Изменяем углы поворота пропорционально //====== смещению мыши gdAngleX += (y - giY)/10.f; gdAngleY += (x - giX)/10.f; //====== Запоминаем координаты мыши giX = x; giY = y; } static void __stdcall OnRMouseMove(AUX_EVENTREC *pEvent) { int x = pEvent->data[AUX_MOUSEX]; int y = pEvent->data[AUX_MOUSEY]; //====== На сколько удалить или приблизить double dx = (x - giX)/200.f; double dy = (y - giY)/200.f; //====== Удаляем или приближаем gdTransZ += (dx + dy)/2.f; //====== Запоминаем координаты мыши giX = x; giY = y; } short x = pEvent->data[AUX_MOUSEX]; short y = pEvent->data[AUX_MOUSEY]; auxKeyFunc(AUX_DOWN, KeyDown); auxKeyFunc(AUX_UP, KeyUp); auxKeyFunc(AUX_LEFT, KeyLeft); auxKeyFunc(AUX_RIGHT, KeyRight); void __stdcall KeyDown() { gdTransY -= 0.1; // Сдвигаем изображение вниз } void __stdcall KeyUp() { gdTransY += 0.1; // Сдвигаем изображение вверх } void __stdcall KeyLeft() { gdTransX -= 0.1; // Сдвигаем изображение влево } void __stdcall KeyRight() { gdTransX += 0.1; // Сдвигаем изображение вправо } void DrawScene() { //====== Создаем новый список команд OpenGL glNewList(1,GL_COMPILE); //====== Сюда поместите код, рисующий куб, //====== начиная со строки static float v[8][3] = . . . . . . . //====== и заканчивая for (int j = 0; j < 4; j++) glVertex3fv(v[id[i][j]]); } glEnd(); glEndList(); } void __stdcall OnDraw() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode (GL_MODELVIEW); glLoadIdentity (); glTranslated(gdTransX, gdTransY, gdTransZ); glRotated(gdAngleY, 0.,1.,0.); glRotated(gdAngleX, 1.,0.,0.); //====== Воспроизводим команды из списка 1 glCallList(1); auxSwapBuffers(); } void Init() { glClearColor (1., 1., 1., 0.); //====== Включаем интерполяцию цветов полигона glShadeModel (GL_SMOOTH); glEnable(GL_DEPTH_TEST); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glEnable(GL_COLOR_MATERIAL); //====== Готовим сцену DrawScene(); } glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); glBegin(GL_QUADS); //====== Обновляем генератор случайных чисел srand(time(0)); //====== 6 граней куба for (int i = 0; i < 6; i++) { glNormal3dv(norm[i]); //====== 4 вершины одной грани for (int j = 0; j < 4; j++) { //====== Задаем различные цвета glColor3d (rand()%10/10., rand()%10/10., rand()%10/10.); glVertex3fv(v[id[i][j]]); } } glEnd(); glEndList(); void DrawScene() { static double //====== 2 характерные точки angle = 3. * atan(1.)/2.5, V = cos(angle), W = sin(angle), //====== 12 вершин икосаэдра (координаты x,y,z) v[12][3] = { {-V,0.,W}, {V,0.,W}, {-V,0.,-W}, {V,0.,-W}, {0.,W,V}, {0.,W,-V}, {0.,-W,V}, {0.,-W,-V},{W,V,0.}, {-W,V,0.}, {W,-V,0.}, {-W,-V,0.} }; //=== 20 граней икосаэдра, заданные индексами вершин static GLuint id[20][3] = { {0,1, 4}, {0,4, 9}, {9,4, 5}, {4,8, 5}, {4,1,8}, {8,1,10}, {8,10,3}, {5,8, 3}, {5,3, 2}, {2,3,7}, {7,3,10}, {7,10,6}, {7,6,11}, {11,6,0}, {0,6,1}, {6,10,1}, {9,11,0}, {9,2,11}, {9,5, 2}, {7,11,2} }; //====== Начинаем формировать список команд glNewList(1,GL_COMPILE); //====== Выбираем текущий цвет рисования glColor3d (1., 0.4, 1.); glBegin(GL_TRIANGLES); for (int i = 0; i < 20; i++) { //====== Грубый подход к вычислению нормалей glNormal3dv(v[id[i][0]]); glVertex3dv(v[id[i][0]]); glNormal3dv(v[id[i][1]]); glVertex3dv(v[id[i][1]]); glNormal3dv(v[id[i][2]]); glVertex3dv(v[id[i][2]]); } glEnd(); //====== Конец списка команд glEndList(); } //=== Нормирование вектора нормали (или любого другого) void Scale(double v[3]) { double d = sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]); if (d == 0.) { MessageBox(0,"Zero length vector","Error",MB_OK); return; } v[0] /= d; v[1] /= d; v[2] /= d; } void getNorm(double v1[3], double v2[3], double out[3]) { //====== Вычисляем координаты вектора нормали //====== по формулам векторного произведения out[0] = v1[1]*v2[2] - v1[2]*v2[1]; out[1] = v1[2]*v2[0] - v1[0]*v2[2]; out[2] = v1[0]*v2[1] - v1[1]*v2[0]; Scale(out); } void DrawScene() { static double angle = 3. * atan(1.)/2.5, V = cos(angle), W = sin(angle), v[12][3] = { {-V,0.,W}, {V,0.,W}, {-V,0.,-W}, {V,0.,-W}, {0.,W,V}, {0.,W,-V}, {0.,-W,V}, {0.,-W,-V},{W,V,0.}, {-W,V,0.}, {W,-V,0.}, {-W,-V,0.} }; static GLuint id[20][3] = { {0,1, 4}, {0,4, 9}, {9,4, 5}, {4,8, 5}, {4,1,8}, {8,1,10}, {8,10,3}, {5,8, 3}, {5,3, 2}, {2,3,7}, {7,3,10}, {7,10,6}, {7,6,11}, {11,6,0}, {0,6,1}, {6,10,1}, {9,11,0}, {9,2,11}, {9,5, 2}, {7,11,2} }; glNewList(1,GL_COMPILE); glColor3d (1., 0.4, 1.); glBegin(GL_TRIANGLES); for (int i = 0; i < 20; i++) { double d1[3], d2[3], norm[3]; for (int j = 0; j < 3; j++) { d1[j] = v[id[i][0]] [j] - v[id[i][1]] [j]; d2[j] = v[id[i][1]] [j] - v[id[i][2]] [j]; } //====== Вычисление и масштабирование нормали getNorm(d1, d2, norm); glNormal3dv(norm); glVertex3dv(v[id[i][0]]); glVertex3dv(v[id[i][1]]); glVertex3dv(v[id[i][2]]); } glEnd(); glEndList(); } //=== Команды OpenGL для изображения одного треугольника void setTria(double *v1, double *v2, double *v3) { glBegin(GL_TRIANGLES); //====== Нормаль и вершина задаются одним вектором glNormal3dv(v1); glVertex3dv(v1); glNormal3dv(v2); glVertex3dv(v2); glNormal3dv(v3); glVertex3dv(v3); glEnd(); } //====== Генерация внутренних треугольников void Split(double *v1, double *v2, double *v3) { //====== Промежуточные вершины double v12[3], v23[3], v31[3]; for (int i = 0; i < 3; i++) { //====== Можно не делить пополам, //====== так как будем нормировать v12[i] = v1[i]+v2[i]; v23[i] = v2[i]+v3[i]; v31[i] = v3[i]+v1[i]; } //====== Нормируем три новые вершины Scale(v12); Scale(v23); Scale(v31); //====== и рисуем четыре треугольника setTria(v1, v12, v31); setTria(v2, v23, v12); setTria(v3, v31, v23); setTria(v12,v23, v31); } void DrawScene() { static double angle = 3. * atan(1.)/2.5, V = cos(angle), W = sin(angle), v[12][3] = { {-V,0.,W}, {V,0.,W}, {-V,0.,-W}, {V,0.,-W}, {0.,W,V}, {0.,W,-V}, {0.,-W,V}, {0.,-W,-V},{W,V,0.}, {-W,V,0.}, {W,-V,0.}, {-W,-V,0.} }; static GLuint id[20][3] = { {0,1, 4}, {0,4, 9}, {9,4, 5}, {4,8, 5}, {4,1,8}, {8,1,10}, {8,10,3}, {5,8, 3}, {5,3, 2}, {2,3,7}, {7,3,10}, {7,10,6}, {7,6,11}, {11,6,0}, {0,6,1}, {6,10,1}, {9,11,0}, {9,2,11}, {9,5, 2}, {7,11,2} }; glNewList(1,GL_COMPILE); glColor3d (1., 0.4, 1.); glBegin(GL_TRIANGLES); for (int i = 0; i < 20; i++) Split (v[id[i][0]], v[id[i][1]], v[id[i][2]]); glEnd(); glEndList(); } void __stdcall KeyN() { //====== Изменяем способ вычисления нормалей gbSmooth = !gbSmooth; //====== Заново создаем список команд DrawScene(); } void setTria(double *v1, double *v2, double *v3) { glBegin(GL_TRIANGLES); //====== Если выбран способ точного вычисления нормали if (!gbSmooth) { //====== Правая тройка векторов double d1[3], d2[3], norm[3]; //====== Вычисляем координаты векторов //====== двух сторон треугольника for (int j = 0; j < 3; j++) { d1[j] = v1[j] - v2[j]; d2[j] = v2[j] - v3[j]; } //====== Вычисляем нормаль к плоскости //====== треугольника со сторонами d1 и d2 getNorm(d1, d2, norm); glNormal3dv(norm); glVertex3dv(v1); glVertex3dv(v2); glVertex3dv(v3); } else { //=== Неточное (приближенное) задание нормали glNormal3dv(v1); glVertex3dv(v1); glNormal3dv(v2); glVertex3dv(v2); glNormal3dv(v3); glVertex3dv(v3); } glEnd(); } void Split(double *v1, double *v2, double *v3, long depth) { double v12[3], v23[3], v31[3]; if (depth == 0) { //====== Рисование наименьших треугольников setTria(v1, v2, v3); //====== и выход из цепи рекурсивных вызовов return; } //====== Разбиение треугольника for (int i = 0; i < 3; i++) { v12[i] = v1[i]+v2[i]; v23[i] = v2[i]+v3[i]; v31[i] = v3[i]+v1[i]; } //====== Дотягивание до сферы Scale(v12); Scale(v23); Scale(v31); //====== Рекурсивное разбиение на //====== четыре внутренних треугольника Split(v1, v12, v31, depth-1); Split(v2, v23, v12, depth-1); Split(v3, v31, v23, depth-1); Split(v12, v23, v31, depth-1); } void __stdcall KeySpace() { //====== Флаг роста числа разбиений static bool bGrow = true; //====== Продолжаем разбивать до глубины 4 if (bGrow && giDepth < 4) { giDepth += 1; } //====== Смена знака при глубине 4 else if (giDepth > 0) { bGrow = false; giDepth -= 1; } //====== Смена знака при глубине 0 else { bGrow = true; giDepth += 1; } DrawScene(); } //====== Если существует 1-й список, if (glIsList(1)) //====== то освобождаем память glDeleteLists(1,1); #include #include #include #include #include #include #include #include #include const UINT gnRings = 40; // Количество колец (широта) const UINT gnSects = 40; // Количество секций (долгота) //====== Общее количество треугольников const UINT gnTria = (gnRings+1) * gnSects * 2; //====== Общее количество вершин const UINT gnVert = (gnRings+1) * gnSects + 2; //====== Два цвета вершин const COLORREF gClr1 = RGB(0, 255, 0); const COLORREF gClr2 = RGB(0, 0, 255); const double gRad = 1.5; // Радиус сферы const double gMax = 5.; // Амплитуда сдвига const double PI = atan(1.)*4.; // Число пи //====== Точка 3D-пространства class CPoint3D { public: float x, y, z; // Координаты точки //====== Конструктор по умолчанию CPoint3D () { x = y = z = 0; } //====== Конструктор с параметрами CPoint3D (double c1, double c2, float c3) { x = float(c1); z = float(c2); y = float(c3); } //====== Операция присвоения CPoint3D& operator=(const CPoint3D& pt) { x = pt.x; z = pt.z; y = pt.y; return *this; } //====== Операция сдвига в пространстве CPoint3D& operator+=(const CPoint3D& pt) { x += pt.x; y += pt.y; z += pt.z; return *this; } //====== Конструктор копирования CPoint3D (const CPoint3D& pt) { *this = pt; } }; //====== Данные о вершине геометрического примитива struct VERT { CPoint3D v; // Координаты вершины CPoint3D n; // Координаты нормали DWORD c; // Цвет вершины }; struct TRIA { //====== Индексы трех вершин треугольника, //====== выбираемых из массива вершин типа VERT //====== Порядок обхода - против часовой стрелки int i1; int i2; int i3; }; //====== Вектор углов вращения вокруг трех осей CPoint3D gSpin; //====== Вектор случайной девиации вектора gSpin CPoint3D gShift; inline double Rand(double x) { //====== Случайное число в диапазоне (-x, x) return x - (x + x) * rand() / RAND_MAX; } void __stdcall OnDraw() { glClear(GL_COLOR_BUFFER_BIT); //=== Сейчас текущей является матрица моделирования glLoadIdentity(); //====== Учет вращения glRotated(gSpin.x, 1., 0, 0.); glRotated(gSpin.y, 0., 1., 0.); glRotated(gSpin.z, 0., 0., 1.); //====== Вызов списка рисующих команд glCallList(1); //====== Подготовка следующей позиции сферы gSpin += gShift; //====== Смена буферов auxSwapBuffers(); } void Init() { //=== Цвет фона (на сей раз традиционно черный) glClearColor (0., 0., 0., 0.); //====== Включаемаем необходимость учета света glEnable(GL_LIGHTING); //====== Включаемаем первый и единственный источник света glEnable(GL_LIGHT0); //====== Включаем учет цвета материала объекта glEnable(GL_COLOR_MATERIAL); // Вектор для задания различных параметров освещенности float v[4] = { 0.05f, 0.05f, 0.05f, 1.f }; //=== Сначала задаем величину окружающей освещенности glLightModelfv(GL_LIGHT_MODEL_AMBIENT, v); //====== Изменяем вектор v[0] = 0.9f; v[1] = 0.9f; v[2] = 0.9f; //====== Задаем величину диффузной освещенности glLightfv(GL_LIGHT0, GL_DIFFUSE, v); //======= Изменяем вектор v[0] = 0.6f; v[1] = 0.6f; v[2] = 0.6f; //====== Задаем отражающие свойства материчала glMaterialfv(GL_FRONT, GL_SPECULAR, v); //====== Задаем степень блесткости материала glMateriali(GL_FRONT, GL_SHININESS, 40); //====== Изменяем вектор v[0] = 0.f; v[1] = 0.f; v[2] = 1.f; v[3] = 0.f; //====== Задаем позицию источника света glLightfv(GL_LIGHT0, GL_POSITION, v); //====== Переключаемся на матрицу проекции glMatrixMode(GL_PROJECTION); glLoadIdentity(); //====== Задаем тип проекции gluPerspective(45, 1, .01, 15); //=== Сдвигаем точку наблюдения, отодвигаясь от //=== центра сцены в направлении оси z на 8 единиц gluLookAt(0, 0, 8, 0, 0, 0, 0, 1, 0); //====== Переключаемся на матрицу моделирования glMatrixMode(GL_MODELVIEW); //====== Включаем механизм учета ориентации полигонов glEnable(GL_CULL_FACE); //====== Не учитываем обратные поверхности полигонов glCullFace(GL_BACK); //====== Настройка OpenGL на использование массивов glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); glEnableClientState(GL_COLOR_ARRAY); //====== Захват памяти под динамические массивы VERT *Vert = new VERT[gnVert]; TRIA *Tria = new TRIA[gnTria]; //====== Создание изображения Sphere(Vert, Tria); //====== Задание адресов трех массивов (вершин, //====== нормалей и цветов), //====== а также шага перемещения по ним glVertexPointer(3, GL_FLOAT, sizeof(VERT), &Vert->v); glNormalPointer(GL_FLOAT, sizeof(VERT), &Vert->n); glColorPointer(3, GL_UNSIGNED_BYTE, sizeof(VERT), &Vert->c); srand(time(0)); // Подготовка ГСЧ gShift = CPoint3D (Rand(gMax),Rand(gMax),Rand(gMax)); //====== Формирование списка рисующих команд glNewList(1, GL_COMPILE); glDrawElements(GL_TRIANGLES, gnTria*3, GL_UNSIGNED_INT, Tria); glEndList(); //== Освобождение памяти, так как список сформирован delete [] Vert; delete [] Tria; } void Sphere(VERT *v, TRIA* t) { //====== Формирование массива вершин //====== Северный полюс v[0].v = CPoint3D (0, gRad, 0); v[0].n = CPoint3D (0, 1, 0); v[0].c = gClr2; //====== Индекс последней вершины (на южном полюсе) UINT last = gnVert - 1; //====== Южный полюс v[last].v = CPoint3D (0, -gRad, 0); v[last].n = CPoint3D (0, -1, 0); v[last].c = gnVert & 1 ? gClr2 : gClr1; //====== Подготовка констант double da = PI / (gnRings + 2.), db = 2. * PI / gnSects, af = PI - da/2., bf = 2. * PI - db/2.; //=== Индекс вершины, следующей за северным полюсом UINT n = 1; //=== Цикл по широтам for (double a = da; a < af; a += da) { //=== Координата y постоянна для всего кольца double y = gRad * cos(a), //====== Вспомогательная точка xz = gRad * sin(a); //====== Цикл по секциям (долгота) for (double b = 0.; b < bf; n++, b += db) { // Координаты проекции в экваториальной плоскости double x = xz * sin(b), z = xz * cos(b); //====== Вершина, нормаль и цвет v[n].v = CPoint3D (x, y, z); v[n].n = CPoint3D (x / gRad, y / gRad, z / gRad); v[n].c = n & 1 ? gClr1 : gClr2; } } //====== Формирование массива индексов //====== Треугольники вблизи полюсов for (n = 0; n < gnSects; n++) { //====== Индекс общей вершины (северный полюс) t[n].i1 = 0; //====== Индекс текущей вершины t[n].i2 = n + 1; //====== Замыкание t[n].i3 = n == gnSects - 1 ? 1 : n + 2; //====== Индекс общей вершины (южный полюс) t[gnTria-gnSects+n].i1 = gnVert - 1; t[gnTria-gnSects+n].i2 = gnVert - 2 - n; t[gnTria-gnSects+n].i3 = gnVert - 2 - ((1 + n) % gnSects); } //====== Треугольники разбиения колец //====== Вершина, следующая за полюсом int k = 1; //====== gnSects - номер следующего треугольника n = gnSects; for (UINT i = 0; i < gnRings; i++, k += gnSects) { for (UINT j = 0; j < gnSects; j++, n += 2) { //======= Индекс общей вершины t[n].i1 = k + j; //======= Индекс текущей вершины t[n].i2 = k + gnSects + j; //======= Замыкание t[n].i3 = k + gnSects + ((j + 1) % gnSects); //======= То же для второго треугольника t[n + 1].i1 = t[n].i1; t[n + 1].i2 = t[n].i3; t[n + 1].i3 = k + ((j + 1) % gnSects); } } } void __stdcall OnSize(GLsizei w, GLsizei h) { glViewport(0, 0, w, h); } void main() { auxInitDisplayMode(AUX_RGB | AUX_DOUBLE); auxInitPosition(10, 10, 512, 512); auxInitWindow("Vertex Array"); Init(); auxReshapeFunc(OnSize); auxIdleFunc(OnDraw); auxMainLoop(OnDraw); }