Notifications
Clear all

[Closed] maxscript challenge 'Screw"

that and it doesn’t help that genome’s objects have to be dense as heck to make that screw work correct.
It’s cool…but not practical.

heres my contribution, should get you started, not tested on odd number of segments


     fn mxssetedgevisflags m face flags =
     (	
     	setEdgeVis m  face 1 flags[1];
     	setEdgeVis m  face 2 flags[2];
     	setEdgeVis m  face 3 flags[3];
     )
     
     fn create_thread_mesh segs num_turns maj_radius min_radius pitch poffset =
     (
     	rd = 360.0 / segs;	-- angular delta
     	pd = pitch / segs;	-- pitch delta
     	mmd = (maj_radius - min_radius) / segs; -- major to minor delta
     	
     -- compute numverts & faces we need	
     	
     	num_verts = segs * num_turns * 2 + ((segs - 1) * 2) + 1;
     	num_faces = segs * num_turns * 4 + 3 * segs - 4;
     	
     -- empty mesh	
     	
     	msh = mesh numverts:num_verts  numfaces:num_faces
     
     	segs_over_two = segs/2;
     	vert_count = (num_verts - 1)/ 2.0;	-- vert counts
     	final_loop = num_turns * segs;	-- start of final loop
     	r = rd;
     	p = 0.0;
     	rp = maj_radius;
     	verti = 1;	-- vert index
     	
     -- create outer helix verts   
     	
     	for i = 1 to vert_count do
     	(	
 -- outer helix blends to the inner helix over the final loop
     		if i > final_loop then 
     			rp -= mmd;
     		
     		setVert msh verti  (rp * cos r) (rp * sin r) p;
     		verti += 1;
     		
 -- the helix is flat for the first turn and last half turn
 
     		if r >= 360 and i <= vert_count - segs_over_two then
     			p += pd;
     		r += rd;	
     	)
     	top = p;
     
     -- create inner helix verts
     	
     	r = rd;
     	p = 0.0;
     	rp = maj_radius;
     	for i = 1 to vert_count do
     	(	
 
 -- inner helix starts at major rad blending to the minor rad over the first turn
 
     		if i <= segs then
     			rp -= mmd;
     		
     		setVert msh verti  (rp * cos r) (rp * sin r) p;
     		verti += 1;
     		
 -- this is flat for the first and last half turns
 
     		if p < top and i >= segs_over_two then
     			p += pd;
     		r += rd;	
     	)
     	
     -- set the point	
     	
     	setVert msh verti  0 0 (top + poffset);
     	verti += 1;
     	
     -- create the faces	
     	
     	facei = 1 -- face index
     	
     -- first 2 fillet tris	
     	
     	setface msh facei [segs, 1, vert_count + 1];
     	mxssetedgevisflags msh facei #{1,3};
     	setFaceSmoothGroup msh facei 1;
     	facei += 1;
     	
     	setface msh facei [segs, vert_count + 1, segs + 1];
     	setFaceSmoothGroup msh facei 2;
     	facei += 1;
     	
     -- main thread	
     	
     	for i = 1 to vert_count - 1 do
     	(
     		ip1 = i + 1;
     		opi = vert_count + i;
     		opip1 = opi + 1;
     		spi = segs + i;
     
     		setface msh facei [i, ip1, opi];
     		mxssetedgevisflags msh facei #{1,3};
     		setFaceSmoothGroup msh facei 1;
     		facei += 1;
     		setface msh facei [opi, ip1, opip1];
     		mxssetedgevisflags msh facei #{3};
     		setFaceSmoothGroup msh facei 1;
     		facei += 1;
     		
     		if i < vert_count - segs then
     		(	
     			setface msh facei [opi, opip1,spi];
     			mxssetedgevisflags msh facei #{1,3};
     			setFaceSmoothGroup msh facei 2;
     			facei += 1;
     			setface msh facei [spi, opip1, spi + 1];
     			mxssetedgevisflags msh facei #{3};
     			setFaceSmoothGroup msh facei 2;
     			facei += 1;
     		)	
     	)	
     
     -- last fillet 2 tris
     
     	setface msh facei [num_verts - segs - 1, num_verts - segs, vert_count];
     	mxssetedgevisflags msh facei #{2,3};
     	setFaceSmoothGroup msh facei 2;
     	facei += 1;	
     	setface msh facei [vert_count, num_verts - segs, num_verts - 1];
     	mxssetedgevisflags msh facei #{2,3};
     	setFaceSmoothGroup msh facei 1;
     	facei += 1;	
     
     -- point cap	
     	
     	svert = num_verts - segs;
  	for i = 0 to segs - 1 do
  	(
  		b = svert + i;
  		c = b + 1
  		if i == segs - 1 then
  		(
  			b = num_verts - 1;
  			c = svert;
  		)		
  		setface msh facei [num_verts, b , c];	
  		setFaceSmoothGroup msh facei 1;
  		mxssetedgevisflags msh facei #{1};
  		facei += 1;	
  	)	  
     	
     	update msh;
     	msh;
     	
     )	
     
     create_thread_mesh 16 7 0.5 0.375 0.25 0.25

