-
Notifications
You must be signed in to change notification settings - Fork 264
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Mesh split and disassemble/assemble animation #498
Comments
just choose a large number. Long time ago I did this (inspired by the famous from vedo import dataurl, Volume, Axes, show
from vedo.applications import Animation
iso = Volume(dataurl+"embryo.tif").isosurface(80)
meshes = iso.splitByConnectivity(maxdepth=40)
axes = Axes(meshes[0]) # build axes manually
for m in meshes:
cm = m.centerOfMass()
m.pos(cm*7) # explode meshes
# show(meshes, axes=1).close()
anim = Animation() # a vedo.Plotter object
anim.timeResolution = 0.01 # secs
anim.fadeIn(meshes[1:], t=0, duration=0.2)
anim.fadeIn(meshes[0], t=1, duration=1)
# anim.fadeIn(axes, t=0, duration=0.2) # will not work right now!
for m in meshes:
anim.move(m, (0,0,0), style="quadratic")
anim.rotate(m, axis="y", angle=360)
anim.totalDuration = 5 # can now shrink/expand total duration
anim.play()
# edit with https://ezgif.com/ I thought nobody would ever care about.. so it's a bit outdated and not well tested, but it should work for simple things, or you can create your own animation by moving objects in a loop. Check out |
Thanks Marco, Appreciated, the animation looks quite cool I will play with it and see what kind of adaptations I might be able to do.
It wouldn't make more sense the mesh to be split to the exact given number instead of just giving a large number. This might also be not desired, since someone might just want to split the mesh in 3-4 big pieces instead and keeping all the initial structure. |
Uhm since they have a "GroupIds" array you can also use |
Hmm, actually the
You can see one of the segmented parts is loaded "wrongly" which leads to a faulty split. |
I don't quite understand why that happens... maybe the pieces are slightly overlapping so that they cannot be split (?) The thresholding works though: import vedo as vd
path = "data/vedo/DoraColumn_Reassembled/"
m = vd.Mesh(path+"DoraColumn_Reassembled.obj").print()
m0 = m.clone().threshold("GroupIds",-0.5,0.5, on="cells").texture(path+"DoraColumn1_med.jpg")
m1 = m.clone().threshold("GroupIds", 0.5,1.5, on="cells").texture(path+"DoraColumn2_med.jpg")
m2 = m.clone().threshold("GroupIds", 1.5,2.5, on="cells").texture(path+"DoraColumn3_med.jpg")
m3 = m.clone().threshold("GroupIds", 2.5,3.5, on="cells").texture(path+"DoraColumn4_low.jpg")
m4 = m.clone().threshold("GroupIds", 3.5,4.5, on="cells").texture(path+"DoraColumn5_low.jpg")
m5 = m.clone().threshold("GroupIds", 4.5,5.5, on="cells").texture(path+"DoraColumn6_low.jpg")
vd.show(m, at=0, shape="6/1", axes=1, sharecam=0)
vd.show(m0, "piece 0", at=1)
vd.show(m1, "piece 1", at=2)
vd.show(m2, "piece 2", at=3)
vd.show(m3, "piece 3", at=4)
vd.show(m4, "piece 4", at=5)
vd.show(m5, "piece 5", at=6)
vd.interactive() |
Thanks a lot. Yes, it is really strange. Actually every obj file that I load it has one of the pieces always multicolored, I do not think it is overlapping or something. If you try the Tombstone attachment you will see the same issue. |
It is multicolored because I dont have a good explanation for the split method.. |
Using the The threshold alternative is ok but it considers too much manual work :-(. Also any idea why the texture was not loaded correctly? |
I still think that the meshes might be overlapping ..
why do you say that? |
They should not, because in Meshlab when I use the select by faces tool (which selects all the connected faces) and pick faces on each one of the sub-meshes I get the individual pieces. Thus this means that they should not, otherwise if two pieces were overlapping I would be getting both selected. Because in your example with the threshold alternative while you are loading the texture file still the texture is not showing on the objects. |
Hi @marcomusy, Why the position of the object is not set o (0,0,0): I am loading the file with
|
It looks normal. A |
yes! |
Please whenever possible post the full working code. This seems to work ok: from vedo import *
from vedo.applications import Animation
mesh_models = load("tombstone/Tombstone*_low.obj")
grid = Grid(sx=1500, sy=2000, resx=3, resy=2)
gpts = Points(grid.cellCenters())
anim = Animation() # a vedo.Plotter object
anim.timeResolution = 0.01 # secs
anim.totalDuration = 5 # can shrink/expand duration
anim.fadeIn(mesh_models, t=0, duration=0.2)
anim.fadeIn(grid, t=0, duration=0.2)
anim.fadeIn(gpts, t=0, duration=0.2)
for i, mm in enumerate(mesh_models):
mm.rotateX(70).color(i)
anim.move(mm, grid.cellCenters()[i])
anim.show() # needed on mac OSX, press q
anim.play() |
either you specify Also you can remove the z-axis just by setting |
Hi @marcomusy, Aside of the disassemble/assemble animation is there a way to fracture a mesh into multiple pieces. Something similar to this addon from Blender https://www.youtube.com/watch?v=ZG_ZMnKzVTQ. Imagine you have a solid (or non solid, which I guess it would need to be solidified somehow maybe by using the volume???) sphere (this could be any 3D mesh) and then I want to fracture this in random pieces where each piece is fractured differently from the other. Then when you put the pieces back together you should get the original sphere. The fracturing though I would prefer not to be in a sharp cut like a slice, though it might contain such fractures but not only such. I would like to have something similar like when you break an object and you can get any possible fracture as kind of exemplified in the blender addon in the video. |
yes. try: from vedo import *
import numpy as np
np.random.seed(0)
s = Sphere(quads=True, res=15).clean()
res = 0.02 #control the tetras resolution
# fill the space w/ points
pts = (np.random.rand(10000, 3)-0.5)*2
fillpts = s.insidePoints(pts).subsample(res).scale(0.9) # make pts uniform
seeds = s.clone().subsample(0.3).ps(12).c('black') # pick uniform pts on sphere
printc("# of pieces, #points in sphere:", seeds.N(), fillpts.N())
tmesh = delaunay3D(merge(fillpts,s))
# assign a closest point to each tetrahedron
cids = []
for p in tmesh.cellCenters():
cid = seeds.closestPoint(p, returnPointId=True)
cids.append(cid)
tmesh.celldata["fragment"] = np.array(cids)
pieces = []
for i in range(seeds.NPoints()):
tc = tmesh.clone().threshold(above=i-0.1, below=i+0.1)
mc = tc.tomesh(fill=False).color(i)
pieces.append(mc)
############### animate
plt = Plotter(interactive=1)
plt.show(pieces, seeds, "press q to make it explode")
for i in range(15):
for pc in pieces:
cm = pc.centerOfMass()
pc.shift(cm/15)
plt.render()
plt.interactive().close() press |
PS: because it relies in |
"""Add a custom scalar to a TetMesh to segment it.
Press q to make it explode"""
from vedo import TetMesh, Plotter, dataurl, printc
n = 20000
f1 = 0.005 # control the tetras resolution
f2 = 0.15 # control the nr of seeds
tmesh = TetMesh(dataurl+'limb_ugrid.vtk')
surf = tmesh.tomesh(fill=False)
# pick uniform pts on the surface
seeds = surf.clone().subsample(f2).ps(10).c('black')
printc("#pieces:", seeds.N())
# assign to each tetrahedron the id of the closest seed point
cids = []
for p in tmesh.cellCenters():
cid = seeds.closestPoint(p, returnPointId=True)
cids.append(cid)
tmesh.celldata["fragment"] = cids
pieces = []
for i in range(seeds.NPoints()):
tc = tmesh.clone().threshold(name="fragment", above=i-0.1, below=i+0.1)
mc = tc.tomesh(fill=False).color(i)
pieces.append(mc)
############### animate
plt = Plotter(size=(1200,800), axes=1)
plt.show(__doc__, pieces)
for i in range(20):
for pc in pieces:
cm = pc.centerOfMass()
pc.shift(cm/25)
plt.render()
plt.interactive().close() |
PS: One can use pymeshfix + tetgen to generalize, eg: """Segment a TetMesh with a custom scalar.
Press q to make it explode"""
from vedo import Mesh, TetMesh, Plotter, Text2D, dataurl
import tetgen
import pymeshfix
n = 20000
f1 = 0.005 # control the tetras resolution
f2 = 0.15 # control the nr of seeds
# repair and tetralize the closed surface
amesh = Mesh(dataurl+'bunny.obj')
meshfix = pymeshfix.MeshFix(amesh.points(), amesh.faces())
meshfix.repair() # will make it manifold
repaired = Mesh(meshfix.mesh)
tet = tetgen.TetGen(repaired.points(), repaired.faces())
tet.tetrahedralize(order=1, mindihedral=20, minratio=1.5)
tmesh = TetMesh(tet.grid)
surf = tmesh.tomesh(fill=False)
txt = Text2D(__doc__, font="Brachium")
# pick points on the surface and use subsample to make them uniform
seeds = surf.clone().subsample(f2).ps(10).c('black')
# assign to each tetrahedron the id of the closest seed point
cids = []
for p in tmesh.cellCenters():
cid = seeds.closestPoint(p, returnPointId=True)
cids.append(cid)
tmesh.celldata["fragment"] = cids
#tmesh.celldata.select("fragment")# bug, has no effect, needs name=...
pieces = []
for i in range(seeds.NPoints()):
tc = tmesh.clone().threshold(name="fragment", above=i-0.1, below=i+0.1)
mc = tc.tomesh(fill=False).color(i)
pieces.append(mc)
############### animate
plt = Plotter(size=(1200,800), axes=1)
plt.show(txt, pieces)
for i in range(20):
for pc in pieces:
cm = pc.centerOfMass()
pc.shift(cm/25)
txt.text(f"{__doc__}\n\nNr. of pieces = {seeds.N()}")
plt.render()
plt.interactive().close() |
This is cool. Yes except of Now I need to figure out how to get smoother fragmentations, I will play a bit with the parameters to see if I can optimize the cutting part. Thanks a lot 👍 |
Hi @marcomusy, is it possible to load |
It should - if it doesnt load in vedo you may use |
The
|
@marcomusy from the previous example (with the split) I am trying to subdivide and smooth the extracted pieces:
but it gives me the following error:
apparently my |
Also to speed up the split into pieces instead of creating seeds and iterating over the face centers in order to label them (which as I notice in a mesh with dense tetrahedra is quite time consuming, thus quite slow), do you think it would make sense to do the split as a combination of the This means though that I would need a really random shaped 3d model to apply the boolean operations. I was thinking something like a 3d dendrogram (or neural tree, I do not really know how these are called) which would grow random branches from the center of mass of the 3d mesh until its surface and then we could use this for the boolean operations between the two models? Or it could be something simpler. |
|
The rabbit example working fine.
Why not? In principle at the end I want to keep the individual mesh version of the pieces. However, because the fragmented sides are kind of too rough I would like to smooth them. One way to do that is to create more tetrahedras or the second that I thought is to just smooth the surface of the meshes that correspond to the meshes. I've tried the first one but once you start increasing the amount of tetrahedras the post-processing becomes to much time consuming. Thus, I thought the solution of smoothing and to apply some smoothness in order to keep the amount of tetrahedras in logical numbers and then fix the roughness by smoothing. At least I wanted to check how it looks like. However, I am getting the error I've mentioned above. Test the code bellow:
The
Ok |
Yes, the problem is much more serious .. infact tetgen doesn't seem to work well: you may notice that the wireframe part is very irregular and non-manifold, that is why the subdivision and smoothing fails. The from vedo import *
amesh = Mesh(dataurl+'bunny.obj')
amesh.fillHoles().cap().smooth()
tmesh = amesh.tetralize(side=0.015, debug=False)
#tmesh.write('mytetmesh.vtk') # save to disk!
surf = tmesh.tomesh(fill=False)
surf.subdivide(method=1).smooth()
show(surf, axes=1).close() sorry in this moment it is not clear to me why that happens. |
Hhhmm I see, I've also used another tetrahedrealizer but the problem remains (though I forced the output to be manifold). Check on the attached file. You can load it as:
|
Hi @marcomusy,
I have a mesh which I would like to split in a random number of sub-meshes as you do in this example but without discarding any parts. If you see in the image below at the current state some of the parts after the split are removed and only 40 pieces are kept.
Is there a flag for the
maxdepth=
parameter to consider the complete initial mesh? Ideally I would like the complete mesh to be split in 40 (or whichever number is given each time) pieces.Thereafter, I would like to create a kind of animation similar to this one where I move each part aside in the space (or as an inventory list on a side pane) and then put them again together giving this assemply/disassemply outlook. Is there any example which I could follow? If not how easy would that be to do it with vedo?
Thanks.
The text was updated successfully, but these errors were encountered: