Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Архив2 / курсовая docx17 / Moya_kursovaya (2).docx
Скачиваний:
35
Добавлен:
07.08.2013
Размер:
2.62 Mб
Скачать
    1. Результат

В результате выполнения программы, получаем следующие результаты, показанные на рисунках 4-8.

Рисунок 4 – Часть стакана скрыта непрозрачным кубом

Рисунок 5 – Видимость куба сквозь прозрачный стакан

Рисунок 6 – Куб находится позади стакана

Рисунок 7 – Пример масштабирования на уменьшение сцены

Рисунок 8 – Пример масштабирования на увеличение сцены

ЗАКЛЮЧЕНИЕ

В результате выполнения поставленной задачи, получили сцену, состоящую из двух предметов (прозрачный стакан и непрозрачный куб) на статичном фоне, замощенным загруженным изображением. По заданию необходимо было доказать свойства прозрачных тел и свойства непрозрачных тел, а также проверить это опытным путем в результате их взаимодействия. В итоге получили необходимые результаты: непрозрачный предмет скрывает часть прозрачного предмета, а сквозь прозрачный предмет при любом ракурсе виден непрозрачный предмет.

Для получения данных результатов был применен ряд алгоритмов: алгоритм преобразования координат, алгоритм удаления невидимых граней, алгоритм, определяющий лицевые и не лицевые грани с помощью вектора нормали, проведенного к поверхности, а также алгоритм закраски трехмерного объекта с использованием простой модели освещения, основанной на ранее вычисленных значениях вектора нормали.

Итогом работы стало приложение «C# Alpha Blending», наглядно показывающий принцип работы альфа-смешения, а также доказывающий возможность создания трехмерной сцены посредством программирования на языке высокого уровня C#.

СПИСОК ИСПОЛЬЗОВАННЫХ ИСТОЧНИКОВ

1 Кузнецова Е.А., Лукошков М.М., Майоров И.С. Методические указания к выполнению лабораторных работ по дисциплине «Компьютерная геометрия и графика». [Текст] – Издательство: « Архангельский Государственный Технический Университет», г. Архангельск, 2006 г. – стр. 36;

2 Википедия – Свободная Энциклопедия. [Электронный Ресурс] – Режим доступа: http://ru.wikipedia.org/, свободный;

3 Иванов В.П., Батраков А.С. Трехмерная компьютерная графика. [Текст] – Издательство: «Радио и связь», ISBN 5-256-01204-5, г. Москва, 1995 г. – стр. 224;

4 Роджерс Д., Адамс Дж. Математические основы машинной графики. [Текст] – Издательство: «Мир», перевод с английского, ISBN 5-03-002143-4, г. Москва, 2001 г. – стр. 604.

ПРИЛОЖЕНИЕ А

(обязательное)

Листинг основных компонентов

Листинг модуля Form1.cs

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Linq;

using System.Text;

using System.Windows.Forms;

namespace WindowsFormsApplication1

