GeoSELECT.ru



Компьютеры / Реферат: Трехмерная графика (Компьютеры)

Космонавтика
Уфология
Авиация
Административное право
Арбитражный процесс
Архитектура
Астрология
Астрономия
Аудит
Банковское дело
Безопасность жизнедеятельности
Биология
Биржевое дело
Ботаника
Бухгалтерский учет
Валютные отношения
Ветеринария
Военная кафедра
География
Геодезия
Геология
Геополитика
Государство и право
Гражданское право и процесс
Делопроизводство
Деньги и кредит
Естествознание
Журналистика
Зоология
Инвестиции
Иностранные языки
Информатика
Искусство и культура
Исторические личности
История
Кибернетика
Коммуникации и связь
Компьютеры
Косметология
Криминалистика
Криминология
Криптология
Кулинария
Культурология
Литература
Литература : зарубежная
Литература : русская
Логика
Логистика
Маркетинг
Масс-медиа и реклама
Математика
Международное публичное право
Международное частное право
Международные отношения
Менеджмент
Металлургия
Мифология
Москвоведение
Музыка
Муниципальное право
Налоги
Начертательная геометрия
Оккультизм
Педагогика
Полиграфия
Политология
Право
Предпринимательство
Программирование
Психология
Радиоэлектроника
Религия
Риторика
Сельское хозяйство
Социология
Спорт
Статистика
Страхование
Строительство
Схемотехника
Таможенная система
Теория государства и права
Теория организации
Теплотехника
Технология
Товароведение
Транспорт
Трудовое право
Туризм
Уголовное право и процесс
Управление
Физика
Физкультура
Философия
Финансы
Фотография
Химия
Хозяйственное право
Цифровые устройства
Экологическое право
   

Реферат: Трехмерная графика (Компьютеры)


Министерство образования Украины
Кафедра ПО ЭВМ



ОТЧЕТ
О лабораторной работе на тему:
«Трехмерная графика»
по дисциплине «Компьютерная графика»



Краткие теоретические сведения.

Каждая точка пространства (кроме начальной точки О) может быть задана
четверкой одновременно не равных нулю чисел ((x,y,z,1) или, более обще,
(hx,hy,hz,h), где [pic]). Эта четверка определена однозначно с точностью до
общего множителя. Предложенный подход дает возможность воспользоваться
матричной записью и в более сложных , трехмерных задачах.
Как известно, любое аффинное преобразование в трехмерном пространстве
может быть представлено в виде суперпозиции вращений растяжений, отражений
и переносов. Поэтому достаточно подробно описать матрицы только этих
последних преобразований.

A. Матрицы вращения в пространстве.
Матрица вращения вокруг оси абсцисс на угол q:
[pic]
Матрица вращения вокруг оси ординат на угол w:
[pic]
Матрица вращения вокруг оси аппликат на угол x:
[pic]

Б. Матрица растяжения (сжатия):
[pic]
здесь a>0 - коэффициент растяжения (сжатия) вдоль оси абсцисс,b>0-
коэффициент растяжения (сжатия) вдоль оси ординат,y>0-коэффициент
растяжения (сжатия) вдоль оси аппликат.

В. Матрица отражения .
Матрица отражения относительно плоскости xOy:
[pic]
Матрица отражения относительно плоскости yOz:
[pic]
Матрица отражения относительно плоскости zOx:
[pic]

Г. Матрица переноса :
[pic]
Здесь (r,q,v)-вектор переноса.
Заметим, что, как и в двумерном случае , все выписанные матрицы не
вырождены.

Ортографическая проекция - картинная плоскость совпадает с одной из
координатных плоскостей или параллельна ей. Матрица проектирования
вдоль оси Х на плоскость YOZ имеет вид
[pic]
В случае , если плоскость проектирования параллельна координатной
плоскости, необходимо умножить матрицу [Px] на матрицу сдвига . Имеем
[pic]
Аналогично записываются матрицы проектирования вдоль 2-х
координатных осей:
[pic]

Аксонометрическая проекция - проектирующие прямые перпендикулярны
картинной плоскости .
Различают три вида проекций в зависимости от взаимного расположения
плоскости проектирования и координатных осей:
триметрия-нормальный вектор картинной плоскости образует с ортами
координатных осей попарно различные углы(рис.15);
диметрия-два угла между нормалью картинной плоскости и координатными осями
равны (рис. 16).
- изометрия-все три угла между нормалью картинной плоскости и
координатными осями равны (рис. 17).
Каждый из трех видов указанных проекций получается комбинацией
поворотов, за которой следует параллельное проектирование.

Перспективные (центральные) проекции строятся более сложно .
Предположим что центр проектирования лежит на оси Z - C (0,0,c) а плоскость
проектирования совпадает с координатной плоскостью XOY (рис. 19) .
Возьмем в пространстве произвольную точку M(x,y,z), проведем через нее и
точку С прямую и запишем ее параметрические уравнения . Имеем:
X`= xt , Y`=yt, Z`= c+(z-c)t
Найдем координаты точки пересечения этой прямой с плоскостью XOY.
Из того , что z`=0, получаем
[pic]
Тот же самый результат мы получим, привлекая матрицу
[pic]
В самом деле,
[pic]
Mатрица проектирования, конечно, вырождена ; матрица же
соответствующего перспективного преобразования(без проектирования) имеет
следующий вид
[pic]

Язык С++ предоставляет очень удобные средства, позволяющие заметно
упростить работу с векторами и преобразованиями в пространстве.
Рассмотрим реализацию работы с векторами.

// Файл vector.h
#ifndef __VECTOR__
#define __VECTOR__

#include

class Vector
{
public:
double x, y, z;
Vector () {};
Vector ( double v ) { x = y = z = v; };
Vector ( const Vector& v ) { x = v.x; y = v.y; z = v.z; };
Vector ( double vx, double vy, double vz ) { x = vx; y = vy; z = vz; };
Vector& operator = ( const Vector& v ) { x = v.x; y = v.y; z = v.z;
return *this; }
Vector& operator = ( double f ) { x = y = z = f; return *this; };
Vector operator - () const;
Vector& operator += ( const Vector& );
Vector& operator -= ( const Vector& );
Vector& operator *= ( const Vector& );
Vector& operator *= ( double );
Vector& operator /= ( double );
friend Vector operator + ( const Vector&, const Vector& );
friend Vector operator - ( const Vector&, const Vector& );
friend Vector operator * ( const Vector&, const Vector& );
friend Vector operator * ( double, const Vector& );
friend Vector operator * ( const Vector&, double );
friend Vector operator / ( const Vector&, double );
friend Vector operator / ( const Vector&, const Vector& );
friend double operator & ( const Vector& u, const Vector& v )
{ return u.x * v.x + u.y * v.y + u.z * v.z; };
friend Vector operator ^ ( const Vector&, const Vector& );
double operator ! () { return (double) sqrt ( x * x + y * y + z * z ); };
double& operator [] ( int n ) { return *( &x + n ); };
int operator < ( double v ) { return x < v && y < v && z < v; };
int operator > ( double v ) { return x > v && y > v && z > v; };
};

class Ray
{
public:
Vector Org;
Vector Dir;
Ray () {};
Ray ( Vector& o, Vector& d ) { Org = o, Dir = d; };
Vector Point ( double t ) { return Org + Dir * t; };
};

inline Vector Vector :: operator - () const
{
return Vector ( -x, -y, -z );
}

inline Vector operator + ( const Vector& u, const Vector& v )
{
return Vector ( u.x + v.x, u.y + v.y, u.z + v.z );
}

inline Vector operator - ( const Vector& u, const Vector& v )
{
return Vector ( u.x - v.x, u.y - v.y, u.z - v.z );
}

inline Vector operator * ( const Vector& u, const Vector& v )
{
return Vector ( u.x * v.x, u.y * v.y, u.z * v.z );
}

