Студопедия — D-отсечение
Студопедия Главная Случайная страница Обратная связь

Разделы: Автомобили Астрономия Биология География Дом и сад Другие языки Другое Информатика История Культура Литература Логика Математика Медицина Металлургия Механика Образование Охрана труда Педагогика Политика Право Психология Религия Риторика Социология Спорт Строительство Технология Туризм Физика Философия Финансы Химия Черчение Экология Экономика Электроника

D-отсечение






В пунктах 3.6.1 и 3.6.2 делался упор на 2D-отсечение, т.е. отсечение экраном уже спроецированного полигона. Еще один метод - это 3D-отсечение, когда все полигоны отсекаются областью зрения камеры. В этом случае после проецирования полигон заведомо попадает в экран и дальнейшее отсечение уже не требуется.

Кстати, z-отсечение при 3D-отсечение делается почти автоматически, очень хорошо вписываясь в общую схему, при использовании же 2D-отсечения придется делать еще и его.

Рассмотрим стандартную камеру. Ее область зрения задается "пирамидой", ограниченной пятью плоскостями со следующими уравнениями (откуда взялось smallvalue и что это такое, написано в п.3.5):

 

z = -dist + smallvalue

y = (z + dist) * ySize / (2 * dist)

y = -(z + dist) * ySize / (2 * dist)

x = (z + dist) * xSize / (2 * dist)

x = -(z + dist) * xSize / (2 * dist)

Вот рисунок (вид сбоку), на котором видно первые три из этих плоскостей.

y

| ===

| | ===

| ===

| ===|

| === |

=|= |

----*==-|-------O-----------z

=|= |

| === |

| ===|

| ===

| | ===

| ===

|

Отсекаем полигон каждой из этих плоскостей по тому же самому алгоритму Сазерленда-Ходжмана, получаем 3D-отсечение.

Теперь выясним, как это самое отсечение сделать относительно универсально (а не только для стандартной камеры), быстро и просто. Зададим наши пять плоскостей не в форме какого-то уравнения, а в форме

plane = [o, n],

где o - какая-то точка, принадлежащая плоскости; n - нормаль, смотрящая в то полупространство, которое мы хотим оставить. Например, для стандартной камеры в этом случае плоскости запишутся так:

n = (0, 0, 1), o = (0, 0, -dist + smallvalue)

n = (0, -dist, ySize/2), o = (0, 0, -dist)

n = (0, dist, ySize/2), o = (0, 0, -dist)

n = (-dist, 0, xSize/2), o = (0, 0, -dist)

n = (dist, 0, xSize/2), o = (0, 0, -dist)

При такой форме задания плоскости критерий принадлежности произвольной точки p нужному нам полупространству выглядит очень просто:

(p - o) * n >= 0.

Не менее просто выглядит и процедура поиска пересечения отрезка от точки p1 до точки p2 с плоскостью. Для любой точки p внутри отрезка имеем

p = p1 + k * (p2 - p1), 0 <= k <= 1,

но так как p лежит в плоскости, p * n = 0; отсюда имеем

(p1 * n) + (k * (p2 - p1) * n) = 0,

k = -((p2 - p1) * n) / (p1 * n) =

= (p1 * n - p2 * n) / (p1 * n) =

= 1 - (p2 * n) / (p1 * n).

и моментально находим точку пересечения. Все 3D-отсечение, таким образом, сводится к последовательному применению одной универсальной процедуры отсечения плоскостью. Кроме того, видно, что можно посчитать матрицу перевода стандартной камеры в произвольную, применить ее к выписанным точкам o и нормалям n для плоскостей, задающих "стандартную" область зрения (к нормалям, естественно, надо применить только "поворотную" часть матрицы) и получить, таким образом, уравнения плоскостей уже для *любой* камеры. Тогда 3D-отсечение можно сделать вообще до всяческих преобразований сцены, минимизировав, таким образом, количество поворотов и проецирований вершин - не попавшие в область зрения вершины поворачивать и проецировать, очевидно, не надо. Проецирования невидимых вершин, впрочем, можно избежать и другим образом: сделав поворот сцены, а потом 3D-отсечение "стандартной" областью зрения камеры.

Рассмотрим это более подробно. Пусть у нас есть какая-то камера; пусть есть матрица, которая переводит стандартную камеру в эту камеру. Она как бы состоит из двух частей: матрицы T (обозначения здесь использутся те же самые, что в п.2.5) и матрицы параллельного переноса, совмещающей Ss и s (обозначим ее буквой M). Причем сначала применяется матрица M, потом матрица T. Так вот, для перевода какой-то плоскости-ограничителя области зрения стандартной камеры, заданной в форме plane = [o,n], надо всего лишь сделать пару матричных умножений (поскольку M - матрица переноса, и ее применение на деле сводится к трем сложениям, матричных умножений будет ровно два):

new_o = T * M * std_o

new_n = T * std_n