edit: small bug fixed, too many faces created on the top cap also added some more comments

Klunk!
Super impressive stuff.
I’ll have to check this out and mess around with it.
Nice work.

Finally got around to playing with the script more. Very cool. Now just adding an option to add spacing between each loop.

A simple way to do this right now is to just select the loop and chamfer it but its rather hackish to do that.

Better explain

Check this out. Got it working with points
If you adjust the fillet variable to be 0.0 then you’ll create a screw with no flat part


delete objects
columns = 24
numTurns = 8
fillet = 2.0 --positive only
radiusXOuter = 5.0
radiusYOuter = 5.0
radiusXInner = 4.0
radiusYInner = 4.0
columnAngle = 360.0 / columns
count = ceil (numTurns * columns)
height = 60--(units.decodevalue "30cm")

/* Main Outer */
for c = 0 to count do
(									
	calcX = radiusXOuter * cos(c * columnAngle)
	calcY = radiusYOuter * sin(c * columnAngle)
	theHeight = (height/count as float)*c
	
	cornerPos = [calcX,calcY,theHeight]
	point pos:cornerPos size:1 wirecolor:blue cross:true
	append fourCorners cornerPos
)

/* Inner */
rows = if fillet == 0.0 then 1 else 2
for f = 1 to rows do (
	for c = 0 to count do
	(									
		calcX = radiusXInner * cos(180+c * columnAngle)
		calcY = radiusYInner * sin(180+c * columnAngle)
		offset = if f == 1 then -(fillet/2.0) else (fillet/2.0)
		theHeight = (height/count as float)*c+offset
		
		cornerPos = [calcX,calcY,theHeight]
		point pos:cornerPos size:.5 wirecolor:red cross:true
		append fourCorners cornerPos
	)
)

max tool zoomextents all

