The 3D print toolbox currently only outputs the volume/area of all faces.
How can I get the volume of selected mesh objects, ignoring certain faces?
Asking on behalf of a user who mailed me.
Blender Stack Exchange is a question and answer site for people who use Blender to create 3D graphics, animations, or games. It only takes a minute to sign up.
Sign up to join this communityThis can be done using the Python API to get the mesh with modifiers applied, then applying the transform matrix.
The following script applies to all selected objects, showing a popup with the final volume. Not that it does not use units or scene scale.
See is_face_volume
for the method of checking if a face should be included in volume calculations.
import bpy
from bpy import context
# Quick way to test with/without hidden faces
USE_FILTER_FACES = True
def report_info(title="", message=""):
# show in console
print(title, message)
# show in popup
def draw_cb(self, context):
self.layout.label(text=message)
context.window_manager.popup_menu(draw_func=draw_cb, title=title, icon='INFO')
def is_face_skip(f):
"""Ignore faces that pass this test!"""
return f.hide is False
# You may want to filter based on material.
# return f.material_index == 0
def bmesh_from_object_final(ob):
import bmesh
matrix = ob.matrix_world
me = ob.to_mesh()
me.transform(matrix)
bm = bmesh.new()
bm.from_mesh(me)
if USE_FILTER_FACES:
faces_remove = [f for f in bm.faces if not is_face_skip(f)]
for f in faces_remove:
bm.faces.remove(f)
return (bm, matrix.is_negative)
def volume_and_area_from_object(ob):
bm, is_negative = bmesh_from_object_final(ob)
volume = bm.calc_volume(signed=True)
area = sum(f.calc_area() for f in bm.faces)
bm.free()
if is_negative:
volume = -volume
return volume, area
def main():
volume = 0.0
area = 0.0
object_count = 0
for ob in context.selected_objects:
if ob.type != 'MESH':
continue
volume_single, area_single = volume_and_area_from_object(ob)
volume += volume_single
area += area_single
object_count += 1
volume = abs(volume)
report_info(
title="From %d object(s)" % object_count,
message="Volume: %.4f, Area: %.4f" % (volume, area),
)
if __name__ == "__main__":
main()