Что лучше и быстрее, как обычно, не ясно. При отсечении до преобразований тест на попадание точки в область зрения стоит от 3 до 15 умножений (относительно дешевые операции типа сложений не считаем), плюс 11 умножений и 2 деления на поворот и проецирование после отсечения, зато поворачиваются и проецируются только видимые точки. При отсечении после преобразований тест стоит 8 умножений (так как в координатах нормалей шесть нулей и одна единица), зато для всех точек придется сделать 9 умножений для поворота;

проецироваться же по-прежнему будут только видимые точки. Так что наиболее подходящий метод выбирайте сами.

В завершение осталось только привести процедуру для отсечения полигона произвольной плоскостью:

// вычитание векторов

float vecsub(vertex *result, vertex a, vertex b) {

result->x = a.x - b.x;

result->y = a.y - b.y;

result->z = a.z - b.z;

}

// скалярное умножение векторов

float vecmul(vertex a, vertex b) {

return a.x * b.x + a.y * b.y + a.z * c.z;

}

// dst - массив для сохранения вершин результата

// src - массив вершин исходного полигона

// num - число вершин исходного полигона

// n - нормаль к плоскости

// o - точка, лежащая в плоскости

// функция возвращает число вершин результата

int clipPlane(vertex *dst, vertex *src, int num, vertex n, vertex o) {

int i, r;

vertex p1, p2, tmp;

float t1, t2;

float k;

r = 0;

for (i = 0; i < num; i++) {

p1 = src[i];

p2 = src[(i + 1) % num];

vecsub(&tmp, p1, o); t1 = vecmul(tmp, n);

vecsub(&tmp, p2, o); t2 = vecmul(tmp, n);

if (t1 >= 0) { // если начало лежит в области

dst[r++] = p1; // добавляем начало

}

if (((t1 > 0) && (t2 < 0)) || // если ребро пересекает границу

((t2 >= 0) && (t1 < 0))) // добавляем точку пересечения

{

k = 1 - vecmul(p1, n) / vecmul(p2, n);

dst[r].x = p1.x + k * (p2.x - p1.x);

dst[r].y = p1.y + k * (p2.y - p1.y);

dst[r].z = p1.z + k * (p2.z - p1.z);

dst[r].u = p1.u + k * (p2.u - p1.u);

dst[r].v = p1.v + k * (p2.v - p1.v);

r++;

}

}

return r;

}

Точное

Задача текстурирования формулируется таким образом: есть грань – согласно предположениям, треугольная - с наложенной на нее текстурой. То есть каждая точка грани окрашена цветом соответствующей ей точки в текстуре. Текстура накладывается линейным образом. Есть точка экрана с координатами на экране (sx,sy), принадлежащая проекции грани. Требуется найти ее цвет, то есть цвет соответствующей этой точке экрана точки текстуры. А для этого надо найти координаты текстуры для этой точки - точнее, для той точки, проекцией которой на экран является наша (sx,sy). Пусть вершины грани есть точки A(Ax,Ay,Az), B(Bx,By,Bz) и C(Cx,Cy,Cz), а соответствующие им точки текстуры - (Au,Av), (Bu,Bv) и (Cu,Cv). Найдем координаты текстуры для точки, проекцией которой является (sx,sy).

Для точек (x,y,z), проекцией которых является (sx,sy) имеем:

sx = xSize/2+x*dist/(z+dist),

sy = ySize/2-y*dist/(z+dist).

Для упрощения формул будем использовать обозначения

i = sx-XSize/2,

j = YSize/2-sy,

Z = z+dist.

Тогда эти формулы примут вид

i = x*dist/Z,

j = y*dist/Z,

или, что равносильно:

i*Z = x*dist,

j*Z = y*dist.

Рассмотрим точку D, принадлежащую грани. Для нее D = A+a*(B-A)+b*(C-A), так как она лежит в грани. D однозначно задается парой (a,b). Для нее координаты текстуры (из того, что текстура накладывается линейно) будут такие:

Du = Au+a*(Bu-Au)+b*(Cu-Au),

Dv = Av+a*(Bv-Av)+b*(Cv-Av).

Пусть проекция D на экран как раз и имеет координаты (sx,sy), тогда для нее выполнены написанные выше соотношения:

i*DZ = Dx*dist,

j*DZ = Dy*dist.

Подставим сюда координаты D, выраженные через координаты A, B и неизвестные коэффициенты a, b:

 

i*(Az+a*(Bz-Az)+b*(Cz-Az)+dist) = dist*(Ax+a*(Bx-Ax)+b*(Cx-Ax)),

j*(Az+a*(Bz-Az)+b*(Cz-Az)+dist) = dist*(Ay+a*(By-Ay)+b*(Cy-Ay)),

 

т.к. мы договорились, что AZ = Az+dist, и, кстати, поэтому BZ-AZ = Bz-Az, это можно чуть укоротить:

 

i*(AZ+a*(BZ-AZ)+b*(CZ-AZ)) = dist*(Ax+a*(Bx-Ax)+b*(Cx-Ax)),

