Разработка алгоритма и программы закрашивания граней методом Фонга
Анализирование аппроксимации Фонга как метода для точного затенения полигонов, её математическое описание и алгоритм создания. Практическая демонстрация реализации затенения с помощью полигональной аппроксимации. Проект сферы, созданный по методу Фонга.
Рубрика | Программирование, компьютеры и кибернетика |
Вид | курсовая работа |
Язык | русский |
Дата добавления | 04.02.2014 |
Размер файла | 439,0 K |
Отправить свою хорошую работу в базу знаний просто. Используйте форму, расположенную ниже
Студенты, аспиранты, молодые ученые, использующие базу знаний в своей учебе и работе, будут вам очень благодарны.
Размещено на http://www.allbest.ru/
Размещено на http://www.allbest.ru/
Минобрнауки России
Федеральное государственное бюджетное образовательное учреждение высшего профессионального образования «Санкт-Петербургский государственный технологический институт (технический университет)»
УГС: 230000 Информатика и вычислительная техника
Специальность: 230104 Системы автоматизированного проектирования
Факультет информационных технологий и управления
Кафедра систем автоматизированного проектирования и управления
Учебная дисциплина: геометрическое моделирование в САПР
Курс 4, группа 4893
КУРСОВАЯ РАБОТА
Тема: «Разработка алгоритма и программы закрашивания граней методом Фонга»
Выполнил: Рогов Д.В
Санкт-Петербург
2013
Оглавление
1. Цель курсового проектирования
2. Аналитический обзор
3. Дневник выполнения
4. Анализ
Выводы
Литература
ПРИЛОЖЕНИЕ A
1. Цель курсового проектирования
Целью курсового проектирования является изучение, а также визуализация метода закрашивания Фонга с помощью трёхмерной графической библиотеки OpenGL.
2. Аналитический обзор
Аппроксимации Фонга, или затенение по Фонгу (Phong shading), носят название по имени своего изобретателя - Ву Тонг Фонга (Wu Tong Phong). Этот метод дает более точные результаты при затенении полигонов по сравнению с затенением Гуро. Суть этих аппроксимаций заключается в определении нормали к поверхности в каждой вершине полигона и дальнейшей интерполяции вектора по всему полигону поверхности. Далее для каждого пикселя необходимо вычислить значение яркости, основываясь на значениях вектора нормали.
На самом деле, этот процесс занимает очень много времени, и вряд ли его можно считать одним из удобных методов просчета затенения для игр, рассчитанных на средний домашний компьютер. Поэтому большинство компьютерных программ, сулящих использование затенения по Фонгу в реальном времени, на самом деле используют "подделку" - значительно упрощенный вариант аппроксимаций. Такой вариант позволяет достичь приемлемых результатов и при этом он значительно быстрее.
Затенение по Фонгу - это достаточно популярный метод для реализации затенения, особенно в программах, применяющих non-realtime rendering, например, 3D Studio. Однако, несмотря на то, что этот метод значительно точнее затенения Гуро, он по-прежнему не является физически точным.аппроксимация затенение алгоритм
Затенение по Фонгу - это логичная реализация физической модели света, которую мы рассмотрели ранее. И если вы недостаточно внимательно отнеслись к ней, вернитесь еще раз, т. к без нее некоторые аспекты дальнейшего изложения будут казаться непонятными. Каждый одиночный пиксел имеет свое собственное значение яркости, тщательно просчитанное при использовании интерполированного вектора нормали.
Просчет затенения по Фонгу включает в себя:
· вычисление двух квадратных корней
· реализацию двух операций деления
· четырех операций умножения
и это не считая значительного количества операций сложения на каждый пиксел. Более того, они не являются целочисленными. Сравните это с единственной операцией сложения на пиксель при затемнении Гуро и вы поймете, почему этот метод столь медленный.
Алгоритм метода Фонга
1.Определение нормали к граням
2.По нормалям к граням определяются нормали в вершинах. В каждой точке закрашиваемой грани определяется интерполированный вектор нормали
3.Цвет каждой точки грани вычисляется в соответствии с направлением интерполированного вектора нормали и согласно выбранной модели отражения света
Кроме интерполяции нормали, в методе Фонга есть ещё один существенный момент. Интенсивность отражения света рассчитывается для каждой точки полигона индивидуально, а не интерполяцией интенсивностей вершин, как в методе Гуро.
Математическое описание метода
Опишем основную модель вычисления освещения, составляющую "фундаментальную основу" любой современной 3D-графики. Итак, у нас есть некоторая поверхность, освещенная светом (см. рис.). По Фонгу, цвет участка поверхности считается раздельно по каждому из цветовых каналов (красному, синему и зеленому) и складывается из трех компонентов: фонового освещения, имитирующего естественный рассеянный свет помещения, а также одинакового для всех точек поверхности диффузного отражения (рассеянного света, отраженного от поверхности) и зеркального отражения (имитирующего направленное отражение). Разберемся с каждым из слагаемых.
Фоновое освещение (ambient) рассчитывается по формуле Ia = kaLa. Теоретически, в сцене оно имитирует рассеянный свет, не имеющий конкретного источника. Поскольку центра и направления у него нет, то оно совершенно одинаково для всех точек поверхности. La в формуле - яркость этого света, ka - коэффициент светового отражения, показывающий, какая часть энергии отражается объектом (чем коэффициент меньше, тем объект темнее). На практике фоновое освещение используется, для того чтобы подсветить излишне темные участки.
Диффузное отражение (diffuse) соответствует отражению света от неровной поверхности. Подобная поверхность рассеивает падающий на нее свет практически равномерно по всем направлениям: с какой стороны на нее не гляди, выглядеть будет одинаково. Однако, в отличие от фонового освещения, диффузное отражение учитывает направление на источник света. Точнее, согласно закону Ламберта, яркость участка поверхности определяется только вертикальным компонентом падающего света, или, в математической форме
Id = kd(l,n)Ld
Здесь Ld - яркость источника света, kd - коэффициент отражения, l - вектор направления на источник света, n - вектор нормали (перпендикуляр к поверхности). Иногда учитывают квадратичное убывание яркости при удалении источника света от поверхности: это дает дополнительный коэффициент (a+bd+cd2)-1, где d - расстояние до источника света; a, b, c - эмпирически подбираемые (для большей естественности) коэффициенты.
Без диффузного отражения изобразить хоть какое-то освещение невозможно. Но изюминка кроется в последнем компоненте - зеркальном (specular) отражении, учитывающем не только направление на источник света, но и местоположение наблюдателя. Зеркальное отражение, как и следует из названия, концентрируется вдоль одного конкретного направления. Например: пусть r - "вектор отражения", лежащий в той же плоскости, что n и l, и образующий с n тот же угол, что и l, но только лежащий "по другую сторону" от n. Проще говоря, r - вектор, соответствующий "школьному" закону "угол падения равен углу отражения". Тогда полагают, что доля отраженной в сторону наблюдателя энергии пропорциональна (r,v)a, где a - "зеркальный коэффициент" отражения; v - вектор, направленный из точки на наблюдателя. Итого:
Is= ks(r,v)a)Ls
Просуммировав, получим стандартную модель Фонга:
I = (a+bd+cd2)-1(kd Ld (l,n) + ks Ls (r,v)a) + kaLa
Ее хватает для любых практических применений. Для расчетов, конечно, формула слишком сложна, и ее так или иначе упрощают или сводят расчет для всей поверхности к расчету по небольшому набору точек и интерполяции цвета поверхности на их основе (модель Гуро).
3. Дневник выполнения
Для демонстрации того, как на практике реализуются различные методы закрашивания криволинейных поверхностей в графической системе, следовало бы использовать сферу. Однако объект этого типа в OpenGL непосредственно не поддерживается. В библиотеках утилит GL (GLU) и инструментальных средств GL (GLUT) имеются различные варианты аппроксимации сферы. В первой используется квадратичная аппроксимация, а во второй -- полигональная.
В этом разделе будет рассмотрен упрощенный алгоритм полигональной аппроксимации, на основе которого мы разработаем программу и продемонстрируем, как параметры закрашивания связываются в программе с полигональной аппроксимацией криволинейных поверхностей. Будем использовать методику рекурсивного разбиения, которая позволяет аппроксимировать кривые и криволинейные поверхности с любой заданной точностью.
Начнем мы с тетраэдра, хотя можно было бы начать с любого правильного многогранника, гранями которого являются треугольники. Правильный тетраэдр имеет четыре грани, каждая из которых -- равносторонний треугольник, и определяется четырьмя вершинами. Начнем со следующего массива вершин: (0, 0, 1), (0, /3, - 1/3), (-/3, - /3, - 1/3), (/3, - /3, - 1/3).
Все четыре вершины лежат на сферической поверхности единичного радиуса, центр которой находится в начале координат.
Начальное приближение вычертим в режиме построения проволочного изображения. Определим в программе глобально четыре вершины, используя тип переменных point,
point v[4]={{0.0; 0.0, 1.0}, {0.0, 0.942809, -0.333333},
{-0.816497, -0.471405, -0.333333},
{0.816497, -0.471405, -0.333333}};
Для вычерчивания треугольника воспользуемся функцией triangle(), текст которой представлен ниже:
void triangle( point3 a, point3 b, point3 с)
{
glBegin(GL_LINE_LOOP);
glVertex3fv(a);
glVertex3fv(b);
glVertex3fv(c);
glEnd();
}
Отдельную функцию разработаем для вычерчивания тетраэдра:
void tetrahedron()
triangle(v[0], v[l], v[2]
triangle(v[3], v[2], v[l]
triangle(v[0], v[3], v[l]
triangle(v[0], v[2], v[3]
}
При перечислении вершин в треугольниках я придерживался правила правой руки, так что несложно будет преобразовать эту программу для формирования не проволочного, а закрашенного изображения. После того как в программу будут добавлены вызовы функций инициализации, она сможет вывести на экран изображение,
Это простой правильный многогранник, в котором только при наличии большой фантазии можно угадать будущую сферу.
Можно приблизить его к сфере, разделив каждую грань на правильные треугольники меньшего размера. Разбиение на треугольники гарантирует, что все грани нового объекта фигуры будут плоскими. Существуют, по меньшей мере, три способа такого разбиения,
Можно выполнить разбиение биссектрисами каждого внутреннего угла, которые, поскольку треугольник равносторонний, пересекутся в одной точке. Можно вычислить центр масс треугольника и соединить его с каждой вершиной. Но оба эти метода нам не подходят, поскольку в результате получаются треугольники с разными длинами сторон, что не позволит сформировать на их основе правильный многогранник. Поэтому мы разделим каждую сторону треугольника пополам и соединим средние точки, как показано на рис. в.
После того как каждая грань будет разделена выбранным способом, четыре новых треугольника будут лежать в плоскости прежней грани. Поэтому нам придется сдвинуть новые вершины на поверхность аппроксимируемой сферы, выполнив нормализацию их координат. Эта операция реализуется приведенной ниже программой:
void normal(point p)
{
double d=0.0;
int i;
for(i=0; i<3; ++i)
d=sqrt(d);
if(d > 0.0) for(i=0; i<2; ++i)
d+=p[i]*p[i ];
p[i)/=d;
}
Таким образом, разбиение треугольника, заданного вершинами с индексами a, b и с, может быть выполнено с помощью следующей программы:
point vl, v2, v3;
int j;
for(j=0; j<3; j++)
vl[j]=a[j]+b[j];
normal(vl);
for(j=0; j<3; j++)
v2[j]=c[j]+a[j];
normal(v2);
for(j=0; j<3; j++)
v3[j]=b[j]+c[j];
normal(v3);
triangle(v[a], v2, vl);
triangle(v[c], v3, v2);
triangle(v[b], vl, v3);
triangle(vl, v2, v3);
Этот код можно использовать в подпрограмме формирования тетраэдра и с его помощью сформировать 16 треугольных граней вместо прежних четырех. Но желательно повторить подобную процедуру п раз, получая после каждого цикла все более близкое приближение многогранника к сфере. Рекурсивно вызывая подпрограмму разбиения, мы можем контролировать количество циклов, а через него -- точность аппроксимации.
Первое, что нам придется для этого сделать, -- модифицировать подпрограмму формирования тетраэдра и ввести в нее аргумент номера цикла п, который задает глубину рекурсии:
void tetrahedron(int n)
{divide_triangle(v[0], v[l], v[2], n)
divide_triangle(v[3], v[2], v[l], n )
divide_triangle(v[0], v[3], v[l], n )
divide_triangle(v[0], v[2], v[3], n )
}
Функция divide_triangle() вызывает себя в процессе рекурсивного формирования многогранника до тех пор, пока переменная п остается больше нуля, а в противном случае формирует треугольник. Ниже приведен программный код этой функции:
divide_triangle(point3 a, point3 b, point3 с, int n)
{
/* Разбиение треугольника */
point vl, v2, v3;
int j;
if(m>0)
{for(j=0; j<3; j++)
vl[j]=a[j]+b[j];
normal(vl);
for(j=0; j<3; j++)
v2[j]=c[j]+a[j];
normal(v2);
for(j=0; j<3; j++)
v3[j]=b[j]+c[j];
normal(v3);
divide_triangle(a, vl, v2, m-1);
divide_triangle(c, v2, v3, m-1);
divide_triangle(b, v3, vl, m-1);
divide_triangle(vl, v3, v2, m-1)
}
else triangle(a,b,c);
}
На рисунке показан многоугольник, аппроксимирующий сферу, который сформирован описанной программой. Сформировав приближенное представление криволинейной поверхности объекта, можно приступать к включению в программу источников света и тонированию изображения этого объекта.
Использование модели Фонга требует, прежде всего, позаботиться о связывании вектора нормали с каждым плоским многогранником аппроксимированной поверхности. В первом варианте будем использовать самый простой алгоритм, обеспечивающий плоское закрашивание, -- определим нормаль по трем вершинам многоугольника и свяжем этот вектор с первой вершиной.
Воспользуемся для этого операцией векторного произведения, а затем нормализуем результат. Программный код функции формирования векторного произведения представлен ниже:
cross(point3 a, point3 b, point3 с, point3 d);
d[0]=( b[1]-a[1])*(c[2]-a[2])-(b[2]-a[2])*(c[1]-a[1]);
d[l]=(b[2]-a[2])*(c[0]-a[0])-(b[0]-a[0])*(c[2]-a[2]);
d[2]=(b[0]-a[0])*(c[l]-a[l])-(b[l]-a[l])*(c[0]-a[0]);
normal(d);
}
Полагая, что источники света уже сформированы в программе и что работа с ними разрешена, внесем изменения в функцию triangle(), которые позволят сформировать изображение закрашенного треугольника:
void triangle( point3 a, point3 b, point3 с)
{
point3 n;
cross(a, b, c, n);
glBegin(GL_POLYGON);
glNormal3fv(n);
glVertex3fv(a);
glVertex3fv(b);
glVertex3fv(c);
glEnd();
}
В результате программа сформирует изображение аппроксимированной сферы, представленное на рисунке:
Обратите внимание на то, что на контуре изображения сферы отчетливо виден излом между соседними многоугольниками аппроксимирующего многогранника.
Перейти от этой программы к варианту, использующему интерполяционное закрашивание, можно довольно просто, поскольку для сферы известно направление нормали в каждой точке р -- нормаль должна быть направлена вдоль радиуса, а в нашем частном случае-- от начала координат к точке р. После этого с каждой вершиной аппроксимирующего многогранника можно связать нормаль именно к поверхности сферы, a OpenGL будет в процессе закрашивания выполнять интерполяцию между вершинами каждого треугольника. Таким образом, нам понадобится скорректировать текст функции triangle ()следующим образом:
void triangle( point3 a, point3 b, point3 с)
{
point3 n;
int i;
glBegin(GL_POLYGON);
for(i=0;i<3;i++) n[i]=a[i];
normal(n);
glNormal3fv(n);
glVertex3fv(a);
for(i=0;i<3;i++) n[i]=b[i];
normal(n);
glNormal3fv(n);
glVertex3fv(b);
for(i=0;i<3;i++) n[i]=c[i];
normal(n);
glNormal3fv(n);
glVertex3fv(c);
glEnd();
}
Результаты закрашивания, полученные при выполнении этой программы, при различных местоположениях источника света показан на рисунках.
Источник света расположен на положительной полуоси OZ
Источник света расположен в точке 1, 1, 1
Источник света расположен в точке 1, -1, 1
4. Анализ
В результате выполнения курсового проекта была спроектирована сфера, освещаемая методом Фонга.
При создании проекта были рассмотрены такие возможности графической библиотеки как создание геометрических примитивов, создание квадратичных примитивов, задание цвета примитива, работа с освещением и материалом объекта.
Основным недостатком данного метода считаю скорость его выполнения.
Выводы
До недавнего времени графические акселераторы выполняли визуализацию исключительно методом Гуро. Это усложняло разработчикам программ имитацию фотореалистических изображений. Графические процессоры видеоадаптеров нового поколения способны эффективно выполнять более качественную визуализацию (в том числе и методом Фонга) в реальном времени с помощью шейдерных технологий.
Литература
1. Блинова Т.А., Порев В.Н. Компьютерная графика/Под ред. В.Н. Порева - К.: Издательство Юниор, СПБ.: КОРОНА принт. К.:Век+,2006. - 520 с., ил.
2. Никулин Е.А. Компьютерная геометрия и алгоритмы машинной графики.- СПб.: БХВ-Петербург, 2005. - 576 с.: ил.
3. Роджерс Д. Алгоритмические основы машиной графики.- М.: Мир, 1989. - 512с.
4. Роджерс Д. Адамс Дж. Математические основы машиной графики.- М.: Мир, 2001. - 604 с.
5. Пэрент Р. Компьютерная анимация//Пер. с англ.- М.: КУДИЦ-ОБРАЗ, 2004. - 512 с.
6. Эдвард Эйнджел Интерактивная компьютерная графика. Вводный курс на базе OpenGL Издательский дом "Вильямc". Москва. Санкт-Петербург. Киев, 2001.
7. Андрей Мешков, Юрий Тихомиров. Visual C++ и MFC.: Пер с англ. - 2-е изд. Перераб. И доп. - СПб.: БХВ- Петербург,2004 - 1040 с.: ил.
ПРИЛОЖЕНИЕ A
Листинг программы
// PhongDlg.cpp : implementation file//
#include "stdafx.h"
#include "Phong.h"
#include "PhongDlg.h"
#include <cmath>
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// CAboutDlg dialog used for App About
/*Исходный тетраэдр*/
point v[]={{0.0, 0.0, 1.0}, {0.0, 0.942809, -0.33333},
{-0.816497, -0.471405, -0.333333},
{0.816497, -0.471405, -0.333333}};
int n=10;
class CAboutDlg : public CDialog
{
public:
CAboutDlg();
//Dialog Data
enum {IDD = IDD_ABOUTBOX};
protected:
virtual void DoDataExchange(CDataExchange* pDX);//DDX/DDV support
//Implementation
protected:
DECLARE_MESSAGE_MAP()
};
CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
}
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
END_MESSAGE_MAP()
//CPhongDlg dialog
CPhongDlg::CPhongDlg(CWnd* pParent /*=NULL*/)
:CDialog(CPhongDlg::IDD, pParent)
,LightX(0)
,LightY(0)
,LightZ(0)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CPhongDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
DDX_Control(pDX, IDC_SLIDER1, m_LightPos_X);
DDX_Control(pDX, IDC_EDIT1, Lx);
DDX_Text(pDX, IDC_EDIT1, LightX);
DDX_Text(pDX, IDC_EDIT2, LightY);
DDX_Text(pDX, IDC_EDIT3, LightZ);
}
BEGIN_MESSAGE_MAP(CPhongDlg, CDialog)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
//}}AFX_MSG_MAP
ON_BN_CLICKED(IDC_BUTTON1, &CPhongDlg::OnBnClickedButton1)
ON_WM_KEYDOWN()
ON_WM_CHAR()
ON_WM_HSCROLL()
ON_EN_CHANGE(IDC_EDIT2, &CPhongDlg::OnEnChangeEdit2)
ON_EN_CHANGE(IDC_EDIT3, &CPhongDlg::OnEnChangeEdit3)
END_MESSAGE_MAP()
//CPhongDlg message handlers
BOOL CPhongDlg::OnInitDialog()
{
CDialog::OnInitDialog();
m_LightPos_X.SetRange(-5,5);
pdc = GetDC();
CenterWindow();
Init();
//Add "About..." menu item to system menu.
//IDM_ABOUTBOX must be in the system command range.
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
CString strAboutMenu;
strAboutMenu.LoadString(IDS_ABOUTBOX);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
//Set the icon for this dialog. The framework does this automatically
//when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE);//Set big icon
SetIcon(m_hIcon, FALSE);//Set small icon
//TODO: Add extra initialization here
return TRUE;//return TRUE unless you set the focus to a control
}
void CPhongDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialog::OnSysCommand(nID, lParam);
}
}
//If you add a minimize button to your dialog, you will need the code below
//to draw the icon. For MFC applications using the document/view model,
//this is automatically done for you by the framework.
void CPhongDlg::OnPaint()
{
int w=1000;
int h=1000;
glClearColor(0, 0.0, 0.0, 0.0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
//if (w <= h)
glOrtho(-4.0, 4.0, -4.0*(GLfloat)h/(GLfloat)w,
4.0*(GLfloat)h/(GLfloat)w, -10.0, 10.0);
//glMatrixMode(GL_MODELVIEW);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glColor3f(1,0,0);
glBegin(GL_LINES);
glColor3f(0,0,0);
glVertex3f(-5,0,0);
glVertex3f(5.0f,0,0);
glEnd();
glBegin(GL_LINES);
glColor3f(0,0,0);
glVertex3f(0,-5,0);
glVertex3f(0,5,0);
glEnd();
glColor3f(0,0,0);
glBegin(GL_LINES);
//glColor3f(0,0,0);
glVertex3f(0,0,-5);
glVertex3f(0,0,5);
glEnd();
//gluLookAt(100,0,100,0,0,0,0,1,0);
SwapBuffers(wglGetCurrentDC());
CDialog::OnPaint();
}
//The system calls this function to obtain the cursor to display while the user drags
//the minimized window.
HCURSOR CPhongDlg::OnQueryDragIcon()
{
return static_cast<HCURSOR>(m_hIcon);
}
int CPhongDlg::Init(void)
{
if (!bSetupPixelFormat())
return 0;
hrc = wglCreateContext(pdc->GetSafeHdc());
ASSERT(hrc != NULL);
wglMakeCurrent(pdc->GetSafeHdc(), hrc);
//GLfloat light_position[4];
light_position[0]=1;
light_position[1]=-1;
light_position[2]=1;
light_position[3]=1;
CRect rect;
glClearDepth(1.0);
glEnable(GL_DEPTH_TEST);
glLoadIdentity();
glMatrixMode(GL_PROJECTION);
GetClientRect(rect);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
//gluLookAt(-0,2,-0,0,0,0,0,1,0);
GLfloat white_light[]={255.0,255.0,255.0,255.0};
GetClientRect(rect);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClearDepth(1.0);
glEnable(GL_DEPTH_TEST);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
/*gluPerspective(60.0f, (GLfloat)rect.right/
(GLfloat)rect.bottom, 0.1f, 1000.0f);
glMatrixMode(GL_MODELVIEW);
*/
glViewport(0,0,rect.right,rect.bottom);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glLightfv(GL_LIGHT0,GL_POSITION,light_position);
GLfloat mat_specular[]={1.0, 1.0, 1.0, 1.0};
GLfloat mat_diffuse[]={1.0, 1.0, 1.0, 1.0};
GLfloat mat_ambient[]={1.0, 1.0, 1.0, 1.0};
GLfloat mat_shininess={100.0};
GLfloat light_ambient[]={1.0, 0.0, 0.0, 1.0};
GLfloat light_diffuse[]={1.0, 1.0, 1.0, 1.0};
GLfloat light_specular[]={1.0, 1.0, 1.0, 1.0};
/* Установка компонентов источника 0*/
glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);
glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);
/* Определение свойств материала */
glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient);
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
glMaterialf(GL_FRONT, GL_SHININESS, mat_shininess);
glEnable(GL_SMOOTH); /* режим плавного закрашивания */
glEnable(GL_LIGHTING); /* учитывать источники света */
glEnable(GL_LIGHT0); /* включить источник 0 */
glEnable(GL_DEPTH_TEST); /* разрешить работу с z-буфером */
glClearColor (0, 1.0, 1.0, 1.0);
glColor3f (0.0, 0.0, 0.0);
return 0;
}
int CPhongDlg::bSetupPixelFormat(void)
{
static PIXELFORMATDESCRIPTOR pfd=
{
sizeof(PIXELFORMATDESCRIPTOR),//size of this pfd
1,//version number
PFD_DRAW_TO_WINDOW |//support window
PFD_SUPPORT_OPENGL |//support OpenGL
PFD_DOUBLEBUFFER,//double buffered
PFD_TYPE_RGBA,//RGBA type
24, // 24-bit color depth
0, 0, 0, 0, 0, 0,//color bits ignored
0,//no alpha buffer
0,//shift bit ignored
0,//no accumulation buffer
0, 0, 0, 0,//accum bits ignored
32,//32-bit z-buffer
0,//no stencil buffer
0,//no auxiliary buffer
PFD_MAIN_PLANE, // main layer
0,//reserved
0, 0, 0//layer masks ignored
};
int pixelformat;
if ((pixelformat = ChoosePixelFormat(pdc->GetSafeHdc(), &pfd)) == 0)
{
MessageBox(CString("ChoosePixelFormat failed"));
return FALSE;
}
if (SetPixelFormat(pdc->GetSafeHdc(), pixelformat, &pfd) == FALSE)
{
MessageBox(CString("SetPixelFormat failed"));
return FALSE;
}
return TRUE;
return 0;
}
void CPhongDlg::triangle( point a, point b, point c)
/* Отображение одного треугольника */
{
if (mode==0) glBegin(GL_LINE_LOOP);
else glBegin(GL_POLYGON);
if(mode==1) glNormal3fv(a);
if(mode==2) glNormal3fv(a);
glVertex3fv(a);
if(mode==2) glNormal3fv(b);
glVertex3fv(b);
if(mode==2) glNormal3fv(c);
glVertex3fv(c);
glEnd();
}
void CPhongDlg::normal(point p)
{
/* Нормализация вектора */
//double sqrt();
float d =0.0;
int i;
for(i=0; i<3; i++) d+=p[i]*p[i];
d=sqrt(d);
if(d>0.0) for(i=0; i<3; i++) p[i]/=d;
}
void CPhongDlg::divide_triangle(point a, point b, point c, int m)
{
/* Разбиение треугольника */
point vl, v2, v3;
int j;
if(m>0)
{ for(j=0; j<3; j++)
vl[j]=a[j]+b[j];
normal(vl);
for(j=0; j<3; j++ )
v2[j]=c[j]+a[j];
normal(v2);
for(j=0; j<3; j++)
v3[j]=b[j]+c[j];
normal(v3);
divide_triangle(a, vl, v2, m-1);
divide_triangle(c, v2, v3, m-1);
divide_triangle(b, v3, vl, m-1);
divide_triangle(vl, v3, v2, m-1);
}
else triangle(a,b,c); /* draw triangle at end of recursion*/
}
void CPhongDlg::tetrahedron(int m)
{
/* Разбиение граней тетраэдра с помощью программы
разбиения треугольников */
divide_triangle(v[0], v[1], v[2], m);
divide_triangle(v[3], v[2], v[1], m);
divide_triangle(v[0], v[3], v[1], m);
divide_triangle(v[0], v[2], v[3], m);
/* */
}
void CPhongDlg::display()
{
/* Отображение объекта в трех видах */
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
static bool b=0;
mode=0;
tetrahedron(n);
mode=1;
glTranslatef(-2, 0.0,0);
tetrahedron(n);
mode=2;
glTranslatef( 4.0, 0.0,0.0);
tetrahedron(n);
glFlush();
}
/* */
void CPhongDlg::myReshape(int w, int h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (w <= h)
glOrtho(-4.0, 4.0, -4.0*(GLfloat)h/(GLfloat)w,
4.0*(GLfloat)h/(GLfloat)w, -10.0, 10.0);
else
glOrtho(-4.0*(GLfloat)w/(GLfloat)h,
4.0*(GLfloat)w/(GLfloat)h, -4.0, 4.0, -10.0, 10.0);
glMatrixMode(GL_MODELVIEW);
display();
/* */
}
void CPhongDlg::myinit()
{
GLfloat mat_specular[]={1.0, 1.0, 1.0, 1.0};
GLfloat mat_diffuse[]={1.0, 1.0, 1.0, 1.0};
GLfloat mat_ambient[]={1.0, 1.0, 1.0, 1.0};
GLfloat mat_shininess={100.0};
GLfloat light_ambient[]={1.0, 0.0, 0.0, 1.0};
GLfloat light_diffuse[]={1.0, 1.0, 1.0, 1.0};
GLfloat light_specular[]={1.0, 1.0, 1.0, 1.0};
/* Установка компонентов источника 0 */
glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);
glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);
/* Определение свойств материала */
glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient);
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
glMaterialf(GL_FRONT, GL_SHININESS, mat_shininess);
glEnable(GL_SMOOTH); /* режим плавного закрашивания */
glEnable(GL_LIGHTING); /* учитывать источники света */
glEnable(GL_LIGHT0); /* включить источник 0 */
glEnable(GL_DEPTH_TEST); /* разрешить работу с z-буфером */
glClearColor( 00, 1.0, 1.0, 1.0);
glColor3f (0.0, 0.0, 0.0);
}
void CPhongDlg::OnBnClickedButton1()
{
glLoadIdentity();
glColor3f(1,0,0);
display();
SwapBuffers(wglGetCurrentDC());
//glColor3f(1,0,0);
}
void CPhongDlg::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
//TODO: Add your message handler code here and/or call default
CDialog::OnKeyDown(nChar, nRepCnt, nFlags);
}
void CPhongDlg::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
{
CDialog::OnChar(nChar, nRepCnt, nFlags);
}
void CPhongDlg::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
if(nSBCode == SB_THUMBPOSITION)
{
light_position[0]=nPos;
UpdateData();
OnBnClickedButton1();
}
CDialog::OnHScroll(nSBCode, nPos, pScrollBar);
}
void CPhongDlg::OnEnChangeEdit2()
{
}
void CPhongDlg::OnEnChangeEdit3()
{
}
//PhongDlg.h : header file
//
#pragma once
#include "afxcmn.h"
#include "afxwin.h"
typedef float point[4];
/* Исходный тетраэдр */
static GLfloat theta[] = {0.0,0.0,0.0};
/*point v[]={{0.0, 0.0, 1.0}, {0.0, 0.942809, -0.33333},
{-0.816497, -0.471405, -0.333333},
{0.816497, -0.471405, -0.333333}};
//*/
// CPhongDlg dialog
class CPhongDlg : public CDialog
{
// Construction
public:
CPhongDlg(CWnd* pParent = NULL); // standard constructor
// Dialog Data
enum { IDD = IDD_PHONG_DIALOG };
protected:
virtual void DoDataExchange(CDataExchange* pDX); //DDX/DDV support
// Implementation
protected:
HICON m_hIcon;
// Generated message map functions
virtual BOOL OnInitDialog();
afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
DECLARE_MESSAGE_MAP()
int bSetupPixelFormat(void);
int Init(void);
CDC *pdc;
HGLRC hrc;
//int n;
int mode;
void triangle( point a, point b, point c) ;
void normal(point p) ;
void divide_triangle(point a, point b, point c, int m);
void tetrahedron( int m);
void display();
void myReshape(int w, int h);
void myinit();
public:
GLfloat light_position[4];
afx_msg void OnBnClickedButton1();
public:
afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
public:
afx_msg void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags);
public:
CSliderCtrl m_LightPos_X;
public:
afx_msg void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar);
public:
afx_msg void OnEnChangeEdit2();
public:
afx_msg void OnEnChangeEdit3();
public:
CEdit Lx;
public:
int LightX;
public:
int LightY;
public:
int LightZ;
};
Размещено на Allbest.ru
...Подобные документы
Задачи моделирования освещения. Локальные и глобальные модели. Диффузное и зеркальное отражение. Уравнение освещенности Фонга. Интерполяция цвета (закраска Гуро). Вычисление нормалей и клонирование вершин. Ошибки интерполяции Фонга, поддержка в OpenGL.
презентация [71,7 K], добавлен 14.08.2013Сущность метода неопределённых коэффициентов, использование интерполяционных многочленов и разностных соотношений для аппроксимации производных. Алгоритм программы и обоснование языка программирования. Экспериментальное исследование и решение задачи.
курсовая работа [227,4 K], добавлен 30.04.2009Разработка алгоритма аппроксимации данных методом наименьших квадратов. Средства реализации, среда программирования Delphi. Физическая модель. Алгоритм решения. Графическое представление результатов. Коэффициенты полинома (обратный ход метода Гаусса).
курсовая работа [473,6 K], добавлен 09.02.2015Обзор методов и подходов решения поставленной задачи аппроксимации логического вывода экспертной системы. Разработка и описание метода сетевого оператора для решения данной задачи. Разработка алгоритма решения. Проведение вычислительного эксперимента.
дипломная работа [1,5 M], добавлен 23.02.2015Сущность интеллектуальных систем. Запись математического выражения в виде ориентированного графа. Особенности разработки генетического алгоритма для решения задачи аппроксимации логического вывода экспертной системы на основе метода сетевого оператора.
дипломная работа [1,0 M], добавлен 17.09.2013Оценка погрешности и точности в математике. Составление программы и алгоритма для численного дифференцирования с заданной допустимой погрешностью на алгоритмическом языке Turbo Pascal 7.0. Составление алгоритма и программы аппроксимации функции.
курсовая работа [810,6 K], добавлен 24.03.2012Описание методов вычисления определителя матрицы. Математическое решение задачи с применением метода исключения Гаусса с выбором главного элемента. Схема алгоритма программы, описание переменных и структур данных, текст программы на языке Pascal.
курсовая работа [438,8 K], добавлен 16.02.2011Описание алгоритма решения задачи графическим способом. Ввод элементов исходного массива в цикле. Нахождение определённых элементов. Сортировка элементов с помощью пузырькового метода. Разработка программы на языке Pascal. Поиск наибольшего элемента.
лабораторная работа [123,5 K], добавлен 15.01.2014Принцип и значение метода Эйлера для расчета дифференциальных уравнений. Анализ его геометрического смысла. Улучшение метода за счет аппроксимации производной. Разработка блок-схем и программы на языке Turbo Pascal для проверки методов интегрирования.
курсовая работа [385,7 K], добавлен 15.06.2013Обучение нейронных сетей как мощного метода моделирования, позволяющего воспроизводить сложные зависимости. Реализация алгоритма обратного распространения ошибки на примере аппроксимации функции. Анализ алгоритма обратного распространения ошибки.
реферат [654,2 K], добавлен 09.06.2014Разработка алгоритма решения задачи численного интегрирования методом трапеции. Словесное описание и блок-схема разработанного алгоритма программы. Описание интерфейса, главного окна и основных форм программы. Проверка работоспособности программы.
курсовая работа [1,4 M], добавлен 16.03.2012Характеристика методов нечеткого моделирования и изучение системы кластеризации в пакетах прикладных программ. Разработка и реализация алгоритма для оптимизации базы правил нечеткого классификатора с помощью генетического алгоритма аппроксимации функции.
дипломная работа [1,9 M], добавлен 21.06.2014Математический алгоритм вычисления корней нелинейного уравнения и его решение методом касательных. Особенности программной реализации решения таких уравнений. Процедура подготовки и решения задачи на ЭВМ, характеристика алгоритма и структуры программы.
курсовая работа [96,6 K], добавлен 02.06.2012Математическое обоснование метода решения задачи: определенный интеграл, квадратурная формула Симпсона (формула парабол). Словесное описание алгоритма и составление его блок-схемы. Выбор языка программирования. Текст программы решения задачи, ее листинг.
курсовая работа [593,6 K], добавлен 09.07.2012Математическое описание операций преобразования плоских фигур. Выбор и обоснование языка программирования и среды разработки. Задание базовой фигуры. Разработка алгоритма работы программы. Проверка корректности работы программы в различных режимах.
курсовая работа [567,6 K], добавлен 13.10.2014Описание математической модели. Обоснование метода реализации. Вид алгоритма и программы. Руководство системного программиста, оператора. Комбинирование метод хорд и касательных. Интерпретация и анализ результатов. Листинг программы, контрольный пример.
курсовая работа [3,3 M], добавлен 12.01.2014Составление алгоритма и программы для факторизации целого числа N с помощью ро-метода Полларда. Краткое описание данного метода: составление последовательности, вычисление разности и наибольшего общего делителя. Алгоритм работы и листинг программы.
курсовая работа [12,1 K], добавлен 24.06.2010Решение базовых задач линейного программирования симплекс-методом, их реализация на языке программирования С++. Математическое обеспечение; разработка алгоритма программы, решающей задачу с помощью симплекс-таблиц с произвольными свободными членами.
курсовая работа [217,8 K], добавлен 25.05.2014Программирование нестандартных функций, задач оптимизации, дифференциального уравнения и аппроксимации с помощью языка Паскаль. Алгоритм и программа операций над матрицами. Нахождение значения корней нелинейного уравнения по методу половинного деления.
курсовая работа [1,1 M], добавлен 12.08.2011Реализация приложения, которое выполняет считывание, обработку, визуализацию и аппроксимацию экспериментальных данных полиномиальной функции. Блок схема алгоритма аппроксимации методом наименьших квадратов. Разработка интерфейса и листинга программы.
курсовая работа [1,1 M], добавлен 07.07.2013