12:04
Тестирование треугольника 3D — Лисья нора
§ Теория трехмерного треугольника
Technology3DNow!. Немного теории, которая гласит следующее.- Есть параметрическое уравнение линии, которое задается как точка вектора
N + t*NM. - И параметрическое уравнение плоскости, которая задается как сложение двух векторов
A + u*AB + v*AC
N + t*NM = A + u*AB + v*AC. Если это непонятно, то статью можно дальше не читать.Теперь я раскодирую вектора по координатам. Вектора имеют 3 точки в декартовой системе координат (x,y,z).
Здесь к примеру, NM.x = M.x - N.x, AC.x = C.x - A.x и так далее... Как и обычно, потребуется неизвестные (u,v,t) перенести в левую часть уравнений, а известное — в правую, что переписывается следующим образом. И еще сделаю замену (NM.x, NM.y, NM.z) на (dx, dy, dz):
u*AB.x + v*AC.x - t*dx = AN.x u*AB.y + v*AC.y - t*dy = AN.y u*AB.z + v*AC.z - t*dz = AN.zЗдесь AN.x = N.x - A.x. Если начальной точки нет, N=0, то остается лишь только
-(A.x,A.y,A.z). Надо найти решения уравнения, но из-за того что я уже раньше находил, не буду переписывать вывод формулы.A = dx(A.y*AC.z - A.z*AC.y) + dy(A.z*AC.x - A.x*AC.z) + dz(A.x*AC.y - A.y*AC.x) B = dx(A.z*AB.y - A.y*AB.z) + dy(A.x*AB.z - A.z*AB.x) + dz(A.y*AB.x - A.x*AB.y) C = A.x(AB.z*AC.y - AB.y*AC.z) + A.y(AB.x*AC.z - AB.z*AC.x) + A.z(AB.y*AC.x - AB.x*AC.y) D = dx(AB.z*AC.y - AB.y*AC.z) + dy(AB.x*AC.z - AB.z*AC.x) + dz(AB.y*AC.x - AB.x*AC.y)Вообще прекрасно видно, что коэффициенты вычисления 2x2 матриц совпадают для C и D, так что высчитывать их заново не придется. Теперь, зная все коэффициенты, вычислить (u,v,t) можно легко
u = A/D, v=B/D, t=C/D.Особенность использования t в том, что оно задает параметр линии, а поскольку конечная точка вычисляется как t*(dx,dy,dz) то как можно заметить, при фиксированном dz число t пропорционально глубине. Это означает, что вычислять можно только один раз за кадр коэффициент C, и использовать его для всего треугольника, но, по правде говоря, меняя D, ведь t=C/D, где C-константа для кадра, а вот D меняется в зависимости от рисуемой сейчас в данный момент точки на экране. Так что как бы так не было, а делить число придется. От деления никуда не избавиться.
Вторая особенность заключается в том, что коэффициенты при C или D задают нормаль треугольника, так что это можно еще использовать для расчета освещения, например, или уровня наклона к камере.
§ Вычисления
Можно попробовать сделать предрасчет треугольника перед тем как его рендерить.A1,A2,A3 = A.y*AC.z - A.z*AC.y, A.z*AC.x - A.x*AC.z, A.x*AC.y - A.y*AC.x B1,B2,B3 = A.z*AB.y - A.y*AB.z, A.x*AB.z - A.z*AB.x, A.y*AB.x - A.x*AB.y C1,C2,C3 = AB.z*AC.y - AB.y*AC.z, AB.x*AC.z - AB.z*AC.x, AB.y*AC.x - AB.x*AC.yКогда начинается растеризация треугольника, то начинает бросаться луч в различные точки экрана в (dx,dy,dz). Здесь dz всегда фиксированное и по сути означает фокусное расстояние или FOV, для экрана размером 320 на 200 выбирается расстояние вдвое меньшее чем высота, то есть dz=100.
Для dx=-160 до 160, dy = -100 до 100, получается что луч пробегает все точки на экране (их 64000), бросая луч и проверяя точку пересечения с треугольником:
D = (C1*dx + C2*dy + C3*dz) u = (A1*dx + A2*dy + A3*dz) / D v = (B1*dx + B2*dy + B3*dz) / D t = (C1*A.x + C2*A.y + C3*A.z) / DЯсное дело, что таким методом крайне накладно вычислять треугольник. Каждый раз вычислять u,v,t необязательно, поскольку при инкременте x+1 добавляется к числителю +A1, +B1 (u, v соответственно) и к знаменателю +C1. Достаточно одного лишь сложения, но с делением конечно же, дела обстоят хуже.
§ Рисование
Представим себе, что существуют 3 точки прямо перед камерой, которая смотрит в сторону (0,0,1):Теперь надо рассчитать разности у векторов AB, AC:
А после этого рассчитать и параметры треугольника.
Как заметить можно, тут используется 18 умножении и 9 вычитаний. С точки зрения вычисления на верилоге, с учетом наличия DSP модулей, это даст 9 тактов при частоте 25 мгц + 1 такт на подсчет разностей. Можно, при наличии большого количества DSP, все за 1 такт подсчитать.
И сам цикл рисования.