Разработка алгоритма и программы закрашивания граней методом Фонга

Анализирование аппроксимации Фонга как метода для точного затенения полигонов, её математическое описание и алгоритм создания. Практическая демонстрация реализации затенения с помощью полигональной аппроксимации. Проект сферы, созданный по методу Фонга.

Рубрика Программирование, компьютеры и кибернетика
Вид курсовая работа
Язык русский
Дата добавления 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

...

Подобные документы

Работы в архивах красиво оформлены согласно требованиям ВУЗов и содержат рисунки, диаграммы, формулы и т.д.
PPT, PPTX и PDF-файлы представлены только в архивах.
Рекомендуем скачать работу.