Notifications
Clear all

[Closed] Sample Simple Object Plug-in

following this discussion http://forums.cgsociety.org/showthread.php?f=98&t=1030079 i’ve made the plugin that might be helpful as a sample:


/* denisT script collection (2012)*/

plugin simpleObject BrickChimney
	name:"Chimney"
	classID:#(0x10001967,0xA0000001)
	category:"Scripted Primitives"
(
	local attach = meshop.attach
	parameters params rollout:params
	(
		height type:#worldunits default:5 ui:ui_height
		radius type:#worldunits default:5 ui:ui_radius
		shift type:#float default:0.5 ui:ui_shift
		
		brickLength type:#worldunits default:2.5 ui:ui_brickLength
		brickWidth type:#worldunits default:1.6 ui:ui_brickWidth
		brickHeight type:#worldunits default:1 ui:ui_brickHeight
		brickFillet type:#worldunits default:0.15 ui:ui_brickFillet
		brickFilletSegs type:#integer default:2 ui:ui_brickFilletSegs
		
		brickSmooth type:#integer default:1 ui:ui_brickSmooth
		brickMapCoords type:#integer default:1 ui:ui_brickMapCoords
		brickRealWorldMapSize type:#boolean default:off ui:ui_brickRealWorldMapSize
	)
	rollout params "Parameters"
	(
		group "Chimney:" 
		(
			spinner ui_height "Height: " type:#worldunits range:[0,1e9,0] fieldwidth:56
			spinner ui_radius "Radius: " type:#worldunits range:[0,1e9,0] fieldwidth:56
			spinner ui_shift "Shift: " type:#float range:[0,1,0] fieldwidth:56
		)
		group "Brick:" 
		(
			spinner ui_brickLength "Length: " type:#worldunits range:[0,1e9,0] fieldwidth:56
			spinner ui_brickWidth "Width: " type:#worldunits range:[0,1e9,0] fieldwidth:56
			spinner ui_brickHeight "Height: " type:#worldunits range:[0,1e9,0] fieldwidth:56
			spinner ui_brickFillet "Fillet: " type:#worldunits range:[0,1e9,0] fieldwidth:56
			spinner ui_brickFilletSegs "Fillet Segs: " type:#integer range:[0,5,0] fieldwidth:56
			
			checkbox ui_brickSmooth "Smooth" offset:[0,4]
			checkbox ui_brickMapCoords "Apply UV Mapping" 
			checkbox ui_brickRealWorldMapSize "Real-World Map Size" 
		)
	)
	fn numberRows = 
	(
		(if (height*brickHeight) == 0 then 0 else (height/brickHeight) as integer) + 1
	)
	fn numberBricksInRow = 
	(
		--brickLength = 2*radius*sin(pi/n)
		if (radius*brickLength) == 0 then 0 else 
		(
			n = 180./(asin(brickLength/(2*radius)))
			if (bit.isNAN n) then 0 else (n as integer) 
		)
	)
	fn transformMesh mesh verts offset: angle: = 
	(
		for v in verts do
		(
			tm = transmatrix ((getVert mesh v) + offset)
			tm = rotateZ tm angle
			setVert mesh v tm.pos
		)
		mesh
	)
	on buildMesh do
	(
		setMesh mesh numverts:0 numfaces:0
		if (n = numberBricksInRow()) > 0 do
		(	
			local b = if brickFilletSegs > 0 then
			(
				createinstance ChamferBox Length_Segments:1 Width_Segments:1 Height_Segments:1 Fillet_Segments:brickFilletSegs \
					length:brickLength width:brickWidth height:brickHeight Fillet:brickFillet \
					smooth:brickSmooth mapcoords:brickMapCoords realWorldMapSize:brickRealWorldMapSize
			)
			else
			(
				createinstance Box lengthsegs:1 widthsegs:1 heightsegs:1 \
					length:brickLength width:brickWidth height:brickHeight \
					mapcoords:(brickMapCoords > 0) realWorldMapSize:brickRealWorldMapSize
			)
			
			local verts = #{1..b.mesh.numverts}
			local angle = 360.0/n
			local offset = [radius-brickWidth/2,0,0]
			for z=0 to numberRows()-1 do
			(
				offset.z = brickHeight*z
				s = shift*angle*z
				for k=0 to n-1 do
				(
					brick = copy b.mesh
					transformMesh brick verts offset:offset angle:(k*angle + s)
					attach mesh brick
				)
			)
			free b
		)
	)

	tool create
	(
		on mousePoint click do case click of
		(
			1: 
			(
				nodeTM.translation = gridPoint
				height = 0
				radius = 0
			)
			3: #stop
		)
		on mouseMove click do case click of
		(
			2: 
			(
				radius = sqrt (gridDist.x^2 + gridDist.y^2)
			)
			3: height = gridDist.z
		)
	)
)

as i have time i will add new features. any questions, suggestions are welcome.

32 Replies

that features could be added:
#1 Tape/Bend the bricks
#2 Random Size a little
#3 Random Material ID
#4 Support Square/Rectangular Chimney
#5

any enthusiast is free to extend the plug-in…

Cool! Although its extremely slow for me in Max 2010 64bit. Takes seconds to update anything/create it.

1 Reply
(@denist)
Joined: 11 months ago

Posts: 0

i know. i’m thinking about a way of optimization. vertex transformation kills the performance. maybe attaching too.

Maybe do a sort of Proxy while editing/creating that is lower poly, then on end, create the higher poly mesh?

1 Reply
(@denist)
Joined: 11 months ago

Posts: 0

yes. it’s the right way. but i’m not looking for easy ways

I wasn’t either on my Edge Twist issue I had in my other thread, but i spent too many hours trying to get it to work, and now I just have to user do it, and then is all good. Having more control is always good too.

attach mesh is the bottleneck…

Maybe do it like this method I saw from soulburn,


local snapObjs = #()
	for obj in selection where (superclassof obj == GeometryClass) do 
	(
		append snapObjs (snapshot obj)
	)
	
	local count = 1
	local currentIteration = 0
	local numOfItems = snapObjs.count
	select snapObjs
	
	--Thank you to SoulBurn Scripts for this algorithm/method
	if snapObjs.count > 1 do
	(
		while (selection.count > 1) do 
		(
			for i = selection.count to 2 by -2 do 
			(
				currentIteration += 1
				m = ((currentIteration as float)/(numOfItems as float))*100
				attachTo = snapObjs[i]
				convertToPoly attachTo
				attachTo.EditablePoly.attach snapObjs[i-1] attachTo
				deleteItem snapObjs (i-1)
			)
		)
		
		convertToMesh selection[1]

i updated the plug-in… now it’s ~10 times faster:


/* denisT script collection (2012)*/

plugin simpleObject BrickChimney
	name:"Chimney"
	classID:#(0x10001967,0xA0000001)
	category:"Scripted Primitives"
(
	local attach = meshop.attach

	local numBricks = 0, numBrickVerts = 0, numBrickFaces = 0
	parameters params rollout:params
	(
		--useClone type:#boolean default:on ui:ui_useClone

		height type:#worldunits default:5 ui:ui_height
		radius type:#worldunits default:5 ui:ui_radius
		shift type:#float default:0.5 ui:ui_shift
		
		brickLength type:#worldunits default:2.5 ui:ui_brickLength
		brickWidth type:#worldunits default:1.6 ui:ui_brickWidth
		brickHeight type:#worldunits default:1 ui:ui_brickHeight
		brickFillet type:#worldunits default:0.15 ui:ui_brickFillet
		brickFilletSegs type:#integer default:2 ui:ui_brickFilletSegs
		
		brickSmooth type:#integer default:1 ui:ui_brickSmooth
		brickMapCoords type:#integer default:1 ui:ui_brickMapCoords
		brickRealWorldMapSize type:#boolean default:off ui:ui_brickRealWorldMapSize
	)
	rollout params "Parameters"
	(
		--checkbox ui_useClone "Use Cluster Method" offset:[0,0]

		group "Chimney:" 
		(
			spinner ui_height "Height: " type:#worldunits range:[0,1e9,0] fieldwidth:56
			spinner ui_radius "Radius: " type:#worldunits range:[0,1e9,0] fieldwidth:56
			spinner ui_shift "Shift: " type:#float range:[0,1,0] fieldwidth:56
		)
		group "Brick:" 
		(
			spinner ui_brickLength "Length: " type:#worldunits range:[0,1e9,0] fieldwidth:56
			spinner ui_brickWidth "Width: " type:#worldunits range:[0,1e9,0] fieldwidth:56
			spinner ui_brickHeight "Height: " type:#worldunits range:[0,1e9,0] fieldwidth:56
			spinner ui_brickFillet "Fillet: " type:#worldunits range:[0,1e9,0] fieldwidth:56
			spinner ui_brickFilletSegs "Fillet Segs: " type:#integer range:[0,5,0] fieldwidth:56
			
			checkbox ui_brickSmooth "Smooth" offset:[0,4]
			checkbox ui_brickMapCoords "Apply UV Mapping" 
			checkbox ui_brickRealWorldMapSize "Real-World Map Size" 
		)
	)
	fn numberRows = 
	(
		(if (height*brickHeight) == 0 then 0 else (height/brickHeight) as integer) + 1
	)
	fn numberBricksInRow = 
	(
		--brickLength = 2*radius*sin(pi/n)
		if (radius*brickLength) == 0 then 0 else 
		(
			n = 180./(asin(brickLength/(2*radius)))
			if (bit.isNAN n) then 0 else (n as integer) 
		)
	)
	fn transformMesh mesh verts offset: angle: = 
	(
		for v=1 to verts.count do
		(
			tm = transmatrix (verts[v] + offset)
			tm = rotateZ tm angle
			setvert mesh v tm.pos
		)
		mesh
	)
	on buildMesh do
	(
		t1 = timestamp()
		setMesh mesh numverts:0 numfaces:0
		numBricks = 0
		if (n = numberBricksInRow()) > 0 do
		(	
			local b = if brickFilletSegs > 0 then
			(
				createinstance ChamferBox Length_Segments:1 Width_Segments:1 Height_Segments:1 Fillet_Segments:brickFilletSegs \
					length:brickLength width:brickWidth height:brickHeight Fillet:brickFillet \
					smooth:brickSmooth mapcoords:brickMapCoords realWorldMapSize:brickRealWorldMapSize
			)
			else
			(
				createinstance Box lengthsegs:1 widthsegs:1 heightsegs:1 \
					length:brickLength width:brickWidth height:brickHeight \
					mapcoords:(brickMapCoords > 0) realWorldMapSize:brickRealWorldMapSize
			)
			
			brick = b.mesh 
			
			numBrickVerts = brick.numverts
			numBrickFaces = brick.numfaces
			
			local verts = #{1..numBrickVerts}
			local vert_array = for v in verts collect (getvert brick v)
			
			local angle = 360.0/n
			local offset = [radius-brickWidth/2,0,0]
			
			local meshes = #()
			for z=0 to numberRows()-1 do
			(
				offset.z = brickHeight*z
				s = shift*angle*z
				for k=0 to n-1 do
				(
					brick = transformMesh b.mesh vert_array offset:offset angle:(k*angle + s)
					append meshes brick
				)
			)
			n = numBricks = meshes.count
			while (num = n/2) > 0 do for k=1 to num do 
			(
				attach meshes[k] meshes[n]
				n -= 1
			)
			setmesh mesh meshes[1]
			free b
			free meshes
			--format "time:% bricks:%
" (timestamp()-t1) numBricks
		)
	)

	tool create
	(
		on mousePoint click do case click of
		(
			1: 
			(
				nodeTM.translation = gridPoint
				height = 0
				radius = 0
			)
			3: #stop
		)
		on mouseMove click do case click of
		(
			2: 
			(
				radius = sqrt (gridDist.x^2 + gridDist.y^2)
			)
			3: height = gridDist.z
		)
	)
)

Still is a bit laggy for me, but definitely faster.

Can this access multiple cores then?

Page 1 / 3