combine this with klunks tool and we got ourselves something.


   /* denisT collection 2013 */
   
   plugin simpleObject Screw name:"Screw"
   classID:#(0x00001967, 0x1063899f)
   category:"Standard Plus" 
   version:1
   (
   	local screwobject, bodyobject
   	parameters params rollout:params
   	(
   		curve type:#maxobject
   		
   		radius1 type:#worldUnits default:4 ui:ui_radius1
   		radius2 type:#worldUnits default:6 ui:ui_radius2
   
   		height type:#worldUnits default:10 ui:ui_height
   
   		turns type:#float default:1 ui:ui_turns
   		step type:#worldUnits default:1 ui:ui_step
   		sides type:#integer default:16 ui:ui_sides
   		direction type:#integer default:1 animatable:off ui:ui_direction	
   
   		autosmooth type:#float default:45 ui:ui_autosmooth
   
   		mapCoords type:#boolean default:on ui:ui_mapCoords
   		realWorldMapSize type:#boolean default:off ui:ui_realWorldMapSize 
   		
   		manualUpdate type:#boolean default:off animatable:off ui:ui_manualUpdate
   	)
   	rollout params "Parameters" 
   	(
   		local updating = on
   			
   		group "Geometry: "
   		(
   			spinner ui_radius1 "Inner Radius: " type:#worldUnits range:[0,1e9,0] fieldwidth:50 align:#right offset:[2,0]
   			spinner ui_radius2 "Outer Radius: " type:#worldUnits range:[0,1e9,0] fieldwidth:50 align:#right offset:[2,-2]
   			spinner ui_height "Height: " type:#worldUnits range:[0,1e9,0] fieldwidth:50 align:#right offset:[2,6]
   			spinner ui_turns "Thread Turns: " type:#float range:[1,256,0] fieldwidth:50 scale:0.1 align:#right offset:[2,6]
   			spinner ui_step "Thread Width: " type:#worldUnits range:[0,1e9,0] fieldwidth:50 scale:0.1 align:#right offset:[2,-2]
   			spinner ui_sides "Sides: " type:#integer range:[3,256,0] fieldwidth:50 align:#right offset:[2,-2]
   			radiobuttons ui_direction labels:#("CW", "CCW") columns:1 align:#left offset:[79,2]	
   
   			spinner ui_autosmooth "Auto Smooth: " type:#float range:[0,180,45] fieldwidth:50 align:#right offset:[2,2]
   
   			checkbox ui_mapCoords "Generate Map Coords." align:#left offset:[-2,4]
   			checkbox ui_realWorldMapSize "Real-World Map Size" align:#left offset:[-2,0]
   		)
   		group "Profile: "
   		(
   			CurveControl ui_profile numCurves:1 width:144 height:100 align:#left offset:[-4,2] enabled:on \
   				x_range:[0,1] y_range:[-0.5,1] x_value:0 \
   				scrollValues:[0,-10] zoomValues:[128,60] \
   				uiFlags:#(#constrainY, #noFilterButtons) \
   				rcmFlags:#(#move_xy, #move_x, #move_y, #corner, #delete) 
   			
   			checkbox ui_manualUpdate "Manual Update" align:#left offset:[-2,0]
   			button ui_updateProfile "Update" width:71 align:#left offset:[-4,0] tooltip:"Update Profile" across:2
   			button ui_resetProfile "Reset" width:71 align:#right offset:[4,0] tooltip:"Reset Profile"
   		)
   		
   		fn setProfile action:#ui update: = if isproperty this #curve do 
   		(
   			if update == unsupplied do update = not manualUpdate
   			c = ui_profile.curves[1]
   			
   			if not iskindof curve bezier_float do curve = bezier_float()
   			t = curve
   				
   			n = 1f
   			
   			while t.keys.count < c.points.count do addnewkey t (n += 1)
   			while t.keys.count > c.points.count do deletekey t 1
   			for n=1 to c.points.count do 
   			(
   				p = c.points[n]
   				k = t.keys[n]
   				
   				k.time = p.value.x
   				k.value = p.value.y
   				k.inTangentType = #linear
   				k.outTangentType = #linear
   				k.x_locked = p.lock_x
   				k.y_locked = p.lock_y
   				k.selected = p.selected
   			)
   			if update do 
   			(
   				this.domesh()
   				redrawviews()
   			)
   		)
   		fn getProfile = if isproperty this #curve do 
   		(
   			c = ui_profile.curves[1]
   			t = curve
   			
   			c.numPoints = t.keys.count
   			for n=t.keys.count to 1 by -1 do 
   			(
   				p = c.points[n]
   				k = t.keys[n]
   
   				p.value = [k.time, k.value]
   				p.bezier = off
   				p.corner = on
   				p.lock_x = k.x_locked
   				p.lock_y = k.y_locked
   				p.selected = k.selected
   			)
   		)
   
   		on ui_profile deleted c val do if not loading and not updating do setProfile()
   		on ui_profile ptChanged c val do if not loading and not updating do setProfile()
   		on ui_profile tangentChanged c val type do if not loading and not updating do setProfile()
   		
   		fn resetProfile update:off = 
   		(
   			c = ui_profile.curves[1]
   			c.numpoints = 3
   			c.points[2].value = [0.5,1]
   			c.points[3].value = [1,0]
   			c.points[1].lock_x = c.points[3].lock_x = on
   			c.points.lock_y = off
   			
   			setProfile update:update
   		)
   		on ui_updateProfile pressed do undo "Update Screw Profile" on 
   		(
   			updating = on
   			setProfile update:on
   			updating = off
   		)
   		on ui_resetProfile pressed do undo "Reset Screw Profile" on 
   		(
   			updating = on
   			resetProfile update:on
   			updating = off
   		)
   		on params open do
   		(
   			updating = on
   			deleteAllChangeHandlers id:#screw_callback
   			c = ui_profile.curves[1]
   			if not iskindof curve bezier_float then resetProfile update:off else getProfile()
   
   			ccTarget = (refs.dependents ui_profile.curves[1])[1]
   			when topology ccTarget change id:#screw_callback do 
   			(
   				if ui_profile.curves[1].numpoints != numkeys curve do setProfile action:#curve
   			)
   			updating = off
   		)
   		on params close do 
   		(
   			deleteAllChangeHandlers id:#screw_callback
   		)
   	)
   	
   	fn domesh = 
   	(
   		if screwobject == undefined do screwobject = createinstance plane width:1 length:1
   		screwobject.widthsegs = if iskindof curve bezier_float then (numkeys curve)-1 else 1
   		screwobject.lengthsegs = sides*turns
   		screwobject.mapCoords = mapCoords
   		screwobject.realWorldMapSize = realWorldMapSize
   		mesh = screwobject.mesh
   
   		if bodyobject == undefined do bodyobject = createinstance plane width:1 length:1 widthsegs:1
   		bodyobject.lengthsegs = sides*(turns-1)
   		bodyobject.mapCoords = mapCoords
   		bodyobject.realWorldMapSize = realWorldMapSize
   		bodymesh = bodyobject.mesh
   		
   		points = curve.keys.count
   		h = (height - step)/sides/turns
      		ang = 360./sides
   		if direction > 1 do ang = -ang 
   		verts = mesh.verts as bitarray
   		v = 0
   		turn = 0
   		a = 0 
   		f = radius2 - radius1
   		while not verts.isempty do
   		(
   			for k=1 to points while not verts.isempty do
   			(
   				v += 1
   				verts[v] = off
   				p = getvert mesh v
   				p.x = curve.keys[k].time
     				p.z = curve.keys[k].value
   				pos = [(radius1 + p.z*f)*(cos a), (radius1 + p.z*f)*(sin a), p.x*step + turn]
   				setvert mesh v pos
   			)
   			a += ang
   			turn += h
   		)
   		
   		verts = bodymesh.verts as bitarray
   		for v in verts do
   		(
   			if mod v 2 > 0 then
   			(
   				n = (v+1)/2*points
   			)
   			else
   			( 
   				n = (v/2 + sides - 1)*points + 1
   			)
   			if n <= mesh.numverts do setvert bodymesh v (getvert mesh n)
   		)
   		n = mesh.numfaces
   		meshop.attach mesh bodymesh
   		for f=n+1 to mesh.numfaces do setfacematid mesh f 2
   
   		meshop.weldVertsByThreshold mesh #all 0.0001
   		
   		if direction < 2 do meshop.flipNormals mesh #all			
   		meshop.autoSmooth mesh #all autosmooth
   		update mesh
   		mesh
   	)
   	
   
   	on buildmesh do domesh()
   
   	tool create
   	(
   		on mousePoint click do case click of
   		(
   			1: 
   			(
   				nodeTM.translation = gridPoint
   				radius1 = radius2
   				height = 0.01
   				turns = 2
   				step = 0.001
   			)
   			4: #stop
   		)
   		on mouseMove click do case click of
   		(
   			2: radius1 = radius2 = amax (abs gridDist.x) (abs gridDist.y)
   			3: 
   			(
   				height = gridDist.z
   				step = height/turns*0.9
   			)
   			4: radius2 = amax (abs gridDist.x) (abs gridDist.y)
   		)
   	)
   	on update do domesh()
   )
   

use RC menu to edit curve (profile)…

must say this is a pretty badass one. Maybe one of my favorites.

I’m going to mess around and see what I can add to it.

what is biggest problem of any scripted simple object?

3 Replies
(@denist)
Joined: 11 months ago

Posts: 0

the biggest problem of every scripted simple object is the memory leaking. so for every object we always have to optimize the code to minimize mesh build. every time when not any parameter causes changing the object’s topology we have to use the old mesh and only change its verts positions.

(@miauu)
Joined: 11 months ago

Posts: 0

It have to be “installed” on every 3dsMax that will open the scene?

(@jokermartini)
Joined: 11 months ago

Posts: 0

That’s for sure. And it doesnt work on network nodes unless installed. I wonder if they work on command line rendering.

I’m not sure? What’s the problem?

Page 2 / 4