How can I obtain the volume of complex objects, in such a way that it can be used in a driver?
-
1volume of those parts or everything like a giant cylinder? – MikoCG Dec 20 '21 at 07:29
-
Oh, I’m sorry for that. I mean geometry like Suzanne monkey head. There’s plugin that can calculate it but its value cannot be copied/added as a driver. – Raditya Raksi Dec 20 '21 at 14:42
-
Does this answer your question? Is it possible to display volume of a mesh object? – Harry McKenzie Jan 13 '23 at 00:52
-
How does your object change throughout the animation? Does the volume of the object even change? If so, how? – Markus von Broady Jan 13 '23 at 11:38
2 Answers
Yes you can have a change in volume of a selected object drive another object's property. In this example, I am using the change in volume of the selected object (Cube) for driving the Y position of the sphere.
import bpy
import bmesh
bpy.app.handlers.depsgraph_update_post.clear()
obj = bpy.context.active_object
me = obj.data
bm = bmesh.new()
def drive_property(volume):
bpy.data.objects["Sphere"].location.y = volume / 2
def update_volume():
bm.clear()
bm.from_mesh(me)
bm.transform(obj.matrix_world)
bmesh.ops.triangulate(bm, faces=bm.faces)
volume = 0
for f in bm.faces:
v1 = f.verts[0].co
v2 = f.verts[1].co
v3 = f.verts[2].co
volume += v1.dot(v2.cross(v3)) / 6
print("Volume:", volume)
drive_property(volume)
def on_depsgraph_update(scene):
depsgraph = bpy.context.evaluated_depsgraph_get()
for update in depsgraph.updates:
if update.id.name == "Cube":
update_volume()
bpy.app.handlers.depsgraph_update_post.append(on_depsgraph_update)
- 10,995
- 8
- 23
- 51
-
1That's an interesting approximation. I don't quite understand the logic, it seems you could use the
f.normalinstead ofv2.cross(v3)? Maybe not, because the cross product is not normalized? I tested with solidify and it seemed to work with that, I think it works because opposite normals cancel each-other. I tested with it with a sphere, and a sphere with a quarter of it cut off, and it works wonderfully each time. I added an internal face to a cuboid and since it's just one face it should either add to or subtract from the volume but it stayed correct. What gives ?! – Markus von Broady Jan 13 '23 at 12:26 -
1I've dissolved one edge of the cuboid to make an extruded triangle with half volume of the cuboid (still correct volume displayed), then again added an internal face by ctrl+R, F, and volume stayed correct - but it's a single triangle, so what gives, the
v1.dot(v2.cross(v3)) / 6for this triangle is0? – Markus von Broady Jan 13 '23 at 12:29 -
1And once I have that internal face, moving the object around changes the volume for some reason… And internal face can be considered as producing invalid topology, but I still don't understand why creating the internal face doesn't change the volume by without moving the entire mesh/object... https://i.imgur.com/d4KjBPD.gif – Markus von Broady Jan 13 '23 at 12:38
-
@MarkusvonBroady when u calculate the volume of a mesh with internal face, say a cuboid with an internal face that splits it, the script will still work because it is iterating over all the faces of the mesh, regardless of whether they are internal or external. The script calculates the volume of each face as a tetrahedron and adds it to the total volume. When it reaches an internal face, it also calculates its volume as a tetrahedron and adds it to the total volume. Because the internal face is part of the mesh, it is included in the calculation. – Harry McKenzie Jan 13 '23 at 15:09
-
@MarkusvonBroady When the internal face is inside the mesh, it will have the opposite normal direction of the external faces, this means that the cross product of the vectors of the face will be pointing the opposite direction. So, the dot product will be negative. The volume of the tetrahedron formed by the internal face will be subtracted from the total volume. – Harry McKenzie Jan 13 '23 at 15:09
-
Here's the steps I taken: Check the number of faces: 5. Create a loopcut with Ctrl+R, check the number of faces: 8 (3 quads converted to 6 quads). Fill the loopcut with a single triangular face, recheck number of faces: 9. It's a single face even after triangulation, it's not doubled going in both directions, and the last step, just creating an internal face in existing loop doesn't in any way change coordinates of other vertices, and yet it adds another face's "volume". I also calculated the volume for that face and it is 0 - until you move the object, that is. – Markus von Broady Jan 13 '23 at 16:05
-
I was simply lucky that because the internal face was at Y=0, the calculation was yielding 0 for it, but when you move the object it's no longer the case. Also if you add internal faces not at Y=0. I still don't understand the logic and or limitations other than internal faces messing with the algorithm :D – Markus von Broady Jan 13 '23 at 16:06
-
wow oh i forgot about your gif that was pretty interesting haha i will try that tomorrow! but yeah its only supposed to work for manifold meshes XD – Harry McKenzie Jan 13 '23 at 16:25
Here's an answer that is almost in every way worse than the ingenious mathematical answer by Harry
✅ Good aspects of this answer:
- actually using a driver, which doesn't require running Python outside of sandbox mode (no security warnings)
- works with internal faces
- updates more immediately (not counting huge CPU lag) while editing the mesh in Edit Mode
- maybe it's more accurate for some geometries but I wasn't able to find an example
- you can use it to get a confirmation Harry's answer is correct even though the latter seems way too simple to be.
(sphere is Harry's answer, cylinder is mine)
❌ Bad aspects:
- doesn't work with internal holes like when using Solidify modifier
- slow as hell
- probably still less accurate than Harry's answer, despite the huge number of samples
- for the most part, needs the mesh to be watertight (but works with Susanne)
- maybe some more, again I didn't test thoroughly
Instructions
- ⭾ Tab to edit the default cube.
- MA Merge all vertices at center.
- Keep the vertex selected, ⭾ Tab to Object Mode.
- ⬆ ShiftA, E, P Add an empty.
- ⬆ Shift$\color{green}{█}\color{#888}{0█}$ click the single-vert "cube", so it becomes active but the empty stays selected.
- ✲ CtrlP, V Parent the empty to the vertex.
- Add the following geonodes setup to the single-vert "cube":
- $\color{#888}{█0}\color{green}{█}$ right-click a field of choice, Add Driver.
- In the popup window set the target object as the empty.
- Default settings should work, but since Harry divides the result by 2, you may also want to change the formula to
var / 2.
- 36,563
- 3
- 30
- 99