inline Vector operator * ( const Vector& u, double f )
{
return Vector ( u.x * f, u.y * f, u.z * f );
}

inline Vector operator * ( double f, const Vector& v )
{
return Vector ( f * v.x, f * v.y, f * v.z );
}

inline Vector operator / ( const Vector& u, const Vector& v )
{
return Vector ( u.x / v.x, u.y / v.y, u.z / v.z );
}

inline Vector operator / ( const Vector& u, double f )
{
return Vector ( u.x / f, u.y / f, u.z / f );
}

inline Vector& Vector :: operator += ( const Vector& v )
{
x += v.x;
y += v.y;
z += v.z;
return *this;
}

inline Vector& Vector :: operator -= ( const Vector& v )
{
x -= v.x;
y -= v.y;
z -= v.z;
return *this;
}

inline Vector& Vector :: operator *= ( const Vector& v )
{
x *= v.x;
y *= v.y;
z *= v.z;
return *this;
}

inline Vector& Vector :: operator *= ( double v )
{
x *= v;
y *= v;
z *= v;
return *this;
}

inline Vector& Vector :: operator /= ( double v )
{
x /= v;
y /= v;
z /= v;
return *this;
}

inline Vector Normalize ( Vector& v ) { return v / !v; }

Vector RndVector ();
Vector& Clip ( Vector& v );

#endif


----------------------------------------------------------------------------

// Файл vector.срр
#include
#include
#include "vector.h"

Vector operator ^ ( const Vector& u, const Vector& v )
{
return Vector ( u.y * v.z - u.z * v.y,
u.z * v.x - u.x * v.z,
u.x * v.y - u.y * v.x );
}

Vector RndVector ()
{
Vector v ( rand () - 0.5 * RAND_MAX,
rand () - 0.5 * RAND_MAX,
rand () - 0.5 * RAND_MAX );
return Normalize ( v );
}

Vector& Clip ( Vector& v )
{
if ( v.x < 0.0 ) v.x = 0.0;
else
if ( v.x > 1.0 ) v.x = 1.0;
if ( v.y < 0.0 ) v.y = 0.0;
else
if ( v.y > 1.0 ) v.y = 1.0;
if ( v.z < 0.0 ) v.z = 0.0;
else
if ( v.z > 1.0 ) v.z = 1.0;
return v;
}

С этой целью создается класс Vector, содержащий в себе компоненты
вектора, и для этого класса переопределяются основные знаки операций.
- - унарный минус и поэлементное вычитание векторов;
+ - поэлементное сложение векторов;
* - умножение вектора на число;
* - поэлементное умножение векторов;
/ - деление вектора на число;
/ - поэлементное деление векторов;
& - скалярное произведение векторов;
^ - векторное произведение;
! - длина вектора;
[] - компонента вектора.

При этом стандартные приоритеты операций сохраняются.
Кроме этих операций определяются также некоторые простейшие функции для
работы с векторами:
. Normalize – нормирование вектора;
. RndVector – получение почти равномерно распределенного случайного
единичного вектора;
. Clip – отсечение вектора.
С использованием этого класса можно в естественной и удобной форме
записывать сложные векторные выражения.
Аналогичным образом вводится класс Matrix, служащий для представления
матриц преобразований в трехмерном пространстве. Для этого класса также
производится переопределение основных знаков операций.

//Файл matrix.h
#ifndef __MATRIX__
#define __MATRIX__

#include "vector.h"

class Matrix
{
public:
double x [4][4];
Matrix () {};
Matrix ( double );
Matrix& operator += ( const Matrix& );
Matrix& operator -= ( const Matrix& );
Matrix& operator *= ( const Matrix& );
Matrix& operator *= ( double );
Matrix& operator /= ( double );
void Invert ();
void Transpose ();
friend Matrix operator + ( const Matrix&, const Matrix& );
friend Matrix operator - ( const Matrix&, const Matrix& );
friend Matrix operator * ( const Matrix&, double );
friend Matrix operator * ( const Matrix&, const Matrix& );
friend Vector operator * ( const Matrix&, const Vector& );
};

Matrix Translate ( const Vector& );
Matrix Scale ( const Vector& );
Matrix RotateX ( double );
Matrix RotateY ( double );
Matrix RotateZ ( double );
Matrix Rotate ( const Vector&, double );
Matrix MirrorX ();
Matrix MirrorY ();
Matrix MirrorZ ();

#endif

//--------------------------------------------------------------------------
-

// Файл matrix.cpp
#include
#include "matrix.h"

Matrix :: Matrix ( double v )
{
int j;
for ( int i = 0; i < 4; i++ )
for ( j = 0; j < 4; j++ )
x [i][j] = ( i == j ) ? v : 0.0;
x [3][3] = 1;
}

void Matrix :: Invert ()

{
Matrix Out ( 1 );
for ( int i = 0; i < 4; i++ ) {
double d = x [i][i];
if ( d != 1.0 ) {
for ( int j = 0; j < 4; j++ ) {
Out.x [i][j] /= d;
x [i][j] /= d;
}
}
for ( int j = 0; j < 4; j++ ) {
if ( j != i ) {
if ( x[j][i] != 0.0 ) {
double mulby = x[j][i];
for ( int k = 0; k < 4; k++ ) {
x [j][k] -= mulby * x [i][k];
Out.x [j][k] -= mulby * Out.x [i][k];
}
}
}
}
}
*this = Out;
}

void Matrix :: Transpose ()
{
double t;
int j;
for ( int i = 0; i < 4; i++ )
for ( j = 0; j < 4; j++ )
if ( i != j ) {
t = x [i][j];
x [i][j] = x [j][i];
x [j][i] = t;
}
}

Matrix& Matrix :: operator += ( const Matrix& A )
{
int j;
for ( int i = 0; i < 4; i++ )
for ( j = 0; j < 4; j++ )
x [i][j] += A.x [i][j];
return *this;
}

Matrix& Matrix :: operator -= ( const Matrix& A )
{
int j;
for ( int i = 0; i < 4; i++ )
for ( j = 0; j < 4; j++ )
x [i][j] -= A.x [i][j];
return *this;
}

Matrix& Matrix :: operator *= ( double v )
{
int j;
for ( int i = 0; i < 4; i++ )
for ( j = 0; j < 4; j++ )
x [i][j] *= v;
return *this;
}

Matrix& Matrix :: operator *= ( const Matrix& A )
{
Matrix res = *this;
int j;
for ( int i = 0; i < 4; i++ )
for ( j = 0; j < 4; j++ ) {
double sum = 0;
for ( int k = 0; k < 4; k++ )
sum += res.x [i][k] * A.x [k][j];
x [i][j] = sum;
}
return *this;
}

Matrix operator + ( const Matrix& A, const Matrix& B )
{
Matrix res;
int j;
for ( int i = 0; i < 4; i++ )
for ( j = 0; j < 4; j++ )
res.x [i][j] = A.x [i][j] + B.x [i][j];
return res;
}

Matrix operator - ( const Matrix& A, const Matrix& B )
{
Matrix res;
int j;
for ( int i = 0; i < 4; i++ )
for ( j = 0; j < 4; j++ )
res.x [i][j] = A.x [i][j] - B.x [i][j];
return res;
}

Matrix operator * ( const Matrix& A, const Matrix& B )
{
Matrix res;
int j;
for ( int i = 0; i < 4; i++ )
for ( j = 0; j < 4; j++ ) {
double sum = 0;
for ( int k = 0; k < 4; k++ )
sum += A.x [i][k] * B.x [k][j];
res.x [i][j] = sum;
}
return res;
}

Matrix operator * ( const Matrix& A, double v )
{
Matrix res;
int j;
for ( int i = 0; i < 4; i++ )
for ( j = 0; j < 4; j++ )
res.x [i][j] = A.x [i][j] * v;
return res;
}