{

// Структура координат

public struct Point3D

{

public double x;

public double y;

public double z;

public Point3D(double x, double y, double z)

{

this.x = x;

this.y = y;

this.z = z;

}

}

public partial class Form1 : Form

{

Bitmap b;

Graphics g;

Image image;

Point3D[] Vertex = new Point3D[48]; // Массив координат вершин (x, y, z)

Point3D[] View = new Point3D[48]; // Массив видовых координат

Point[] Scrn = new Point[48]; // Массив экранных координат

Point[] Perspective = new Point[48]; // Массив перспективных координат

double[] NZ = new double[27]; // Массив нормалей для освещения

int[] Order = new int[27]; // Массив порядка отображения видимых граней

double[] D = new double[27]; // Массив, содержащий средние значения Z-граней

double Teta = Math.PI / 180; // Угол тета = 45 градусов

double Phi = Math.PI / 180; // Угол фи = 45 градусов

bool mousePress = false;

double sX = 0;

double sY = 0;

double nx, ny, nz;

int D0 = 500;

int R0 = 300;

public Form1()

{

InitializeComponent();

this.MouseWheel += new MouseEventHandler(Form1_MouseWheel);

b = new Bitmap("Background.jpg"); // Экземпляр класса Bitmap

image = Image.FromFile("Background.jpg"); // Загружаем фоновое изображение

g = Graphics.FromImage(b); // Задаем поверхность для рисования

}

// Построение объектов сцены

void ПостроитьСцену()

{

g.DrawImage(image, 0, 0);

for (int i = 0; i < 48; i++)

{

// Преобразование из мировых в видовые координаты

View[i].x = 20 * (int)Math.Round(Vertex[i].x * (-Math.Sin(Teta)) + Vertex[i].y * Math.Cos(Teta));

View[i].y = 20 * (int)Math.Round(Vertex[i].x * (-Math.Cos(Phi) * Math.Cos(Teta)) - Vertex[i].y * (Math.Cos(Phi) * Math.Sin(Teta)) + Vertex[i].z * Math.Sin(Phi));

View[i].z = -20 * (int)Math.Round(Vertex[i].x * (-Math.Sin(Phi) * Math.Cos(Teta)) - Vertex[i].y * (Math.Sin(Phi) * Math.Sin(Teta)) - Vertex[i].z * (Math.Cos(Phi)) + R0);

// Перспективное преобразование видовых координат

Perspective[i].X = pictureBox1.Width / 2 + (int)Math.Round(D0 * (View[i].x / View[i].z));

Perspective[i].Y = pictureBox1.Height / 2 + (int)Math.Round(D0 * (View[i].y / View[i].z));

if (View[i].z == 0)

{

Perspective[i].X = 0;

Perspective[i].Y = 0;

}

else

{

Perspective[i].X = (int)(Math.Round(D0 * (View[i].x / View[i].z)));

Perspective[i].Y = (int)(Math.Round(D0 * (View[i].y / View[i].z)));

}

// Получение экранных координат

Scrn[i].X = (int)Perspective[i].X + pictureBox1.Width / 2;

Scrn[i].Y = (int)Perspective[i].Y + pictureBox1.Height / 2;

}

// Находим среднее значение по координате Z каждой грани

for (int i = 0; i < 19; i++)

{

D[i] = (View[i].z + View[i + 20].z + View[i + 21].z + View[i + 1].z) / 4;

}

// Конечная грань стакана

D[19] = (View[19].z + View[39].z + View[20].z + View[0].z) / 4;

// Грань - основание стакана

for (int i = 0; i < 19; i++)

{

D[20] += View[i].z / 20;

}

// Грани ядовито-желтого куба

D[21] = (View[40].z + View[41].z + View[42].z + View[43].z) / 4;

D[22] = (View[40].z + View[44].z + View[47].z + View[43].z) / 4;

D[23] = (View[43].z + View[47].z + View[46].z + View[42].z) / 4;

D[24] = (View[42].z + View[46].z + View[45].z + View[41].z) / 4;

D[25] = (View[41].z + View[45].z + View[44].z + View[40].z) / 4;

D[26] = (View[44].z + View[45].z + View[46].z + View[47].z) / 4;

// Заполняем список граней

List<Point[]> Plane = new List<Point[]>();

for (int i = 0; i < 19; i++)

{

Plane.Add(new Point[] { Scrn[i], Scrn[20 + i], Scrn[21 + i], Scrn[1 + i] });

}

Plane.Add(new Point[] { Scrn[19], Scrn[39], Scrn[20], Scrn[0] });

Plane.Add(new Point[] {Scrn[0], Scrn[1], Scrn[2], Scrn[3], Scrn[4], Scrn[5], Scrn[6], Scrn[7], Scrn[8], Scrn[9], Scrn[10], Scrn[11], Scrn[12], Scrn[13], Scrn[14], Scrn[15], Scrn[16], Scrn[17], Scrn[18], Scrn[19]});

// Куб ядовито-желтого цвета

Plane.Add(new Point[] { Scrn[40], Scrn[41], Scrn[42], Scrn[43] });

Plane.Add(new Point[] { Scrn[40], Scrn[44], Scrn[47], Scrn[43] });

Plane.Add(new Point[] { Scrn[43], Scrn[47], Scrn[46], Scrn[42] });

Plane.Add(new Point[] { Scrn[42], Scrn[46], Scrn[45], Scrn[41] });

Plane.Add(new Point[] { Scrn[41], Scrn[45], Scrn[44], Scrn[40] });

Plane.Add(new Point[] { Scrn[44], Scrn[45], Scrn[46], Scrn[47] });

// Список цветов для граней сцены

List<Color> PlaneColor = new List<Color>()

{

Color.FromArgb(80, 208, 208, 208), // 1 Грань стакана

Color.FromArgb(80, 208, 208, 208), // 2 Грань стакана

Color.FromArgb(80, 208, 208, 208), // 3 Грань стакана

Color.FromArgb(80, 208, 208, 208), // 4 Грань стакана

Color.FromArgb(80, 208, 208, 208), // 5 Грань стакана

Color.FromArgb(80, 208, 208, 208), // 6 Грань стакана

Color.FromArgb(80, 208, 208, 208), // 7 Грань стакана

Color.FromArgb(80, 208, 208, 208), // 8 Грань стакана

Color.FromArgb(80, 208, 208, 208), // 9 Грань стакана

Color.FromArgb(80, 208, 208, 208), // 10 Грань стакана

Color.FromArgb(80, 208, 208, 208), // 11 Грань стакана

Color.FromArgb(80, 208, 208, 208), // 12 Грань стакана

Color.FromArgb(80, 208, 208, 208), // 13 Грань стакана

Color.FromArgb(80, 208, 208, 208), // 14 Грань стакана

Color.FromArgb(80, 208, 208, 208), // 15 Грань стакана

Color.FromArgb(80, 208, 208, 208), // 16 Грань стакана

Color.FromArgb(80, 208, 208, 208), // 17 Грань стакана

Color.FromArgb(80, 208, 208, 208), // 18 Грань стакана

Color.FromArgb(80, 208, 208, 208), // 19 Грань стакана

Color.FromArgb(80, 208, 208, 208), // 20 Грань стакана

Color.FromArgb(100, 102, 102, 102), // 21 - основание стакана

Color.FromArgb(255, 204, 255, 0), // Грань куба

Color.FromArgb(255, 204, 255, 0), // Грань куба

Color.FromArgb(255, 204, 255, 0), // Грань куба

Color.FromArgb(255, 204, 255, 0), // Грань куба

Color.FromArgb(255, 204, 255, 0), // Грань куба

Color.FromArgb(255, 204, 255, 0), // Грань куба

};

СортировкаГраней(27, 0); // Сортировка 27 граней по глубине, начиная с 0-ой грани

ВычислениеНормали(); // Вычисление нормали к плоскости по трем точкам

for (int i = 0; i < 27; i++) // Перебираем все грани

{

if (NZ[Order[i]] >= 0) // Если грань не видна

{

int A = (int)((double)PlaneColor[Order[i]].A); // Прозрачность

int R = (int)((double)PlaneColor[Order[i]].R * NZ[Order[i]]); // Красный цвет * интенсивность

int G = (int)((double)PlaneColor[Order[i]].G * NZ[Order[i]]); // Зеленый цвет * интенсивность

int B = (int)((double)PlaneColor[Order[i]].B * NZ[Order[i]]); // Синий цвет * интенсивность

Color Glass = Color.FromArgb(A, R, G, B); // Задаем цвет

g.FillPolygon(new SolidBrush(Glass), Plane[Order[i]]); // Закраска

}

if (NZ[Order[i]] <= 0) // Если грань видна

{

int A = (int)Math.Abs(((double)PlaneColor[Order[i]].A));

int R = (int)Math.Abs(((double)PlaneColor[Order[i]].R * NZ[Order[i]]));

int G = (int)Math.Abs(((double)PlaneColor[Order[i]].G * NZ[Order[i]]));

int B = (int)Math.Abs(((double)PlaneColor[Order[i]].B * NZ[Order[i]]));

Color Glass = Color.FromArgb(A, R, G, B);

g.FillPolygon(new SolidBrush(Glass), Plane[Order[i]]);

}

}

}

// Процедура нахождения нормалей к поверхностям

void ВычислениеНормали()

{

// Получение нормалей к первым 19 граням стакана

for (int i = 0; i < 19; i++)

{

nx = View[i].y * (View[i + 20].z - View[i + 21].z) + View[i + 20].y * (View[i + 21].z - View[i].z) + View[i + 21].y * (View[i].z - View[i + 20].z);

ny = View[i].z * (View[i + 20].x - View[i + 21].x) + View[i + 20].z * (View[i + 21].x - View[i].x) + View[i + 21].z * (View[i].x - View[i + 20].x);

nz = View[i].x * (View[i + 20].y - View[i + 21].y) + View[i + 20].x * (View[i + 21].y - View[i].y) + View[i + 21].x * (View[i].y - View[i + 20].y);

NZ[i] = nz / Math.Sqrt(nz * nz + ny * ny + nx * nx);

}

// Нормаль к 19-ой грани (не поддается циклу)

nx = View[19].y * (View[39].z - View[20].z) + View[39].y * (View[20].z - View[19].z) + View[20].y * (View[19].z - View[39].z);

ny = View[19].z * (View[39].x - View[20].x) + View[39].z * (View[20].x - View[19].x) + View[20].z * (View[19].x - View[39].x);

nz = View[19].x * (View[39].y - View[20].y) + View[39].x * (View[20].y - View[19].y) + View[20].x * (View[19].y - View[39].y);

NZ[19] = nz / Math.Sqrt(nz * nz + ny * ny + nx * nx);

// Нормаль к грани (основание стакана), грань имеет 10 вершин, взято 3 (0, 10, 19)

nx = View[0].y * (View[10].z - View[19].z) + View[10].y * (View[19].z - View[0].z) + View[19].y * (View[0].z - View[10].z);

ny = View[0].z * (View[10].x - View[19].x) + View[10].z * (View[19].x - View[0].x) + View[19].z * (View[0].x - View[10].x);

nz = View[0].x * (View[10].y - View[19].y) + View[10].x * (View[19].y - View[0].y) + View[19].x * (View[0].y - View[10].y);

NZ[20] = nz / Math.Sqrt(nz * nz + ny * ny + nx * nx);

// 40, 41, 42

nx = View[40].y * (View[41].z - View[42].z) + View[41].y * (View[42].z - View[40].z) + View[42].y * (View[40].z - View[41].z);

ny = View[40].z * (View[41].x - View[42].x) + View[41].z * (View[42].x - View[40].x) + View[42].z * (View[40].x - View[41].x);

nz = View[40].x * (View[41].y - View[42].y) + View[41].x * (View[42].y - View[40].y) + View[42].x * (View[40].y - View[41].y);

NZ[21] = nz / Math.Sqrt(nz * nz + ny * ny + nx * nx);

// 40, 44, 47

nx = View[40].y * (View[44].z - View[47].z) + View[44].y * (View[47].z - View[40].z) + View[47].y * (View[40].z - View[44].z);

ny = View[40].z * (View[44].x - View[47].x) + View[44].z * (View[47].x - View[40].x) + View[47].z * (View[40].x - View[44].x);

nz = View[40].x * (View[44].y - View[47].y) + View[44].x * (View[47].y - View[40].y) + View[47].x * (View[40].y - View[44].y);

NZ[22] = nz / Math.Sqrt(nz * nz + ny * ny + nx * nx);

// 43, 47, 46

nx = View[43].y * (View[47].z - View[46].z) + View[47].y * (View[46].z - View[43].z) + View[46].y * (View[43].z - View[47].z);

ny = View[43].z * (View[47].x - View[46].x) + View[47].z * (View[46].x - View[43].x) + View[46].z * (View[43].x - View[47].x);

nz = View[43].x * (View[47].y - View[46].y) + View[47].x * (View[46].y - View[43].y) + View[46].x * (View[43].y - View[47].y);

NZ[23] = nz / Math.Sqrt(nz * nz + ny * ny + nx * nx);

// 42, 46, 45

nx = View[42].y * (View[46].z - View[45].z) + View[46].y * (View[45].z - View[42].z) + View[45].y * (View[42].z - View[46].z);

ny = View[42].z * (View[46].x - View[45].x) + View[46].z * (View[45].x - View[42].x) + View[45].z * (View[42].x - View[46].x);

nz = View[42].x * (View[46].y - View[45].y) + View[46].x * (View[45].y - View[42].y) + View[45].x * (View[42].y - View[46].y);

NZ[24] = nz / Math.Sqrt(nz * nz + ny * ny + nx * nx);

// 41, 45, 44

nx = View[41].y * (View[45].z - View[44].z) + View[45].y * (View[44].z - View[41].z) + View[44].y * (View[41].z - View[45].z);

ny = View[41].z * (View[45].x - View[44].x) + View[45].z * (View[44].x - View[41].x) + View[44].z * (View[41].x - View[45].x);

nz = View[41].x * (View[45].y - View[44].y) + View[45].x * (View[44].y - View[41].y) + View[44].x * (View[41].y - View[45].y);

NZ[25] = nz / Math.Sqrt(nz * nz + ny * ny + nx * nx);

// 44, 45, 46

nx = View[44].y * (View[45].z - View[46].z) + View[45].y * (View[46].z - View[44].z) + View[46].y * (View[44].z - View[45].z);

ny = View[44].z * (View[45].x - View[46].x) + View[45].z * (View[46].x - View[44].x) + View[46].z * (View[44].x - View[45].x);

nz = View[44].x * (View[45].y - View[46].y) + View[45].x * (View[46].y - View[44].y) + View[46].x * (View[44].y - View[45].y);

NZ[26] = nz / Math.Sqrt(nz * nz + ny * ny + nx * nx);

}

// Получить изображение куба

void ПоказатьСцену()

{

ПостроитьСцену();

pictureBox1.Image = b;

}

// Метод-флаг

bool Flag(int i, int PlaneNumber, int[] Order)

{

bool flag = true; // Флаг поднят

for (int j = 0; j < PlaneNumber; j++) // Перебираем грани по их номерам

if (Order[j] == i) flag = false; // Сравниваем номер грани в массиве порядка с номером данной грани

return flag; // Возвращаем значение флага

}

// Метод сортировки граней

void СортировкаГраней(int PlanesCount, int PlaneNumber)

{

double k = 1000; // Показатель глубины

for (int i = 0; i < 27; i++) // Перебираем все грани

{

if (Flag(i, PlaneNumber, Order)) //

if (D[i] < k) // Если ср. знач. по Z < показателя глубины

{ // то...

k = D[i]; // Показатель глубины равняется конкретному значению

Order[PlaneNumber] = i; // Заполнения массива по порядку расположения граней

}

}

PlanesCount --; // Уменьшаем количество граней на 1

PlaneNumber ++; // Увеличиваем номер грани на 1

if (PlanesCount > 0) // Если количество граней > 0, вызываем рекурсию

СортировкаГраней(PlanesCount, PlaneNumber);

}

// События, обрабатываемые при загрузке формы приложения

private void Form1_Load(object sender, EventArgs e)

{

Teta = 89.549087;

Phi = 134.99817;

Vertex[0] = new Point3D(-50, -50, 0); // A

Vertex[1] = new Point3D(-48, -50, -15); // B

Vertex[2] = new Point3D(-40, -50, -30); // C

Vertex[3] = new Point3D(-28, -50, -42); // D

Vertex[4] = new Point3D(-15, -50, -48); // E

Vertex[5] = new Point3D(0, -50, -50); // F

Vertex[6] = new Point3D(15, -50, -48); // G

Vertex[7] = new Point3D(28, -50, -42); // H

Vertex[8] = new Point3D(40, -50, -30); // I

Vertex[9] = new Point3D(48, -50, -15); // J

Vertex[10] = new Point3D(50, -50, 0); // K

Vertex[11] = new Point3D(48, -50, 15); // L

Vertex[12] = new Point3D(40, -50, 30); // M

Vertex[13] = new Point3D(28, -50, 42); // N

Vertex[14] = new Point3D(15, -50, 48); // O

Vertex[15] = new Point3D(0, -50, 50); // P

Vertex[16] = new Point3D(-15, -50, 48); // R

Vertex[17] = new Point3D(-28, -50, 42); // S

Vertex[18] = new Point3D(-40, -50, 30); // T

Vertex[19] = new Point3D(-48, -50, 15); // U

// Верхняя плоскость стакана

Vertex[20] = new Point3D(-60, 100, 0); // A-1

Vertex[21] = new Point3D(-58, 100, -19); // B-1

Vertex[22] = new Point3D(-48, 100, -36); // C-1

Vertex[23] = new Point3D(-35, 100, -50); // D-1

Vertex[24] = new Point3D(-18, 100, -58); // E-1

Vertex[25] = new Point3D(0, 100, -60); // F-1

Vertex[26] = new Point3D(18, 100, -58); // G-1

Vertex[27] = new Point3D(35, 100, -50); // H-1

Vertex[28] = new Point3D(48, 100, -36); // I-1

Vertex[29] = new Point3D(58, 100, -19); // J-1

Vertex[30] = new Point3D(60, 100, 0); // K-11

Vertex[31] = new Point3D(58, 100, 19); // L-12

Vertex[32] = new Point3D(48, 100, 36); // M-13

Vertex[33] = new Point3D(35, 100, 50); // N-14

Vertex[34] = new Point3D(18, 100, 58); // O-15

Vertex[35] = new Point3D(0, 100, 60); // P-16

Vertex[36] = new Point3D(-18, 100, 58); // R-17

Vertex[37] = new Point3D(-35, 100, 50); // S-18

Vertex[38] = new Point3D(-48, 100, 36); // T-19

Vertex[39] = new Point3D(-58, 100, 19); // U-20

// Ядовито-желтый куб (а = 50)

// Нижняя грань

Vertex[40] = new Point3D(-60, -50, -65); // A

Vertex[41] = new Point3D(-60, -50, -115); // B

Vertex[42] = new Point3D(-10, -50, -115); // C

Vertex[43] = new Point3D(-10, -50, -65); // D

// Верхняя грань

Vertex[44] = new Point3D(-60, 0, -65); // A-1

Vertex[45] = new Point3D(-60, 0, -115); // B-1

Vertex[46] = new Point3D(-10, 0, -115); // C-1

Vertex[47] = new Point3D(-10, 0, -65); // D-1

ПоказатьСцену();

}

// Управление сценой с помощью клавиш-стрелок

private void Form1_KeyDown(object sender, KeyEventArgs e)

{

if (e.KeyCode == Keys.Up)

{

Phi = Phi + Math.PI / 128;

ПоказатьСцену();

}

if (e.KeyCode == Keys.Down)

{

Phi = Phi - Math.PI / 128;

ПоказатьСцену();

}

if (e.KeyCode == Keys.Right)

{

Teta = Teta + Math.PI / 128;

ПоказатьСцену();

}

if (e.KeyCode == Keys.Left)

{

Teta = Teta - Math.PI / 128;

ПоказатьСцену();

}

}

// Управление сценой с помощью мыши

private void pictureBox1_MouseMove(object sender, MouseEventArgs e)

{

if (mousePress)

{

if (e.X < sX)

{

Teta = Teta - Math.PI / 128;

sX = e.X;

}

if (e.X > sX)

{

Teta = Teta + Math.PI / 128;

sX = e.X;

}

if (e.Y > sY)

{

Phi = Phi - Math.PI / 128;

sY = e.Y;

}

if (e.Y < sY)

{

Phi = Phi + Math.PI / 128;

sY = e.Y;

}

ПоказатьСцену();

}

}

// Событие, вохникающее при отпускании мыши

private void pictureBox1_MouseUp(object sender, MouseEventArgs e)

{

mousePress = false;

}

// Событие, возникающее при нажатии мыши

private void pictureBox1_MouseDown(object sender, MouseEventArgs e)

{

mousePress = true;

if (e.Button == MouseButtons.Right)

{

R0 = 300;

ПоказатьСцену();

}

}

// Событие при прокрутке колеса мыши

void Form1_MouseWheel(object sender, MouseEventArgs e)

{

if ((e.Delta == 120) && (R0 != 150))

{

R0 -= 5;

ПоказатьСцену();

}

else if ((e.Delta == -120) && (R0 != 800))

{

R0 += 5;

ПоказатьСцену();

}

}

}

}

Соседние файлы в папке курсовая docx17