Движение луча света по поверхности Безье / Курсовик по КГ
.docМинистерство образования и науки Российской Федерации
Санкт-Петербургский государственный электротехнический университет «ЛЭТИ»
кафедра математического обеспечения ЭВМ
Пояснительная записка
к курсовой работе по дисциплине «Компьютерная графика»
«Движение луча света по поверхности Безье»
Выполнил: Рыжок М. гр. 3341
Проверил: Ларионова О.Г.
Санкт-Петербург 2007
Курсовая работа.
Движение луча света по поверхности Безье
Цель работы: Изучить представление в компьютерной графике математические модели трехмерных поверхностей, в частности, поверхностей Безье, и способов их визуализации.
Задание на курсовую работу: разработать программу, осуществляющую имитацию движения луча по поверхности Безье. Программа должна обладать дружественным интерфейсом и предоставлять пользователю возможность влиять на свойства поверхности и луча.
Предварительные сведения
Практическое использование в различных областях науки и техники различных типов поверхностей, таких как бикубическая поверхность Кунса или кубических сплайновых кривых затрудняется необходимостью задания точной, интуитивно неочевидной математической информации, например, координат точек, касательных векторов и векторов кручения. Большинство этих проблем можно преодолеть, если использовать математический аппарат поверхностей Безье.
Поверхности Безье являются обобщением понятии кривых Безье к трехмерному случаю. Декартово или тензорное произведение поверхностей Безье задается в виде:
, где К и J есть базисные функции Бернштейна в параметрических направлениях u и w: , , а элементы Bij являются вершинами задающей полигональной сетки. Индексы n и m на единицу меньше числа многогранников в направлениях u и w соответственно.
Из-за того, что для смешивающих функций используется базис Бернштейна, многие свойства поверхности известны:
-
Степень поверхности в каждом параметрическом направлении на единицу меньше числа вершин задающего многоугольника в этом направлении.
-
Гладкость поверхности в каждом параметрическом направлении на 2 единицы меньше числа вершин задающего многоугольника в этом направлении
-
Поверхность отображает в общем виде форму задающей полигональной сетки
-
Совпадают только угловые точки задающей полигональной сетки и поверхности
-
Поверхность содержится внутри выпуклой оболочки задающей полигональной сетки.
-
Поверхность инварианта относительно аффинного преобразования
-
Каждая из граничных линий поверхности Безье является кривой Безье.
В матричном виде декартово произведение поверхности Безье задается преобразованием :
Здесь U = [un, un-1, … u1, 1]
W = [wn, wn-1, …w1, 1]T
, N и M вычисляются по формулам
Для специального случая бикубической поверхности Безье размера 4*4 уравнение сокращается до:
Поверхность Безье не обязательно должна быть квадратной. Для сетки размера 5*3 уравнение превращается в:
На рисунке 1 представлена бикубическая поверхность Безье, на рисунке 2 – поверхность 5*3
Рисунок 1 Рисунок 2
Поверхности Безье связаны со многими другими геометрическими моделями, например, поверхностями Кунса, рассмотрение которых остается за пределами данной работы.
Описание интерфейса программы.
Программа с помощью матричных преобразований создает и визуализирует поверхность Безье на основе полигональной сетки. Пользователю предоставляется возможность совершать следующие действия с помощью клавиатуры:
-
Перемещение поверхности в пространстве (клавиши ‘a’ и ‘d’ – вправо-влево, ‘w’ и ‘s’ – вверх-вниз, ‘e’и ‘r’ – вперед-назад).
-
Визуализация каркасной сетки поверхности и непрерывного изображения, переключение между ними (клавиша ‘l’)
-
Включение \ выключение источника света (клавиша ‘p’)
-
Увеличение \ уменьшение количества полигональных узлов базисной сетки:(клавиши ‘n’ и ‘m’ в одном направлении, клавиши ‘h’ и ‘j’ – в другом направлении).
-
Выбор цвета источника света:
-
Клавиша ‘1’ – красный
-
Клавиша ‘2’ – зеленый
-
Клавиша ‘3’ – синий
-
Клавиша ‘4’ – желтый
-
Клавиша ‘5’ – фиолетовый
-
Клавиша ‘6’ – голубой
-
Клавиша ‘7’ – белый
-
-
Расширение и сужение угла прожектора (клавиши ‘8’ и ‘9’)
-
Увеличение и уменьшение яркости цвета (клавиши ‘+’ и ‘-’)
-
Увеличение и уменьшение скорости вращения (клавиши ‘f’ и ‘F’)
-
Поворот оси вращения (клавиши ‘x’ и ‘X’ изменяют наклон оси вращения относительно оси абсцисс, ‘y’ и ‘Y’ – относительно оси ординат, ‘z’ и ‘Z’ – относительно оси апликат).
Примеры изображения каркасной сетки поверхности Безье
Примеры изображения луча разных цветов и плсщади на поверхности Безье
Поверхность Безье: измененная полигональная сетка
Пояснение пользователю
Приложение
Текст программы на языке С++ с использованием библиотеки OpenGL
#include "windows.h"
#include <GL\glut.h>
#include "matrix.h"
#include "curves.h"
#include "stdio.h"
float xt = 0.0f;
float yt = 0.0f;
float zt = 0.0f;
float h = 1.0f;
GLfloat light_amb[] = {0.0f, 1.0f, 0.4f, 1.0f};
GLfloat light_diff[] = {0.0f, 0.0f, 0.3f, 1.0f};
GLfloat light_spec[] = {0.3f, 0.8f, 0.3f, 0.5f};
GLfloat light_pos[] = {0,0,0,1};
float amplif = 1.0; //light amplification
float spot_cutoff = 180; //light spot cutoff
float rotatus[] = {1.0, 0.0, 0.0};
//create control point for patch
Point CP[16];
CCubicCurve curves[4]; //four curves
CCubicPatch patch;
void InitCurves()
{
CP[0].x = 1.0f;
CP[0].y = 1.0f;
CP[0].z = 1.0f;
CP[1].x = 4.0f;
CP[1].y = 2.0f;
CP[1].z = 0.0f;
CP[2].x = 8.0f;
CP[2].y =-2.0f;
CP[2].z = 0.0f;
CP[3].x = 12.0f;
CP[3].y = 0.0f;
CP[3].z = 0.0f;
CP[4] = CP[0];
CP[4].z += 10.0f;
CP[5] = CP[1];
CP[5].y = -20.0f;
CP[5].z += 10.0f;
CP[6] = CP[2];
CP[6].y = 10.0f;
CP[6].z += 10.0f;
CP[7] = CP[3];
CP[7].z += 10.0f;
CP[7].x += 2.0f;
CP[8] = CP[0];
CP[8].z += 20.0f;
CP[9] = CP[1];
CP[9].y += -15.0f;
CP[9].x = -1.0f;
CP[9].z += 20.0f;
CP[10] = CP[2];
CP[10].z += 20.0f;
CP[11] = CP[3];
CP[11].z += 20.0f;
CP[12] = CP[0];
CP[12].z += 30.0f;
CP[13] = CP[1];
CP[13].z += 30.0f;
CP[14] = CP[2];
CP[14].z += 30.0f;
CP[15] = CP[3];
CP[15].z += 30.0f;
patch.GeneratePatch(CP);
Matrix4x1 p1, p2, p3, p4;
p1.M[0] = -7.0f;
p1.M[1] = 2.0f;
p1.M[2] = 0.0f;
p2.M[0] = -7.0f;
p2.M[1] = 2.0f;
p2.M[2] = 2.0f;
p3.M[0] = -7.0f;
p3.M[1] = 2.0f;
p3.M[2] = 3.0f;
p4.M[0] = -7.0f;
p4.M[1] = 2.0f;
p4.M[2] = 4.0f;
curves[0].GenerateBezierCoefficients(p1,p2,p3,p4);
//subdivide curve
curves[0].SubdivideBezierCurve(&curves[1], &curves[2]);
//give subdiveded curves another color
curves[1].SetColor(1,0,0,0.5f);
curves[2].SetColor(0,1,0,0.5f);
curves[1].SubdivideBezierCurve(&curves[0], &curves[3]);
curves[0].SetColor(1,1,1,0.5f);
curves[3].SetColor(1,1,0,0.5f);
}
void lightcolor(float R = 0.0f, float G = 0.0f, float B = 0.0f)
{
if (R > 1.0 || R < 0.0 || G > 1.0 || G < 0.0 || B > 1.0 || B < 0.0)
return;
light_amb[0] = R;
light_amb[1] = G;
light_amb[2] = B;
light_diff[0] = R;
light_diff[1] = G;
light_diff[2] = B;
glLightfv(GL_LIGHT0, GL_AMBIENT, light_amb);
glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diff);
}
void reshape(int w, int h)
{
glViewport(0,0,w,h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60, 1, 0.1, 200);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0,-10,50, 0,-10,0, 0,1,0);
glLightfv(GL_LIGHT0, GL_POSITION, light_pos);
}
void keyboard(unsigned char key, int x, int y)
{
static bool line_on = false;
switch (key)
{
case 'l':
if (line_on)
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
else
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
line_on = !line_on;
break;
case 'a':
xt -= 1.0f;
break;
case 'd':
xt += 1.0f;
break;
case 'w':
yt +=1.0f;
break;
case 's':
yt -=1.0f;
break;
case 'e':
zt -= 1.0f;
break;
case 'r':
zt += 1.0f;
break;
case 'n':
patch.ChangeEval(TM_S_EVALS, -1);
break;
case 'm':
patch.ChangeEval(TM_S_EVALS, 1);
break;
case 'h':
patch.ChangeEval(TM_CURVE_EVALS, -1);
break;
case 'j':
patch.ChangeEval(TM_CURVE_EVALS, 1);
break;
case 'p':
{
static bool light = false;
if (light)
glDisable(GL_LIGHTING);
else
glEnable(GL_LIGHTING);
patch.ToggleNormals();
light = !light;
}break;
case '1':
{ lightcolor(1, 0, 0); break;}
case '2':
{ lightcolor(0, 1, 0); break;}
case '3':
{ lightcolor(0, 0, 1); break;}
case '4':
{ lightcolor(1, 1, 0); break;}
case '5':
{ lightcolor(1, 0, 1); break;}
case '6':
{ lightcolor(0, 1, 1); break;}
case '7':
{ lightcolor(1, 1, 1); break;}
case '8':
{
spot_cutoff -= 10;
glLightf(GL_LIGHT0,GL_SPOT_CUTOFF, spot_cutoff);
break;
}
case '9':
{
spot_cutoff += 10;
glLightf(GL_LIGHT0,GL_SPOT_CUTOFF, spot_cutoff);
break;
}
case '+':
{
amplif -= 0.1;
glLightfv(GL_LIGHT0, GL_CONSTANT_ATTENUATION, &lif);
break;
}
case '-':
{
amplif += 0.1;
glLightfv(GL_LIGHT0, GL_CONSTANT_ATTENUATION, &lif);
break;
}
case 'f':{h = h*2; break;}
case 'F':{h = h/2.0; break;}
case 'x':
{
if (rotatus[0] < 1)
rotatus[0] += 0.1f;
break;
}
case 'X':
{
if(rotatus[0] > 0)
rotatus[0] -= 0.1f;
break;
}
case 'y':
{
if (rotatus[1] < 1)
rotatus[1] += 0.1f;
break;
}
case 'Y':
{
if (rotatus[1] > 0)
rotatus[1] -= 0.1f;
break;
}
case 'z':
{
if (rotatus[2] < 1)
rotatus[2] += 0.1f;
break;
}
case 'Z':
{
if (rotatus[2] > 0)
rotatus[1] -= 0.1f;
break;
}
case 27:
exit(0);
break;
default:
break;
}
glutPostRedisplay();
}
void display()
{
static float rot = 0;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();
//allow the user to move the patch for further examination
glTranslatef(-xt, -yt, -zt);
glRotatef(rot, rotatus[0], rotatus[1], rotatus[2]);
patch.Draw();
glPopMatrix();
glFlush();
glutSwapBuffers();
if (rot >= 360.0f)
rot -= 360.0f;
rot += h;
}
void init()
{
glClearColor(0.0f, 0.0f, 0.0f, 0.5f);
glEnable(GL_DEPTH_TEST);
glColor3f(0,1,0);
glLineWidth(1);
InitCurves();
glDisable(GL_LIGHTING); //is turned on by the user
glEnable(GL_LIGHT0);
GLfloat amb[] = {1,1,1,0.5f};
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, amb);
//init lights
glLightfv(GL_LIGHT0, GL_AMBIENT, light_amb);
glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diff);
glLightfv(GL_LIGHT0, GL_SPECULAR, light_spec);
glLightf(GL_LIGHT0,GL_SPOT_CUTOFF, spot_cutoff);
glLightfv(GL_LIGHT0, GL_CONSTANT_ATTENUATION, &lif);
}
void idle()
{
glutPostRedisplay();
}
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitWindowPosition(100,100);
glutInitWindowSize(400,400);
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
glutCreateWindow("Bezie Curve Demo - By thoooms");
printf("\n\n\n-------------\nBezie Curve Demo - \n-------------");
printf("\n'a' and 'd':\t x axis movement");
printf("\n'w' and 's':\t y axis movement");
printf("\n'e' and 'r':\t z axis movement");
printf("\n'l':\t\t switches between wireframe and solid rendering");
printf("\n'p':\t\t Enables/Disables the calculation of normals and the lighting");
printf("\n'n' and 'm':\t Changes the number of curves used to create the triangles");
printf("\n'h' and 'j':\t Changes the number of evaluations used to make each curve");
printf("\n'1' - '7' :\t Light an object a color");
printf("\n'8':\t : Cut off the entrance angle");
printf("\n'9':\t : Extend tht entrance angle");
printf("\n'+':\t : Add the brightness");
printf("\n'-':\t : Delete the brightness");
printf("\n'f' and 'F':\t Increase and decrease a rotate speed");
printf("\n'x' and 'X':\t Increase and decrease a rotate angle around X axe");
printf("\n'y' and 'Y':\t Increase and decrease a rotate angle around Y axe");
printf("\n'z' and 'Z':\t Increase and decrease a rotate angle around Z axe");
init();
glutDisplayFunc(display);
glutKeyboardFunc(keyboard);
glutReshapeFunc(reshape);
glutIdleFunc(idle);
glutMainLoop();
return 0;
}
Выводы: В процессе выполнения курсовой работы были освоены навыки в представлении полигональных моделей, в частности, поверхностей Безье для аппроксимации и визуализации трехмерных поверхностей.
Список использованных источников
-
Д.Роджерс, Дж.Адамс. Математические основы машинной графики, Москва, «Мир», 2001г.
-
Ресурсы сайта alglib.source.ru