Vector operator * ( const Matrix& M, const Vector& v )
{
Vector res;
res.x = v.x * M.x [0][0] + v.y * M.x [1][0] + v.z * M.x [2][0] + M.x
[3][0];
res.y = v.x * M.x [0][1] + v.y * M.x [1][1] + v.z * M.x [2][1] + M.x
[3][1];
res.z = v.x * M.x [0][2] + v.y * M.x [1][2] + v.z * M.x [2][2] + M.x
[3][2];
double denom = v.x * M.x [0][3] + v.y * M.x [1][3] +
v.z * M.x [2][3] + M.x[3][3];
if ( denom != 1.0 )
res /= denom;
return res;
}

Matrix Translate ( const Vector& Loc )
{
Matrix res ( 1 );
res.x [3][0] = Loc.x;
res.x [3][1] = Loc.y;
res.x [3][2] = Loc.z;
return res;
};

Matrix Scale ( const Vector& v )
{
Matrix res ( 1 );
res.x [0][0] = v.x;
res.x [1][1] = v.y;
res.x [2][2] = v.z;
return res;
};

Matrix RotateX ( double Angle )
{
Matrix res ( 1 );
double Cosine = cos ( Angle );
double Sine = sin ( Angle );
res.x [1][1] = Cosine;
res.x [2][1] = - Sine;
res.x [1][2] = Sine;
res.x [2][2] = Cosine;
return res;
};

Matrix RotateY ( double Angle )
{
Matrix res ( 1 );
double Cosine = cos ( Angle );
double Sine = sin ( Angle );
res.x [0][0] = Cosine;
res.x [2][0] = - Sine;
res.x [0][2] = Sine;
res.x [2][2] = Cosine;
return res;
};

Matrix RotateZ ( double Angle )
{
Matrix res ( 1 );
double Cosine = cos ( Angle );
double Sine = sin ( Angle );
res.x [0][0] = Cosine;
res.x [1][0] = - Sine;
res.x [0][1] = Sine;
res.x [1][1] = Cosine;
return res;
};

Matrix Rotate ( const Vector& axis, double angle )
{
Matrix res ( 1 );
double Cosine = cos ( angle );
double Sine = sin ( angle );
res.x [0][0] = axis.x * axis.x + ( 1 - axis.x * axis.x ) * Cosine;
res.x [0][1] = axis.x * axis.y * ( 1 - Cosine ) + axis.z * Sine;
res.x [0][2] = axis.x * axis.z * ( 1 - Cosine ) - axis.y * Sine;
res.x [0][3] = 0;
res.x [1][0] = axis.x * axis.y * ( 1 - Cosine ) - axis.z * Sine;
res.x [1][1] = axis.y * axis.y + ( 1 - axis.y * axis.y ) * Cosine;
res.x [1][2] = axis.y * axis.z * ( 1 - Cosine ) + axis.x * Sine;
res.x [1][3] = 0;
res.x [2][0] = axis.x * axis.z * ( 1 - Cosine ) + axis.y * Sine;
res.x [2][1] = axis.y * axis.z * ( 1 - Cosine ) - axis.x * Sine;
res.x [2][2] = axis.z * axis.z + ( 1 - axis.z * axis.z ) * Cosine;
res.x [2][3] = 0;
res.x [3][0] = 0;
res.x [3][1] = 0;
res.x [3][2] = 0;
res.x [3][3] = 1;
return res;
};

Matrix MirrorX ()
{
Matrix res ( 1 );
res.x [0][0] = -1;
return res;
};

Matrix MirrorY ()
{
Matrix res ( 1 );
res.x [1][1] = -1;
return res;
};

Matrix MirrorZ ()
{
Matrix res ( 1 );
res.x [2][2] = -1;
return res;
}
В следующей библиотеке была реализована работа с трехмерными объектами:
гранью, графическим объектом и пространством. Реализованы следующие
возможности:
поворот объектов вокруг координатных осей;
зеркальное отображение объектов по отношению к координатным осям;
центральное и параллельное проектирование;
масштабирование объектов;
удаление невидимых поверхностей;
перемещение объектов в пространстве.

//Файл 3dworks.h
#ifndef __3DWORKS__
#define __3DWORKS__

#include
#include
#include "vector.h"
#include "matrix.h"

#define OneSd 0
#define TwoSds 1

#define MaxPoints 10
#define MaxFacets 10
#define MaxObjects 10

class Polygon
{
public:
int PointNumber;
Vector * Point;
Vector Normal;
Vector Center;
int Color;
int TwoSides;
Polygon () {};
Polygon ( Vector *, int, int, int );
void Draw ( const Vector& );
void Move ( const Vector& );
void Rotate ( double, double, double );
void PolyScale ( const Vector& );
void PolyMirrorX ();
void PolyMirrorY ();
void PolyMirrorZ ();
};

class GrObject
{
public:
int FacetNumber;
Polygon * Facet;
Vector Coords;
GrObject () {};
GrObject ( Polygon *, int, const Vector& );
void Move ( const Vector& );
void Rotate ( double, double, double );
void ObjScale ( const Vector& );
void ObjMirrorX ();
void ObjMirrorY ();
void ObjMirrorZ ();
};

struct BSPNode
{
Polygon * Poly;
double d;
BSPNode * Left;
BSPNode * Right;
};

class Space
{
public:
int ObjectNumber;
GrObject * Object [MaxObjects];
Space () { ObjectNumber = 0; };
Space ( GrObject *, int );
void Add ( GrObject * );
void Draw ( const Vector& );
};

int IsVisible ( const Polygon&, const Vector& );
void DrawBSPTree ( BSPNode *, const Vector& );

#endif

//--------------------------------------------------------------------------
--

//Файл 3dworks.cpp
#include "3dworks.h"

// Polygon's methods

Polygon :: Polygon ( Vector * PointArr, int PointNum, int Col, int TS )
{
if ( PointNum br Matrix m = MirrorZ();br for ( int i = 0; i FacetNumber; i++ )br Facet[i].PolyMirrorZ ();br Coords = m * Coords;br}brbr// Space's methodsbrbrSpace :: Space ( GrObject * Obj, int ObjectNum )br{br if ( ObjectNum = MaxObjects )br {br ObjectNumber = ObjectNum;br for ( int i = 0; i < ObjectNumber; i++ )br Object[i] = &Obj[i];br };br}brbrvoid Space :: Add ( GrObject * Obj )br{br if ( ObjectNumber < MaxObjects ) Object [ObjectNumber++] = Obj;br}brbrvoid Space :: Draw ( const Vector& PrCenter )br{brbr}brbr// Other functionsbrbrint IsVisible ( const Polygon& Poly, const Vector& PrCenter )br{br return ( Poly.Normal & ( PrCenter - Poly.Point[0] )) < 0 ||brPoly.TwoSides;br}brbrvoid DrawBSPTree ( BSPNode * Tree, const Vector& PrCntr )br{br if (( Tree - Poly -> Normal & PrCntr ) > Tree -> d ) {
if ( Tree -> Right != NULL ) DrawBSPTree ( Tree -> Right, PrCntr );
Tree -> Poly -> Draw ( PrCntr );
if ( Tree -> Left != NULL ) DrawBSPTree ( Tree -> Left, PrCntr );
}
else {
if ( Tree -> Left != NULL ) DrawBSPTree ( Tree -> Left, PrCntr );
Tree -> Poly -> Draw ( PrCntr );
if ( Tree -> Right != NULL ) DrawBSPTree ( Tree -> Right, PrCntr );
}
}

Далее представлена демонстрационная программа, которая выполняет все
вышеперечисленные операции с тетраэдром.

//Файл 3dgame.cpp
#include
#include
#include
#include
#include
#include
#include "3dworks.h"

void DrawObject ( GrObject* Obj, const Vector& v )
{
for ( int i = 0; i < Obj->FacetNumber; i++ )
if ( IsVisible ( Obj->Facet[i], v )) Obj->Facet[i].Draw ( v );
}

