Notifications
Clear all

[Closed] a christmas script present

something for the holiday season someone might find useful

will generate a mesh along a spline, though you can use the built in mesh and reduce and scale that to produce the same result (which i have done) I’m not overly keen on the way max maintains the cross section. Anyway It’s mxs prototyping for a version of the max line object for generating tree model branches.


 fn lerp  a b s = (a as float + s * (b - a))	
   	
   -- create transform from a spline knot, we use an arbitary up axis if pxaxis is unsupplied	
   
   fn GetKnotTM shpe splne knt pxaxis: =
   (
   	p = getKnotPoint shpe splne knt;
   	zaxis = normalize ((p - getInVec shpe splne knt) + (getOutVec shpe splne knt - p));
   	if pxaxis == unsupplied then
   	(	
   		xaxis = normalize (cross [0,0,1] zaxis);
   		yaxis = normalize (cross xaxis zaxis);
   	)	
   	else
   	(
   		yaxis = normalize (cross pxaxis zaxis);
   		xaxis = normalize (cross zaxis yaxis);
   	)	
   	matrix3 xaxis yaxis zaxis p;
   )
   
   fn CollectSplineTransforms shpe splne nknots = 
   (
   	tms = #()
   	tms.count = nknots;
   	
   -- initialize the list so we get a more uniform transform orientation 	
   	
   	tms[1] = GetKnotTM shpe splne 1;	
   
   -- use the previous xaxis to align all the subsequent transforms	
   	
   	for i = 2 to numKnots shpe splne do tms[i] = GetKnotTM shpe splne i pxaxis:tms[i-1][1];	
   	tms;
   )	
   
   fn CollectVertCounts start_sides end_sides nknots &nverts &nfaces =
   (
   	vc = #()
   	vc.count = nknots;	
   	nverts = 0;
   	nfaces = 0;
   	for i = 1 to nknots do
   	(
   		vc[i] = (lerp start_sides end_sides ((i - 1) as float /(nknots - 1) as float)) as integer;
   		nverts += vc[i];
   		if i != 1 then nfaces += (vc[i] + vc[i-1]);
   	)
   	vc;
   )	
   
   -- builds the mesh
   
   fn BuildSplineMesh shpe splne start_radius end_radius start_sides end_sides =
   (
   	if start_sides < end_sides then swap start_sides end_sides;
   		
   	nknots = numKnots shpe splne;	
   	nverts = 0;
   	nfaces = 0;
   	vcs = CollectVertCounts start_sides end_sides nknots &nverts &nfaces;
   	tms = CollectSplineTransforms shpe splne nknots;
   	vcoords = getSegLengths shpe splne cum:true byVertex:true;
   
    -- create the base mesh	
   	
   	msh = mesh numverts:nverts numfaces:nfaces;
   	
   -- create the geo verts	
   	
   	vi = 1;
   	for k = 1 to nknots do
   	(
   		radius = lerp start_radius end_radius ((k - 1) as float/(nknots - 1) as float);
   		nsides = vcs[k];
   		for i = 1 to nsides do 	
   		(
   			u = 360 * (i - 1) as float/nsides as float;
   			cu = radius * cos u;
   			su = radius * sin u;
   			setvert msh vi ([cu, su, 0] * tms[k]);
   			vi += 1;
   		)	
   	)
   	
   -- create the geo faces
   
   	fi = 1;	
   	max_offset = 0
   	min_offset = vcs[1];
   	for k = 1 to nknots - 1 do
   	(
   		lastj = 0;
   		max_sides = vcs[k];
   		min_sides = vcs[k + 1]; 
   		mm_ratio = min_sides as float/max_sides as float;
  		jwrap = (max_offset + max_sides + min_sides);
   		
   		for i = 1 to max_sides do
   		(	
   -- handle the larger vert ring increment		
   		
   			i1 = i + max_offset;
   			i2 = i1 + 1;
   			if mod i max_sides == 0 then i2 -= max_sides;
   			
   -- handle the smaller vert ring increment	
   		
   			j1 = min_offset + (ceil (i * mm_ratio) as integer);
   			j2 = j1 + 1;
   			if mod j1 jwrap  == 0 then j2 -= min_sides;
   		
   -- create the faces		
   		
   			setEdgeVis msh fi 1 true;
   			if j1 != lastj and min_sides > 1 then -- do we need to create a quad
   			(	
   				setEdgeVis msh fi 2 true;
   				setface msh fi [i2,i1,j1]
   				fi += 1;
   				setface msh fi [i2,j1,j2]
   				setEdgeVis msh fi 2 true;
   				lastj = j1;
   			)
   			else
   			(
   				setEdgeVis msh fi 2 true;
   				setface msh fi [i2,i1,j2];
   			)	
   			fi += 1;
   		)	
   		max_offset += max_sides;
   		min_offset += min_sides;
   	)
   
   -- allocate mapping	
   	
   	ntverts = nverts + nknots;
   	meshop.setMapSupport msh 1 true;
   	meshop.setNumMapVerts msh 1 ntverts;
   	meshop.setNumMapFaces msh 1 nfaces; 	
   	
   -- mapping verts
   	
   	vi = 1;
   	for k = 1 to nknots do
   	(
   		nsides = vcs[k];
   		vc = vcoords[k];
   		for i = 1 to nsides + 1 do 
   		(	
   			meshop.setmapvert msh 1 vi [(i - 1) as float/nsides as float, vc, 0];
   			vi += 1;
   		)	
   	)	
   
   -- create the mapping faces
   
   	fi = 1;	
   	max_offset = 0
   	min_offset = vcs[1] + 1;
   	for k = 1 to nknots - 1 do
   	(
   		lastj = 0;
   		max_sides = vcs[k];
   		min_sides = vcs[k + 1]; 
   		mm_ratio = min_sides as float/max_sides as float;
   		
   		for i = 1 to max_sides do
   		(	
   -- handle the larger vert ring increment, we don't have to worry about wrap around here :)	
   		
   			i1 = i + max_offset;
   			i2 = i1 + 1;
   
   -- handle the smaller vert ring increment again no wrap around	
   		
   			j1 = min_offset + (ceil (i * mm_ratio) as integer);
   			j2 = j1 + 1;
   		
   -- create the faces		
   		
   			if j1 != lastj and min_sides > 1 then -- do we need to create a quad
   			(	
   				meshop.setMapFace msh 1 fi [i2,i1,j1]
   				fi += 1;
   				meshop.setMapFace msh 1 fi [i2,j1,j2]
   				lastj = j1;
   			)
   			else
   				meshop.setMapFace msh 1 fi [i2,i1,j2];
   			fi += 1;
   		)	
   		max_offset += max_sides + 1;
   		min_offset += min_sides + 1;
   	)	
   	update msh;
   	msh;
   )	  
   
   BuildSplineMesh $ 1 5.0 1.0 11 3
   

had to change the lerp function as it produced errors

also calculating the number of faces can be reduced to

nfaces = 2 * nverts - start_sides - end_sides;

the algorithm could also be used to create bridging faces between any unequal vert “sets”. You would just need to collect the vert indices in correct sequential order.