Notifications
Clear all

[Closed] Fibermesh to spline: Help me improve it!

does every fiber in the object has the same number of sides and segments?

Haven’t had time to check your script denis, i’m still at work. But I see you are providing the numbers to the functions, so that the script doesn’t have to “find” it. It is of course a lot faster this way! You are probably doing some other things differently, I’ll have a closer look later

I know for a fact that the segment, vert and side number will be the same for each element in the mesh.
However, in Zbrush you can change this number! You can create a fibermesh with 5 segments, instead of 4, or 10 sides instead of 1.
So maxscript should still figure out what those numbers are to work on any possible fibermesh.
That’s why in my script I select edge 1, and click “loop” in order to get the number of sides. Since I also have the amount of verts I can use those numbers to get the amount of segments.

VertNumber / Sides = Segments

I only do this with the first element, since I know all the other elements have the same properties as the first one.

 AJ1

Hey Norman – cool script!

After Wayne posted his (which is more a macrorecord of manual steps) I thought I’d have a go at mine & here’s where I got.

(
	--Define Stuff
	AllEdges = #{}
	AllOpenEdges = #{}

	--Do Stuff
	if selection.count == 1 then
	(
		FibreMesh = selection[1]
		SplineName = "Spline_"+FibreMesh.name
		if classof FibreMesh == Editable_Poly then
			(	
			--Selects the interior edges of each fibre. There absolutely has to be a more elegant way to do this. It is beyond me however!
			AllOpenEdges = polyop.GetOpenEdges FibreMesh 
			InteriorEdges=-AllOpenEdges
			polyop.setEdgeSelection FibreMesh InteriorEdges
			FibreMesh.SelectEdgeRing()
			--Divide the polys to create spline. The much better approach would be to have the splines created from the centre coordinates of each edge but again, this is beyond my skills :)
			FibreMesh.ConnectEdges()
			EdgesforSpline = (polyop.getEdgeSelection FibreMesh) as array
			polyop.CreateShape FibreMesh EdgesforSpline name:SplineName
			--Delete the original geometry. Remove this line if you'd still like it.
			delete FibreMesh
			messagebox "Done!" title:"Tada!"
			)
		Else messagebox "Please convert to Editable Poly" title:"Sorry!"
	)
	Else messagebox "Please select (one) object" title:"Oh no!"
)

It won’t work on multi sided strands (I didn’t even realise you could export multi sided hairs!), but it should work on multi segmented strips.

1 Reply
(@norman3d)
Joined: 11 months ago

Posts: 0

hehe cool! What you describe in the comments is exactly what I’m doing with the script. Taking the coordinates of the vertices of every segments (1, 2 or n). Then sum them and divide them by the number of sides to get the averaged out coordinate. In other words, the center. How fast is the script? I assume it isn’t very fast since you are selecting rings and connecting edges, which might be a problem with pretty high-res meshes.

Edit: Make sure to check my comments in my script. I made sure to explain everything I’m doing step by step.

 AJ1

I’m just going through it now- you’ve done exactly what I wanted to do very glad you’ve detailed your process, it’s a big help!

I’ve tested mine on some fairly complex meshes but I’m guessing the performance will take a hit if things get crazy

i do the same things to get number of sides and segments… but can some fibers of the same mesh have different number of segments? number of sides are probably always the same for all fibers.

2 Replies
(@norman3d)
Joined: 11 months ago

Posts: 0

Number of sides and and segments are always the same for each fiber in the mesh. I guess I could have gotten rid of some calculations in my first attempt!

By the way, the last version you posted is not properly working on the “strip” version, look:

(@denist)
Joined: 11 months ago

Posts: 0

it was a bug, i’ve fixed it. thanks!


 fn elementToCurve node:selection[1] uniform:off = if iskindof node Editable_Poly do
 (
 	fn getNumberSides node: = 
 	(
 		node.selectededges = #{1}
 		node.SelectEdgeLoop()
 		(polyop.getvertsusingedge node node.selectededges).numberset
 	)
 	fn collectElements node: =
 	(
 		local getElement = polyop.getElementsUsingFace
 		local getVerts = polyop.getVertsUsingFace
 		
 		local elements = #{}, done = #{}, count = 0
 		
 		for f in (node.faces as bitarray) where not done[f] do
 		(
 			ff = getElement node f
 			vv = getverts node ff
 			append elements (count += vv.numberset)
 			join done ff
 		)
 		elements
 	)
 	fn makeSpline data name: pos:[0,0,0] = 
 	(
 		sp = splineShape name:name pos:pos wirecolor:orange
 		
 		for d in data do
 		(
 			k = addnewSpline sp
 			for v in d do addKnot sp k #smooth #line v
 		)
 		updateShape sp
 		sp
 	)
 
 	sides = getNumberSides node:node
 	
 	if uniform then
 	(
 		segments = (polyop.getVertsUsingFace node (polyop.getElementsUsingFace node 1)).numberset/sides
 
 		elements = #{}
 		step = segments*sides 
 		for k=step to node.numverts by step do append elements k
 	)
 	else elements = collectElements node:node
 	
 	local mesh = snapshotasmesh node
 	
 	local verts = #(), data = #()
 	local i = 0, pos = [0,0,0] 
 	for v=1 to mesh.numverts do
 	(
 		pos += getVert mesh v
 		if (mod (i += 1) sides) == 0 do
 		(
 			append verts (pos/sides)
 			pos = [0,0,0]
 		)
 		if elements[v] do 
 		(
 			append data verts
 			verts = #()
 		)
 	)
 	delete mesh
 
 	makeSpline data name:(node.name + "_Shape") pos:node.transform.pos
 )
 /*
 (
 	gc()
 	node = $Fibers_cylinder
 	t1 = timeStamp()
 	elementToCurve node:node uniform:on
 	format "time: %	uniform: %	mesh: %
" (timeStamp() - t1) on node.name
 
 	gc()
 	t1 = timeStamp()
 	elementToCurve node:$Fibers_cylinder
 	format "time: %	uniform: %	mesh: %
" (timeStamp() - t1) off node.name
 
 	gc()
 	node = $Fibers_strip
 	t1 = timeStamp()
 	elementToCurve node:node uniform:on
 	format "time: %	uniform: %	mesh: %
" (timeStamp() - t1) on node.name
 
 	gc()
 	t1 = timeStamp()
 	elementToCurve node:node
 	format "time: %	uniform: %	mesh: %
" (timeStamp() - t1) off node.name
 )
 */
 

time: 77 uniform: true mesh: Fibers_cylinder
time: 249 uniform: false mesh: Fibers_cylinder
time: 311 uniform: true mesh: Fibers_strip
time: 1569 uniform: false mesh: Fibers_strip

uniform means the same number of segments for every fiber.
so for Fibers_cylinder the algorithm takes 0.077 sec, for Fibers_strip it takes 0.311
if number of segments can vary (not uniform) I do the element searching, which takes a time.

the editablePoly interface is very slow. if you can do the same operation using polyop interface do it.

 3ak

Denis, assuming that fibers are all the same across one mesh, get any element and:
basecount = ((number_of_verts_in_element – number_of_faces_in_element)+1)
baselength = (number_of_verts_in_element / basecount)

So you actually don’t need any loops for this task.

offtopic: Don’t you know why detaching element from mesh completely changes its index arrays (just detach some fibers from sample file and you’ll see wrong result)?

Page 2 / 2