main ()
{
Vector Poly1[3], Poly2[3], Poly3[3], Poly4[3];
Polygon O[4];
Vector A ( -50, 0, 0 ),
B ( 0, 0, 50 ),
C ( 50, 0, 0 ),
D ( 0, 100, 0 ),
PrCenter ( 0, 0, 1000 );

Poly1[0] = A; Poly2[0] = B;
Poly1[1] = D; Poly2[1] = D;
Poly1[2] = B; Poly2[2] = C;

Poly3[0] = C; Poly4[0] = C;
Poly3[1] = A; Poly4[1] = D;
Poly3[2] = B; Poly4[2] = A;

Polygon * P1 = new Polygon ( Poly1, 3, 11, OneSd );
Polygon * P2 = new Polygon ( Poly2, 3, 12, OneSd );
Polygon * P3 = new Polygon ( Poly3, 3, 13, OneSd );
Polygon * P4 = new Polygon ( Poly4, 3, 14, OneSd );

O[0] = *P1; O[1] = *P2;
O[2] = *P3; O[3] = *P4;

delete P1; delete P2;
delete P3; delete P4;

GrObject * Obj = new GrObject ( O, 4, Vector ( 0 ) );

double fi = 0.1, psi = 0.1, step = 0.1;
int ch = 0, Page = 3;

int driver = DETECT, mode, res;
initgraph ( &driver, &mode, "" );
if ( ( res = graphresult () ) != grOk ) {
printf ( "nGraphics error: %sn", grapherrormsg ( res ) );
exit ( 1 );
}
setgraphmode ( 1 );

DrawObject ( Obj, PrCenter );

do {

setactivepage ( Page % 2 );
clearviewport ();
if ( kbhit ())
{
switch ( ch = getch() ) {
case '+': Obj->ObjScale ((1.1,1.1,1.1)); break;
case '-': Obj->ObjScale ((0.9,0.9,0.9)); break;
case 'x': Obj->ObjMirrorX (); break;
case 'y': Obj->ObjMirrorY (); break;
case 'z': Obj->ObjMirrorZ (); break;
};
if ( ch == 0 )
{
switch ( ch = getch () ) {
case 72 : fi -= step; break;
case 80 : fi += step; break;
case 75 : psi += step; break;
case 77 : psi -= step; break;
};
};
};

Obj->Rotate ( fi, psi, 0 );
DrawObject ( Obj, PrCenter );

setvisualpage ( Page++ % 2 );
if ( fi == 0 && psi == 0 ) while ( !kbhit ());

} while ( ch != 27 );

delete Obj;

closegraph ();
}




Реферат на тему: Трехмерная компьютерная графика

Кемеровский Государственный Университет
кафедра математического анализа



Курсовая работа по теме:

Трёхмерная компьютерная графика



Выполнил: студент М-963
Печёркин Ю. К.
Руководитель: Ким В. Б.



Кемерово 1999


Введение

Машинная графика в настоящее время уже вполне сформировалась как наука.
Существует аппаратное и программное обеспечение для получения разнообразных
изображений - от простых чертежей до реалистичных образов естественных
объектов. Машинная графика используется почти во всех научных и инженерных
дисциплинах для наглядности восприятия и передачи информации. Знание её
основ в наше время необходимо любому ученому или инженеру. Машинная графика
властно вторгается в бизнес, медицину, рекламу, индустрию развлечений.
Применение во время деловых совещаний демонстрационных слайдов,
подготовленных методами машинной графики и другими средствам автоматизации
конторского труда, считается нормой. В медицине становится обычным
получение трехмерных изображений внутренних органов по данным компьютерных
томографов. В наши дни телевидение и другие рекламные предприятия часто
прибегают к услугам машинной графики и компьютерной мультипликации.
Использование машинной графики в индустрии развлечений охватывает такие
несхожие области как видеоигры и полнометражные художественные фильмы.
На сегодняшний день создано большое количество программ, позволяющих
создавать и редактировать трёхмерные сцены и объекты. Среди наиболее
популярных можно назвать такие как 3D studio Max, которая позволяет
трёхмерные компьютерные ролики. Область её применения в основном реклама,
мультипликация и оформление телевизионных передач. Другой не менее
популярный пакет программ это Auto-CAD. Он применяется в основном
инженерами и проектировщиками для создания чертежей и пространственных
моделей. Кроме этих существует множество других специализированных
программных пакетов охватывающих практически все стороны человеческой
жизни.
Среди многообразия возможностей, предоставляемых современными
вычислительными средствами, те, что основаны на пространственно-образном
мышлении человека, занимают особое место. Современные программно-
оперативные средства компьютерной графики представляют собой весьма
эффективный инструмент поддержки такого мышления при выполнении работ самых
разных видов. С другой стороны именно пространственно-образное мышление
является неформальной творческой основой для расширения изобразительных
возможностей компьютеров. Это важное обстоятельство предполагает взаимно
обогащающее сотрудничество всё более совершенной техники и человека со всем
богатством знания, накопленного предшествующими поколениями. Глаз и раньше
был эффективным средством познания человеком мира и себя. Поэтому столь
привлекательной оказывается компьютерная визуализация, особенно
визуализация динамическая, которую следует рассматривать как важнейший
инструмент для обучения наукам.

1. Введение в машинную графику

Современная машинная графика - это тщательно разработанная дисциплина.
Обстоятельно исследованы сегменты геометрических преобразований и описаний
кривых и поверхностей. Также изучены, но все еще продолжают развиваться
методы растрового сканирования, отсечение, удаление линий и поверхностей,
цвет, закраска, текстура и эффекты прозрачности. Сейчас наибольший интерес
представляют именно эти разделы машинной графики.
Машинная графика - сложная и разнообразная дисциплина. Для изучения её,
прежде всего, необходимо разбить на обозримые части. Прежде всего
необходимо рассмотреть методы и алгоритмы растровой графики. Это достаточно
простой, но очень важный раздел машинной графики. В этом разделе
рассматриваются алгоритмы рисования отрезков и окружностей на экране
монитора, методы растровой развёртки, заполнения многоугольников,
устранения ступенчатости или лестничного эффекта. Отдельно следует
рассмотреть методы отсечения изображения, т.е. отбора той информации,
которая необходима для визуализации конкретной сцены.
При построении трёхмерной сцены возникает проблема удаления невидимых
линий и поверхностей. Это одна из наиболее сложных составляющих
визуализации трёхмерных объектов. Способы достижения эффектов прозрачности,
отражения и т.п., строго говоря, не входят в задачу удаления невидимых
частей трёхмерных объектов и, тем не менее, некоторые из них тесно связаны
с этой проблемой. Например, построение теней. Не смотря на это, в
компьютерной графике выделяется довольно большой раздел, посвящённый
построению реалистичных изображений, в котором подробно рассматриваются
методы создания таких эффектов как зеркальное отражение, преломление лучей
в различных средах, тени, фактура объекта. Так же рассматриваются различные
источники света, их спектральные характеристики и форма. Сюда же относятся
цветовые эффекты, сглаживание поверхностей и многое другое.
Как видно из выше сказанного компьютерная графика это достаточно
объемная дисциплина, поэтому я остановлюсь лишь на некоторых её наиболее
интересных аспектах.

2. Растровая графика

Любое изображение, в том числе и трёхмерное, состоит из графических
примитивов. Поэтому, прежде всего, необходимо знать специальные методы
генерации изображения, вычерчивание прямых и кривых линий, закраски
многоугольников, создающей впечатление сплошных объектов. Рассмотрим
некоторые из этих методов.

1. Алгоритмы вычерчивания отрезков

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

2. Цифровой дифференциальный анализатор

