Получение фактических трехмерных координат точки на треугольнике, который был сглажен в 2 измерения
Это немного сложная проблема, поэтому я сделаю все возможное, чтобы разбить ее на куски.
Я пишу библиотеку 3D Python для обучения / развлечения (в отличие от той, которую я собирался использовать для других). В разработанной мною системе трехмерные точки обычно сглаживаются на изображении следующим образом:
- Увеличение индекса Z на
width
перемещает точку на полпути к точке схода в центре. - В
Z = 0
значения X и Y соответствуют непосредственно пикселю в X, Y.
(Для этого метода может быть имя, но если оно есть, я не знаком с ним.)
В Python:
# vx and vy are the vanishing point's coordinates
def flatten_point(width, vx, vy, x, y, z):
distance = (x - vx, y - vy)
flat_distance = [d / (1 + float(z) / width) for d in distance]
return (vx + flat_distance[0], vx + flat_distance[1])
На данный момент я могу довольно эффективно создавать треугольники, сглаживая их вершины и используя барицентрические координаты, чтобы найти и заполнить пиксели, которые попадают между этими тремя точками. Это работает достаточно хорошо, если мне не нужно ничего знать о фактических точках на треугольнике, которым соответствуют эти пиксели, но если я хочу заштриховать треугольник так, чтобы более глубокие точки были нарисованы темнее, мне нужно знать, на какой незафиксированной точке треугольник, которому соответствует пиксель.
joriki на math.stackexchange рекомендует использовать барицентрические координаты в качестве весов, чтобы найти исходную точку. Это действительно работало некоторое время - и, вероятно, сработало бы, если бы я использовал линейную систему глубины - но оно разваливается, когда глубины точек треугольника достаточно различаются. Треугольник, кажется, приближается к наибольшей глубине быстрее, чем на самом деле, как если бы он был изогнут назад.
Итак, вкратце: как я могу повернуть функцию сглаживания точек, чтобы получить фактическую трехмерную точку произвольного 2D-пикселя на плоском треугольнике? В качестве альтернативы, если есть лучший / более эффективный способ сглаживания треугольников без потери глубины каждого пикселя, это также сработает.
1 ответ
Вы правы в том, что проблема заключается в том, что ваши значения глубины не являются линейными. К счастью, решение простое, но немного дороже, если рассчитывать на пиксели.
Используя ваши барицентрические координаты, а не интерполируя три компонента Z напрямую, вам нужно интерполировать их инверсию и реверсировать результат. Это называется перспективной коррекцией.
Пример только для Z:
def GetInterpolatedZ(triangle, u, v):
z0 = 1.0 / triangle[0].z
z1 = 1.0 / triangle[1].z
z2 = 1.0 / triangle[2].z
z = z0 + u * (z1-z0) + v * (z2-z0)
return 1.0/z
С triangle
список из трех векторов и u
а также v
барицентрические координаты для triangle[1]
а также triangle[2]
соответственно. Вам нужно будет переназначить свои Z до и после делений, если они смещены.
Если вы хотите интерполировать фактические координаты X и Y, вы делаете нечто подобное. Вам нужно будет интерполировать x/z и y/z и переопределить результат путем умножения на z.
def GetInterpolatedZ(tri, u, v):
t0 = Vec3(tri[0].x/tri[0].z, tri[0].y/tri[0].z, 1.0/tri[0].z)
t1 = Vec3(tri[1].x/tri[1].z, tri[1].y/tri[1].z, 1.0/tri[1].z)
t2 = Vec3(tri[2].x/tri[2].z, tri[2].y/tri[2].z, 1.0/tri[2].z)
inter = t0 + u * (t1-t0) + v * (t2-t0)
inter.z = 1.0 / inter.z
inter.x *= inter.z
inter.y *= inter.z
return inter
Снова, tri
это список из трех векторов и u, v
барицентрические координаты для tri[1], tri[2]
, Vec3
является регулярным трехкомпонентным евклидовым векторным типом.