j*(AZ+a*(BZ-AZ)+b*(CZ-AZ)) = dist*(Ay+a*(By-Ay)+b*(Cy-Ay)).

 

Выделим a и b:

 

a*(i*(BZ-AZ)-dist*(Bx-Ax))+b*(i*(CZ-AZ)-dist*(Cx-Ax)) = dist*Ax-i*AZ,

a*(j*(BZ-AZ)-dist*(By-Ay))+b*(j*(CZ-AZ)-dist*(Cy-Ay)) = dist*Ay-j*AZ.

 

Получили систему двух линейных уравнений, из которой можно найти a и b, а по ним немедленно вычисляются u и v. Введем вектор M = BA (Mx = Bx-Ax и т.д.) и вектор N = CA, обозначим d = dist (все это для краткости записи). Тогда эти два уравнения перепишутся в виде:

 

a*(i*Mz-d*Mx)+b*(i*Nz-d*Nx) = d*Ax-i*AZ,

a*(j*Mz-d*My)+b*(j*Nz-d*Ny) = d*Ay-j*AZ,

 

и решая систему (например, по формулам Крамера) получаем:

 

(dAx-iAZ)(jNz-dNy)-(dAy-jAZ)(iNz-dNx)

a = ------------------------------------- =

(iMz-dMx)(jNz-dNy)-(iNz-dNx)(jMz-dMy)

 

djAxNz-ddAxNy-ijAZNz+idAZNy-diAyNz+ddAyNx+ijNzAZ-djAZNx

= ------------------------------------------------------- =

ijMzNz-idMzNy-djMxNz+ddMxNy-ijMzNz+idNzMy+djNxMz-ddNxMy

 

dj(AxNz-AZNx)+dd(AyNx-AxNy)+id(AZNy-AyNz)

= ----------------------------------------- =

id(MyNz-MzNy)+dj(NxMz-MxNz)+dd(MxNy-NxMy)

 

i(AZNy-AyNz)+j(AxNz-AZNx)+d(AyNx-AxNy)

= --------------------------------------

i(MyNz-MzNy)+j(NxMz-MxNz)+d(MxNy-NxMy)

 

аналогично получаем

 

i(AZMy-AyMz)+j(AxMz-AZMx)+d(AyMx-AxMy)

b = --------------------------------------

i(MyNz-MzNy)+j(NxMz-MxNz)+d(MxNy-NxMy)

 

Знаки умножения здесь везде опущены, иначе читать это все совсем невозможно.

 

Осталось немного, подставить Mx = Bx-Ax и так далее, а потом подставить эти a и b в формулы для Du и Dv. В процессе подстановок что-то сократится, что-то упростится, но формулы для Du и Dv все равно получатся длиной в несколько строк.

 

Но из этих формул видно кое-что интересное. А именно, то, что

 

u = (C1*sx+C2*sy+C3) / (C4*sx+C5*sy+C6),

v = (C7*sx+C8*sy+C9) / (C4*sx+C5*sy+C6),

 

причем C1,..., C9 - просто какие-то коэффициенты, зависящие от грани. То есть, можно посчитать эти коэффициенты один раз на грань, а потом считать u, v по написанным пару строк выше формулам. Но все равно получается как минимум одно деление на точку. Это слишком медленно. Поэтому все методы текстурирования на самом деле используют приближенные вычисления, хотя и именно по этим формулам.

 

Стоит отметить тот факт, что на самом деле здесь грань не обязательно должна быть треугольной - можно взять любые три вершины многоугольной грани. То же самое справедливо и для остальных описанных методов текстурирования.


 







Дата добавления: 2015-10-02; просмотров: 418. Нарушение авторских прав; Мы поможем в написании вашей работы!



Композиция из абстрактных геометрических фигур Данная композиция состоит из линий, штриховки, абстрактных геометрических форм...

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

ТЕОРЕТИЧЕСКАЯ МЕХАНИКА Статика является частью теоретической механики, изучающей условия, при ко­торых тело находится под действием заданной системы сил...

Теория усилителей. Схема Основная масса современных аналоговых и аналого-цифровых электронных устройств выполняется на специализированных микросхемах...

Типология суицида. Феномен суицида (самоубийство или попытка самоубийства) чаще всего связывается с представлением о психологическом кризисе личности...

ОСНОВНЫЕ ТИПЫ МОЗГА ПОЗВОНОЧНЫХ Ихтиопсидный тип мозга характерен для низших позвоночных - рыб и амфибий...

Принципы, критерии и методы оценки и аттестации персонала   Аттестация персонала является одной их важнейших функций управления персоналом...

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

Ведение учета результатов боевой подготовки в роте и во взводе Содержание журнала учета боевой подготовки во взводе. Учет результатов боевой подготовки - есть отражение количественных и качественных показателей выполнения планов подготовки соединений...

Сравнительно-исторический метод в языкознании сравнительно-исторический метод в языкознании является одним из основных и представляет собой совокупность приёмов...

Studopedia.info - Студопедия - 2014-2024 год . (0.011 сек.) русская версия | украинская версия