Один из методов разложения отрезка в растр состоит в решении
дифференциального уравнения, описывающего этот процесс. Для прямой линии
имеем:
[pic] или [pic]н
Решение представляется в виде
[pic]
где x1, y1 и x2, y2 – концы разлагаемого отрезка и yi – начальное значение
для очередного шага вдоль отрезка. Фактически уравнение (2.1.) представляет
собой рекуррентное соотношение для последовательных значений y вдоль
нужного отрезка. Этот метод, используемый для разложения в растр отрезков,
называется цифровым дифференциальным анализатором (ЦДА). В простом ЦДА либо
[pic], либо [pic] (большее из приращений) выбирается в качестве единицы
растра. Ниже приводится простой алгоритм, работающий во всех квадрантах:

Процедура разложения в растр отрезка по методу цифрового дифференциального
анализатора (ЦДА)

предполагается, что концы отрезка (x1,y1) и (x2,y2) не совпадают

Integer – функция преобразования вещественного числа в целое.
Примечание: во многих реализациях функция Integer означает взятие целой
части, т.е. Integer(( 8.5) = ( 9, а не ( 8. В алгоритме используется именно
такая функция.
Sign ( функция, возвращающая ( 1, 0, 1 для отрицательного нулевого и
положительного аргумента соответственно.

if abs ( x2 ( x1 ) ( abs ( y2 ( y1 ) then
Длина = abs ( x2 ( x1 )
else
Длина = abs ( y2 ( y1 )
end if
полагаем большее из приращений (x или (y равным единице растра
(x = ( x2 ( x1 ) / Длина
(y = ( y2 ( y1 ) / Длина
округляем величины, а не отбрасываем дробную часть
использование знаковой функции делает алгоритм пригодным для всех
квадрантов
x = x1 + 0.5 * Sign ( (x )
y = y1 + 0.5 * Sign ( (y )
начало основного цикла
i =1
while ( i ( Длина )
Plot ( Integer ( x ), Integer ( y ) )
x = x + (x
y = y + (y
i = i + 1
end while
finish
С помощью этого алгоритма получают прямые, вполне удовлетворительного
вида, но у него есть ряд недостатков. Во-первых, плохая точность в концевых
точках. Во-вторых, результаты работы алгоритма зависят от ориентации
отрезка. Вдобавок предложенный алгоритм использует вещественную арифметику,
что заметно снижает скорость выполнения.

3. Алгоритм Брезенхема

Алгоритм Брезенхема выбирает оптимальные растровые координаты для
представления отрезка. В процессе работы одна из координат - либо x, либо у
(в зависимости от углового коэффициента) - изменяется на единицу. Изменение
другой координаты (либо на нуль, либо на единицу) зависит от расстояния
между действительным положением отрезка и ближайшими координатами сетки.
Такое расстояние называется ошибкой.
Алгоритм построен так, что требуется проверять лишь знак этой ошибки.
На рис.2.1 это иллюстрируется для отрезка в первом


Ѕ ( (y ( 1 (ошибка ( 0)

0 ( (y/(x < Ѕ (ошибка (x then
Врем = (x
(x = (y
(y = Врем
Обмен = 1
else
Обмен = 0
end if
инициализация [pic] с поправкой на половину пиксела
[pic] = 2 * (y ( (x
основной цикл
for i = 1 to (x
Plot ( x ,y )
While ( [pic] ( 0 )
If Обмен = 1 then
x = x + s1
else
y = y + s2
end if
[pic] = [pic] ( 2 * (x
end while
if Обмен = 1 then
y = y + s2
else
x = x + s1
end if
[pic] = [pic] + 2 * (y
next i
finish
Этот алгоритм удовлетворяет самым строгим требованиям. Он имеет
приемлемую скорость и может быть легко реализован на аппаратном или
микропрограммном уровне.

4. Алгоритм Брезенхема для генерации окружностей

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


Брезенхему. Для начала заметим, что необходимо сгенерировать только одну
восьмую часть окружности. Остальные её части могут быть получены
последовательными отражениями, как это показано на рис. 2.3. Если
сгенерирован первый октант (от 0( до 45( против часовой стрелки), то второй
октант можно получить зеркальным отражением относительно прямой у = x, что
дает в совокупности первый квадрант. Первый квадрант отражается
относительно прямой x = 0 для получения соответствующей части окружности во
втором квадранте. Верхняя полуокружность отражается относительно прямой у =
0 для завершения построения. На рис.2.3. приведены двумерные матрицы
соответствующих преобразований.
Для вывода алгоритма рассмотрим первую четверть окружности с центром в
начале координат. Заметим, что если работа алгоритма начинается в точке x =
0, у = R, то при генерации окружности по часовой стрелке в первом квадранте
у является монотонно убывающей функцией аргумента x (рис. 2.4). Аналогично,
если исходной точкой является y = 0, x = R, то при генерации окружности
против часовой стрелки x будет монотонно убывающей функцией аргумента у. В
нашем случае выбирается генерация по часовой стрелке с началом в точке x =
0, у = R. Предполагается, что центр окружности и начальная точка находятся
точно в точках растра.
Для любой заданной точки на окружности при генерации по часовой стрелке
существует только три возможности выбрать следующий пиксел, наилучшим
образом приближающий окружность: горизонтально вправо, по диагонали вниз и
вправо, вертикально вниз. На рис.2.5 эти направления обозначены
соответственно mH, mD, mV. Алгоритм выбирает пиксел, для



которого минимален квадрат расстояния между одним из этих пикселов и
окружностью, т. е. минимум из
mH = | ( xi + 1 )2 + ( yi )2 – R2 |
mH = | ( xi + 1 )2 + ( yi ( 1 )2 – R2 |
mH = | ( xi )2 + ( yi ( 1 )2 – R2 |
Вычисления можно упростить, если заметить, что в окрестности точки (
xi, yi ) возможны только пять типов пересечений окружности и сетки растра,
приведенных на рис.2.6.
Разность между квадратами расстояний от центра окружности до
диагонального пиксела ( xi + 1, yi ( 1 ) и от центра до точки на окружности
R2 равна
[pic]
Как и в алгоритме Брезенхема для отрезка, для выбора соответствующего
пиксела желательно использовать только знак ошибки, а не её величину.
При ( < 0 диагональная точка ( xi + 1, yi ( 1 ) находится внутри
реальной окружности, т. е. это случаи 1 или 2 на рис.2.6. Ясно, что в этой
ситуации следует выбрать либо пиксел ( xi + 1, yi ) т. е. mH, либо пиксел (
xi + 1, yi ( 1 ), т. е. mD. Для этого сначала рассмотрим случай 1 и
проверим разность квадратов расстояний от окружности до пикселов в
горизонтальном и диагональном направлениях:
[pic]
При ( < 0 расстояние от окружности до диагонального пиксела
(mD) больше, чем до горизонтального (mH). Напротив, если ( > 0, расстояние
до горизонтального пиксела (mH) больше. Таким образом,
при ( < 0 выбираем mH ( xi + 1, уi )
при ( > 0 выбираем mD ( xi + 1, уi – 1 )

При ( = 0, когда расстояния от окружности до обоих пикселов одинаковы,
выбираем горизонтальный шаг.
Количество вычислений, необходимых для оценки величины (, можно
сократить, если заметить, что в случае 1
[pic]
так как диагональный пиксел ( xi + 1, уi – 1 ) всегда лежит внутри
окружности, а горизонтальный ( xi + 1, уi ) - вне ее. Таким образом, (
можно вычислить по формуле
[pic]
Дополнение до полного квадрата члена ( yi )2 с помощью добавления и
вычитания - 2уi + 1 дает
[pic]
В квадратных скобках стоит по определению (i, и его подстановка

( = 2((i + yi) – 1

существенно упрощает выражение.
Рассмотрим случай 2 на рис.2.6 и заметим, что здесь должен быть выбран
горизонтальный пиксел ( xi + 1, уi ), так как у является монотонно
убывающей функцией. Проверка компонент ( показывает, что
[pic]
поскольку в случае 2 горизонтальный ( xi + 1, уi ) и диагональный ( xi + 1,
уi – 1 ) пикселы лежат внутри окружности. Следовательно, ( < 0, и при
использовании того же самого критерия, что и в случае 1, выбирается пиксел
( xi + 1, уi ).
Если (i > 0, то диагональная точка ( xi + 1, уi – 1 ) находится вне
окружности, т. е. это случаи З и 4 на рис.2.6. В данной ситуации ясно, что
должен быть выбран либо пиксел ( xi + 1, уi – 1 ), т. е. mD, либо ( xi, уi
– 1 ), т. е. mV. Аналогично разбору предыдущего случая критерий выбора
можно получить, рассматривая сначала случай З и проверяя разность между
квадратами расстояний от окружности до диагонального mD и вертикального mV
пикселов, т. е.
[pic]
При ( < 0 расстояние от окружности до вертикального пиксела ( xi, уi –
1 ) больше и следует выбрать диагональный шаг mD, к пикселу ( xi + 1, уi –
1 ). Напротив, в случае ( > 0 расстояние от окружности до диагонального
пиксела больше и следует выбрать вертикальное движение к пикселу ( xi, уi –
1 ). Таким образом,

при ( ( 0 выбираем mD в ( xi + 1, уi – 1 )
при ( < 0 выбираем mV в ( xi, уi – 1 )

Здесь в случае ( = 0, т. е. когда расстояния равны, выбран диагональный
шаг.
Проверка компонент ( показывает, что
[pic]
поскольку для случая З диагональный пиксел ( xi + 1, уi – 1 ) находится вне
окружности, тогда как вертикальный пиксел ( xi, уi – 1 ) лежит внутри ее.
Это позволяет записать ( в виде
[pic]
Дополнение до полного квадрата члена ( xi )2 с помощью добавления и
вычитания 2xi + 1 дает
[pic]
Использование определения (i приводит выражение к виду
[pic]
Теперь, рассматривая случай 4, снова заметим, что следует выбрать
вертикальный пиксел ( xi, уi – 1 ), так как y является монотонно убывающей
функцией при возрастании x. проверка компонент ( для случая 4 показывает,
что
[pic]
поскольку оба пиксела находятся вне окружности. Следовательно, ( > 0 и при
использовании критерия, разработанного для случая 3, происходит верный
выбор mV.
Осталось проверить только случай 5 на рис.2.7, который встречается,
когда диагональный пиксел ( xi + 1, уi – 1 ) лежит на окружности, т. е. (i
= 0. Проверка компонент ( показывает, что
[pic]
Следовательно, ( > 0 и выбирается диагональный пиксел ( xi + 1, уi – 1 ).
Аналогичным образом оцениваем компоненты (:
[pic]
и ( < 0, что является условием выбора правильного диагонального шага к ( хi
+ 1, уi – 1 ). Таким образом, случай (i = 0 подчиняется тому же критерию,
что и случай (i < 0 или (i > 0.
Подведем итог полученных результатов:
(i < 0
( ( 0 выбираем пиксел ( хi + 1, уi ) ( mH
( > 0 выбираем пиксел ( хi + 1, уi – 1 ) ( mD
(i > 0
( ( 0 выбираем пиксел ( хi + 1, уi – 1 ) ( mD
( > 0 выбираем пиксел ( хi , уi – 1 ) ( mV
(i = 0 выбираем пиксел ( хi + 1, уi – 1 ) ( mD
Легко разработать простые рекуррентные соотношения дня реализации
пошагового алгоритма. Сначала рассмотрим горизонтальный шаг mH к пикселу (
хi + 1, уi ). Обозначим это новое положение пиксела как ( i + 1 ). Тогда
координаты нового пиксела и значение (i равны
[pic]
Аналогично координаты нового пиксела и значения (i для шага mD к пикселу (
хi + 1, уi – 1 ) таковы:
[pic]
То же самое для шага mV к ( хi, уi – 1 )
[pic]
Реализация алгоритма Брезенхема для окружности приводиться ниже.

Пошаговый алгоритм Брезенхема для генерации окружности в первом квадранте

все переменные целые
xi = 0
yi = R
(i = 2(1 – R)
Предел = 0
1. Plot ( xi, yi )
if yi ( Предел then 4
выделение случая 1 или 2, 4 или 5, или 3
if (i < 0 then 2
if (i > 0 then 3
if (i = 0 then 20
определение случая 1 или 2
2. ( = 2(i + 2yi – 1
if ( ( 0 then 10
if ( > 0 then 20
определение случая 4 или 5
3. ( = 2(i + 2xi – 1
if ( ( 0 then 20
if ( > 0 then 30
выполнение шагов
шаг mH
10. xi = xi +1
(i = (i +2xi + 1
goto 1
шаг mD
20. xi = xi +1
yi = yi – 1
(i = (i +2xi – 2yi + 2
goto 1
шаг mV
30 yi = yi – 1
(i = (i – 2xi + 1
goto 1
4 finish

5. Растровая развёртка сплошных областей

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

6. Растровая развёртка многоугольников

Можно разработать эффективный метод растровой развёртки
многоугольников, если воспользоваться тем фактом, что соседние пикселы,
вероятно, имеют одинаковые характеристики (кроме пикселов граничных рёбер).
Это свойство называется пространственной когерентностью.
Характеристики пикселов на данной строке изменяются только там, где
ребро многоугольника пересекает строку. Эти пересечения делят сканирующую
строку на области.
Для простого многоугольника на рис. 2.7 строка 2 пересекает
многоугольник при x = 1 и x = 8.

Получаем три области:

x < 1 вне многоугольника
1 ( x ( 8 внутри многоугольника
x > 8 вне многоугольника
Строка 4 делится на пять областей:
x < 1 вне многоугольника
1 ( x ( 4 внутри многоугольника
4 < x < б вне многоугольника
б ( x ( 8 внутри многоугольника
x > 8 вне многоугольника

Совсем необязательно, чтобы точки пересечения для строки 4 сразу
определялись в фиксированном порядке (слева направо). Например, если
многоугольник задаётся списком вершин P1, P2, P3, P4, а список рёбер (
последовательными парами вершин P1P2, P2P3, P3P4, P4P5, P5P1, то для строки
4 будут найдены следующие точки пересечения с рёбрами многоугольника: 8, 6,
4, 1. Эти точки надо отсортировать в возрастающем порядке по x, т. е.
получить 1,4, 6, 8.
При определении интенсивности, цвета и оттенка пикселов на сканирующей
строке рассматриваются пары отсортированных точек пересечений. Для каждого
интервала, задаваемого парой пересечений, используется интенсивность или
цвет заполняемого многоугольника. Для интервалов между парами пересечений и
крайних (от начала строки до первой точки пересечения и от последней точки
пересечения до конца строки) используется фоновая интенсивность или цвет.
Точное определение тех пикселов, которые должны активироваться,
требует некоторой осторожности. Рассмотрим простой прямоугольник,
изображенный на рис. 2.8. Прямоугольник имеет координаты (1,1), (5,1),
(5,4), (1,4). Сканирующие строки с 1 по 4 имеют пересечения с ребрами
многоугольника при x = 1 и 5. Пиксел адресуется координатами своего левого
нижнего угла, значит, для каждой из этих сканирующих строк будут
активированы пикселы с x-координатами 1, 2, 3, 4 и 5. На рис. 2.8 показан
результат. Заметим, что площадь, покрываемая активированными пикселами,
равна 20, в то время как настоящая площадь прямоугольника равна 12.
Модификация системы координат сканирующей строки и теста активации
устраняет эту проблему, как это показано на рис. 2.8,b. Считается, что
сканирующие строки проходят через центр строк пикселов, т. е. через
середину интервала, как это показано на рис. 2.8,b. Тест активации
модифицируется следующим образом: проверяется, лежит ли внутри интервала
центр пиксела, расположенного справа от пересечения. Однако пикселы все еще
адресуются координатами левого нижнего угла. Как показано на рис.2.8,b,
результат данного метода корректен.
Горизонтальные ребра не могут пересекать сканирующую строку и, таким
образом, игнорируются. Это совсем не означает, что их нет на рисунке. Эти
ребра формируются верхней и нижней строками пикселов.
Дополнительная трудность возникает при пересечении сканирующей строки и
многоугольника точно по вершине, как это показано на рис. 2.9. При
использовании соглашения о середине интервала между сканирующими строками
получаем, что строка у = 3.5 пересечет многоугольник в 2, 2 и 8, т. е.
получится нечетное количество пересечений. Следовательно, разбиение
пикселов на пары даст неверный результат, т. е. пикселы (0,3), (1,3) и от
(3,3) до (7,3) будут фоновыми, а пикселы (2,3), (8,3), (9,3) окрасятся в
цвет многоугольника. Если учитывать только одну точку пересечения с
вершиной. Тогда для строки у = 3.5 получим правильный результат. Однако
результат применения метода к строке у = 1.5, имеющей два пересечения в
(5,1), показывает, что метод неверен. Для этой строки именно разбиение на
пары даст верный результат, т. е. окрашен будет только пиксел (5,1). Если
же учитывать в вершине только одно пересечение, то пикселы от (0,1) до
(4,1) будут фоновыми, а пикселы от (5,1) до (9,1) будут окрашены в цвет
многоугольника.
Правильный результат можно получить, учитывая точку пересечения в
вершине два реза, если она является точкой локального минимума или
максимума и учитывая один раз в противном случае. Определить локальный
максимум или минимум многоугольника в рассматриваемой вершине можно с
помощью проверки концевых точек двух ребер. Если у обоих рёбер у больше,
чем у вершины, значит, вершина является точкой локального минимума. Если
меньше, значит, вершина - точка локального максимума. Если одна больше, а
другая меньше, следовательно, вершина не является ни точкой локального
минимума, ни точкой локального максимума. На рис.2.10 точка Р1 - локальный
минимум, Р3 - локальный максимум, а Р2, Р4 - ни то ни другое.
Следовательно, в точках Р1 и Р3 учитываются два пересечения со сканирующими
строками, а в Р2 и Р4 - одно.

7. Алгоритм с упорядоченным списком рёбер

Используя описанные выше методы, можно разработать эффективные
алгоритмы растровой развертки сплошных областей, называемые алгоритмами с
упорядоченным списком ребер. Эффективность этих алгоритмов зависит от
эффективности сортировки. Приведём очень простой алгоритм.

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


Подготовить данные:
Используя сканирующие строки, проведенные через середины отрезков, т.
е. через у + Ѕ определить для каждого ребра многоугольника наивысшую
сканирующую строку, пересекаемую ребром.

Занести ребро многоугольника в у- группу, соответствующую этой
сканирующей строке.

Сохранить в связном списке значения: начальное значение координат x
точек пересечения, (y - число сканирующих строк, пересекаемых ребром
многоугольника, и ~ (x – шаг приращения по x при переходе от одной
сканирующей строки к другой.

Преобразовать эти данные в растровую форму:

Для каждой сканирующей строки проверить соответствующую у- группу на
наличие новых ребер. Новые ребра добавить в список активных рёбер.

Отсортировать координаты x точек пересечения из САР в порядке
возрастания; т. е. х1 предшествует x2, если х1 < х2


Выделить пары точек пересечений из отсортированного по
x списка. Активировать на сканирующей строке y пикселы для целых
значений x, таких, что x1 ( x + Ѕ ( x2. Для каждого ребра из САР
уменьшить (у на 1. Если (у < 0, то исключить данное ребро из САР.
Вычислить новое значение координат x точек пересечения xнов = xстар +
(x
Перейти к следующей сканирующей строке

В алгоритме предполагается, что все данные предварительно преобразованы
в представление, принятое для многоугольников.

8. Алгоритм заполнения по рёбрам

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

Алгоритм со списком ребер и флагом
Обрисовка контура:
Используя соглашения о середине интервала между сканирующими строками
для каждого ребра, пересекающего сканирующую строку, отметить самый
левый пиксел, центр которого лежит справа от пересечения;
т.е.
x + 1/2 > xпересечения
Заполнение:
Для каждой сканирующей строки, пересекающей многоугольник
Внутри = FALSE
for x = 0 (левая граница) to x = xmax, (правая граница)
if пиксел в точке x имеет граничное значение
then инвертировать значение переменной Внутри
if Внутри = TRUE then
присвоить пикселу в x значение цвета многоугольника
else
присвоить пикселу в x значение цвета фона
end if
next x

В данном алгоритме каждый пиксел обрабатывается только один раз, так
что затраты на ввод/вывод значительно меньше, чем в алгоритме со списком
рёбер, в результате чего, при его аппаратной реализации, он работает на
один-два порядка быстрее чем алгоритм с упорядоченным списком рёбер.

9. Алгоритмы заполнения с затравкой

В обсуждавшихся выше алгоритмах заполнение происходит в порядке
сканирования. Иной подход используется в алгоритмах заполнения с затравкой.
В них предполагается, что известен хотя бы один пиксел из внутренней
области многоугольника. Алгоритм пытается найти и закрасить все другие
пикселы, принадлежащие внутренней области. Области могут быть либо
внутренние, либо гранично-определенные. Если область относится к внутренне
- определенным, то все пикселы, принадлежащие внутренней части, имеют один
и тот же цвет или интенсивность, а все пикселы, внешние по отношению к
области, имеют другой цвет. Это продемонстрировано на рис. 2.10. Если
область относится к гранично-определенным, то все пикселы на границе
области имеют выделенное значение или цвет, как это показано на рис. 2.11.
Алгоритмы, заполняющие внутренне - определенные области, называются
внутренне - заполняющими, а алгоритмы для гранично-определённых областей –
гранично-заполняющими. Далее будут обсуждаться гранично-заполняющие
алгоритмы, однако соответствующие внутренне заполняющие алгоритмы можно
получить аналогичным образом.
Внутренне- или гранично-определённые области могут быть 4- или 8-
связными. Если область 4-связная, то любой пиксел в области можно достичь с
помощью комбинаций движений только в 4-х направлениях: налево, направо,
вверх, вниз. Для 8-и связной области добавляются ещё и диагональные
направления. Алгоритм заполнения 8-связной области заполнит и 4-связную, но
обратное не верно. Однако в ситуации, когда требуется заполнить разными
цветами две отдельные 4-связные области, использование 8-связного алгоритма
даст не верный результат. Далее речь пойдёт об алгоритмах для 4-связных
областей, однако их легко адаптировать и для 8-связных.

10. Построчный алгоритм заполнения с затравкой

Используя стек, можно разработать алгоритм заполнения гранично-
определенной области. Стек - это просто массив или другая структура данных,
в которую можно последовательно помещать значения и из которой их можно
последовательно извлекать. Как показывает практика, стек может быть
довольно большим. Зачастую в нём содержится дублирующаяся информация. В
построчном алгоритме заполнения с затравкой стек минимизируется за счёт
хранения только затравочного пиксела для любого непрерывного интервала на
сканирующей строке. Непрерывный интервал - это группа примыкающих друг к
другу пикселов (ограниченная уже заполненными или граничными пикселами). Мы
для разработки алгоритма используем эвристический подход, однако также
возможен и теоретический подход, основанный на теории графов.
Данный алгоритм применим гранично-определённым 4-связным областям,
которые могут быть как выпуклыми, так и не выпуклыми, а также могут
содержать дыры. В области, внешней и примыкающей к нашей, не должно быть
пикселов с цветом, которым область или многоугольник заполнятся. Схематично
работу алгоритма можно разбить на четыре этапа.

Построчный алгоритм заполнения с затравкой
Затравочный пиксел на интервале извлекается из стека, содержащего
затравочные пикселы.

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

В переменной Xлев и Xправ запоминаются крайний левый и крайний правый
пикселы интервала

В диапазоне Xлев ( x ( Xправ проверяются строки расположенные
непосредственно над в под текущей строкой. Определяется, есть ли на
них еще не заполненные пикселы. Если такие пикселы есть (т. е. не все
пикселы граничные, или уже заполненные), то в указанном диапазоне
крайний правый пиксел в каждом интервале отмечается как затравочный и
помещается в стек.

При инициализации алгоритма в стек помешается единственный затравочный
пиксел, работа завершается при опустошении стека. Ниже приводится более
подробное описание алгоритма на псевдокоде.



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

Затравка ( x, y ) выдаёт затравочный пиксел
Pop - процедура, которая извлекает пиксел из стека
Push - процедура, которая помещает пиксел в стек

инициируем стек
Push Затравка ( x, y )
While ( стек не пуст )
Извлекаем пиксел из стека и присваиваем ему новое значение Pop
Пиксел ( x, y )
Пиксел ( x, y ) = Нов_значение
сохраняем x- координату затравочного пиксела
Врем_х = x
заполняем интервал справа от затравки
x = x +1
while Пиксел ( x, y ) ( Гран_значение
Пиксел ( x, y ) = Нов_значение
x = x +1
end while
сохраняем крайний справа пиксел
Xправ = x (1
восстанавливаем x- координату затравки
x = Врем_х
заполняем интервал слева от затравки
x = x (1
while Пиксел ( x, y ) ( Гран_значение
Пиксел ( x, y ) = Нов_значение
x = x (1
end while
сохраняем крайний слева пиксел
Xлев = x +1
восстанавливаем x- координату затравки
x = Врем_х
проверим, что строка выше не является ни границей многоугольника, ни
уже полностью заполненной; если это не так, то найти затравку, начиная
с левого края подинтервала сканирующей строки
x = Xлев
y = y +1
while x ( Xправ
ищем затравку на строке выше
Флаг = 0
while ( Пиксел ( x, y ) ( Гран_значение and
Пиксел ( x, y ) ( Нов_значение and x < Xправ )
if Флаг = 0 then Флаг = 1
x = x + 1
end while
помещаем в стек крайний справа пиксел
if Флаг =1 then
if ( x = Xправ and Пиксел ( x, y ) ( Гран_значение
and Пиксел ( x, y ) ( Нов_значение ) then
Push Пиксел ( x, y )
else
Push Пиксел ( x ( 1, y )
end if
Флаг = 0
end if
продолжим проверку, если интервал был прерван
Xвход = x
while (( Пиксел ( x, y ) = Гран_значение or
Пиксел ( x, y ) = Нов_значение ) and x < Xправ)
x = x + 1
end while
удостоверимся что координата пиксела увеличена
if x = Xвход then x = x + 1
end while
проверим, что строка ниже не является ни границей многоугольника, ни
уже полностью заполненной
Эта часть алгоритма совершенно аналогична проверке для строки
выше, за исключением, того что вместо y = y + 1 надо подставить
y = y ( 1
end while
finish

3. Удаление невидимых линий и поверхностей

Задача удаления невидимых линий и поверхностей является одной из
наиболее сложных в машинной графике. Алгоритмы удаления невидимых линий и
поверхностей служат для определения линий ребер, поверхностей или объемов,
которые видимы или невидимы для наблюдателя, находящегося в заданной точке
пространства.
Необходимость удаления невидимых линий, ребер, поверхностей или объемов
проиллюстрирована рис.3.1. На рис.4.1, а приведен типичный каркасный чертеж
куба. Его можно интерпретировать двояко: как вид куба сверху, слева или
снизу, справа. Удаление тех линий или поверхностей, которые невидимы с
соответствующей точки зрения, позволяют избавиться от неоднозначности.
Результаты показаны на рис.4.1, b и c.
Сложность задачи удаления невидимых линий и поверхностей привела к
появлению большого числа, различных способов ее решения. Многие из них
ориентированы на специализированные приложения. Наилучшего решения общей
задачи удаления невидимых линий и поверхностей не существует. Для
моделирования процессов в реальном времени, например, для авиа тренажеров,
требуются быстрые алгоритмы, которые могут порождать результаты с частотой
видео генерации (30 кадр/с). Для машинной мультипликации требуются
алгоритмы, которые могут генерировать сложные реалистические изображения, в
которых представлены тени, прозрачность и фактура, учитывающие эффекты
отражения и преломления цвета в мельчайших оттенках. Подобные алгоритмы
работают медленно, и зачастую на вычисления требуется несколько минут или
даже часов. Строго говоря, учет эффектов прозрачности, фактуры, отражения и
т. п. не входит в задачу удаления невидимых линий или поверхностей.
Естественнее считать их частью процесса визуализации изображения. Процесс
визуализации является интерпретацией или представлением изображения или
сцены в реалистической манере. Однако многие из этих эффектов встроены в
алгоритмы удаления невидимых поверхностей и поэтому будут затронуты.
Существует тесная взаимосвязь между скоростью работы алгоритма и
детальностью его результата. Ни один из алгоритмов не может достигнуть
хороших оценок для этих двух показателей одновременно. По мере создания все
более быстрых алгоритмов можно строить все более детальные изображения.
Реальные задачи, однако, всегда будут требовать учета еще большего
количества деталей.
Алгоритмы удаления невидимых линий или поверхностей можно
классифицировать по способу выбора системы координат или пространства, в
котором они работают. Алгоритмы, работающие в объектном пространстве, имеют
дело с физической системой координат, в которой описаны эти объекты. При
этом получаются весьма точные результаты, ограниченные, вообще говоря, лишь
точностью вычислений. Полученные изображения можно свободно увеличивать во
много раз. Алгоритмы, работающие в объектном пространстве, особенно полезны
в тех приложениях, где необходима высокая точность. Алгоритмы же,
работающие в пространстве изображения, имеют дело с системой координат того
экрана, на котором объекты визуализируются. При этом точность вычислений
ограничена разрешающей способностью экрана. Результаты, полученные в
пространстве изображения, а затем увеличенные во много раз, не

Новинки рефератов ::

Реферат: Проблема обеспечения безопасности человека при воздействии звуковых и световых эффектов (Безопасность жизнедеятельности)


Реферат: Условия присоединения Украины к России (Политология)


Реферат: Защитные сооружения гражданской обороны, требования, предъявляемые к ним (Безопасность жизнедеятельности)


Реферат: Интенсивная технология возделывания озимой пшеницы (Сельское хозяйство)


Реферат: Институт гражданского общества (Право)


Реферат: Основы права (Право)


Реферат: Эффективность производства, анализ эффективности производства (Предпринимательство)


Реферат: Определение экономической эффективности участка на переменном и постоянном токе (Транспорт)


Реферат: Инновации в сельском хозяйстве (Инвестиции)


Реферат: "Стихотворения в прозе" И.С.Тургенева (Литература : русская)


Реферат: Проблемы и состояние страхового сектора в России (Страхование)


Реферат: Создание экспертной системы для анализа опасностей (Безопасность жизнедеятельности)


Реферат: Исследования химии в начале ХХ века (История)


Реферат: Богослужебные отпусты (Религия)


Реферат: Производственный менеджмент на предприятиях по производству металлоизделий (Менеджмент)


Реферат: Николай Второй (История)


Реферат: Бизнес-план АТС (Менеджмент)


Реферат: Новгородская феодальная республика (История)


Реферат: Банковская система Великобритании (Банковское дело)


Реферат: Немного из истории шитья (Технология)



Copyright © GeoRUS, Геологические сайты альтруист