How can I obtain the volume of complex objects, in such a way that it can be used in a driver?
$\begingroup$
$\endgroup$
4
-
1$\begingroup$ volume of those parts or everything like a giant cylinder? $\endgroup$– MikoCGCommented Dec 20, 2021 at 7:29
-
$\begingroup$ 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. $\endgroup$– Raditya RaksiCommented Dec 20, 2021 at 14:42
-
$\begingroup$ Does this answer your question? Is it possible to display volume of a mesh object? $\endgroup$– Harry McKenzie ♦Commented Jan 13, 2023 at 0:52
-
$\begingroup$ How does your object change throughout the animation? Does the volume of the object even change? If so, how? $\endgroup$– Markus von BroadyCommented Jan 13, 2023 at 11:38
Add a comment
|
2 Answers
$\begingroup$
$\endgroup$
8
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)
-
1$\begingroup$ That's an interesting approximation. I don't quite understand the logic, it seems you could use the
f.normal
instead 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 ?! $\endgroup$ Commented Jan 13, 2023 at 12:26 -
1$\begingroup$ I'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)) / 6
for this triangle is0
? $\endgroup$ Commented Jan 13, 2023 at 12:29 -
1$\begingroup$ And 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... i.imgur.com/d4KjBPD.gif $\endgroup$ Commented Jan 13, 2023 at 12:38
-
$\begingroup$ @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. $\endgroup$– Harry McKenzie ♦Commented Jan 13, 2023 at 15:09
-
$\begingroup$ @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. $\endgroup$– Harry McKenzie ♦Commented Jan 13, 2023 at 15:09
$\begingroup$
$\endgroup$
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
.