Основная мысль в том, чтобы разбить триангулированный меш на множество колонн, которые имеют основание на плоскости xy.
Площадь поверхности треугольника проецируется на плоскость xy, умножается на среднюю координату z трех вершин - это даёт объем такой колонны. Суммирование по всем этим объемам даст в результате объем полного меша (смотри следующий рисунок).
Есть пара вещей, которые должны быть приняты во внимание. Во-первых, меш может оказаться расширенным вниз от плоскости xy. Если мы создаем колонну от грани, которая лежит ниже плоскости xy, произведение спроецированной площади и средней координаты z будет отрицательным числом, так что мы должны вычесть эту величину, чтобы получить объем.
Во-вторых, меш может лежать полностью или частично выше плоскости xy. Если мы взглянем на пример на рисунке сверху, мы увидим что объект имеет два треугольника, которые дают вклад в объем объекта, верхний и нижний (вертикальные треугольники имеют нулевую спроецированную площадь, так что они не дают никакого вклада). Так как обе верхняя и нижняя грани лежат выше плоскости xy, мы должны вычесть объем колонны, создаваемой от нижней грани из объёма, созданного верхней гранью. Если объект будет полностью ниже плоскости xy, он будет с другой стороны, и мы должны будем вычесть объем верхней колонны из объема нижней колонны.
Мы можем сказать, что действие, которое нужно выполнить, определяется направлением нормалей наших треугольников. Если, например, треугольник - выше плоскости xy, но его нормаль указывает вниз (она имеет отрицательный z-компонент), тогда мы должны вычесть рассчитанный объем. Следовательно важно, чтобы все нормали единообразно указывали наружу (в режиме
Если мы принимаем во внимание все четыре возможности (нормаль грани направлена вверх или вниз, грань выше или ниже плоскости xy), мы можем написать следующую схему для нашей функции:
1. Убедиться, что у всех граней нормали единообразно указывают наружу.
2. Для всех граней
• Вычислить z-компоненту вектора нормали грани Nz
• Вычислить произведение P среднего числа z-координат и площади спроецированной поверхности.
• Если Nz положительно: прибавить P
• Если Nz отрицательно: вычесть P
Этот отличный алгоритм работает для простых объектов без отверстий так же, как и для объектов, содержащих отверстия (например, тор), или даже полых (то есть, содержащих объект, полностью заключенный в другом объекте), примеры приведены на следующем скриншоте:
Поскольку мы допускаем, что произведение площади и координаты z может быть отрицательным, мы должны проверять только на направления нормали грани, чтобы охватить все ситуации.
Важная часть кода показана здесь (полный скрипт называется volume.py):
def meshvolume(me):
volume = 0.0
for f in me.faces:
xy_area = Mathutils.TriangleArea(vec(f.v[0].co[:2]),
vec(f.v[1].co[:2]),vec(f.v[2].co[:2]))
Nz = f.no[2]
avg_z = sum([f.v[i].co[2] for i in range(3)])/3.0
partial_volume = avg_z * xy_area
if Nz < 0: volume -= partial_volume
if Nz > 0: volume += partial_volume
return volume
Выделенный код показывает, как мы вычисляем площадь треугольника, спроектированного на плоскость xy.
После прогона скрипта из текстового редактора или из меню Scripts в режиме объектов, появляется сообщение, показывающее объем в единицах Блендера. Прежде, чем выполнять скрипт, убедитесь, что все модификаторы применены, масштабирование и вращение применено (Ctrl + A в режиме объектов), меш полностью триангулирован (
Определение центра масс меша