Notifications
Clear all

[Closed] Sample Simple Object Plug-in

Could I use your mesh attach method for a normal object array?

Like snapshot meshes and attach like that instead of using EPoly? Would it be alot faster?

1 Reply
(@denist)
Joined: 11 months ago

Posts: 0

of course it might be done this way, but i think the converting big mesh to poly will whittle any advantage of using this method.

I ended up taking Lo’s attach function from one of the challenges and having it use meshop instead of polyop.

Also with turning off undo and whatnot, now from before taking almost 30 seconds to attach many HP models, now it takes like 2-3 seconds to attach 1 million polys worth in a couple hundred meshes.

Edit: Although before I forgot to turn off undo with my old method, so it was killing max and causing memory leaks or something. Now max runs 100x better and attach is much better.

1 Reply
(@denist)
Joined: 11 months ago

Posts: 0

30 vs 3 seconds… could you show the final code? how long does it take to convert 1 million face mesh to poly?

Well the 30seconds was prob from leaking, I had to restart max.
But in any case, it still is like 2-4x faster than what I had before.

To attach 841,921K Polys, 99 Objects, being ones with modifiers, turbosmoothed, ect.

Processing took 1.729 seconds


--Thanks to Lo of CGTalk for this one
fn customAttach source nodes = 
(
	with undo off 
	(
		insertitem source nodes 1
		local count = nodes.count
		local att = meshop.attach			
		local vertArr = for o in nodes collect o.numVerts
		local sortedVertArr = deepcopy vertArr
		for i = 1 to nodes.count-1 do if not keyboard.escpressed do
		(
		--	pb.value = 100 - nodes.count*100./count								
			sort sortedVertArr
			local a = findItem vertArr sortedVertArr[1]
			vertArr[a]=-1
			local b = findItem vertArr sortedVertArr[2]
			local nA = nodes[a]
			att nA nodes[b]
			sortedVertArr[1]=vertArr[a]=nA.numVerts
			deleteItem vertArr b
			deleteItem sortedVertArr 2
			deleteItem nodes b
			--verts += nA.numverts								
		)
	)
	nodes[1]
)

the mode for fast preview or fast manual creation added:


/* 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
		manualUpdate type:#boolean default:on ui:ui_manualUpdate

		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

		sector type:#boolean default:off ui:ui_sector
		on sector set val do this.params.ui_sectorFrom.enabled = this.params.ui_sectorTo.enabled = val 

		sectorFrom type:#float default:0 ui:ui_sectorFrom
		sectorTo type:#float default:360 ui:ui_sectorTo
		
		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
		
		brickTaper type:#boolean default:on ui:ui_brickTaper
		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 Clone Method" offset:[0,0]
		checkbox ui_manualUpdate "Preview Mode" offset:[0,0]

		group "Chimney:" 
		(
			spinner ui_height "Height: " type:#worldunits range:[0,1e9,0] scale:0.1 fieldwidth:56
			spinner ui_radius "Radius: " type:#worldunits range:[0,1e9,0] scale:0.1 fieldwidth:56 offset:[0,-2] 
			spinner ui_shift "Shift: " type:#float range:[0,1,0] scale:0.01 fieldwidth:56 offset:[0,-2] 
			checkbox ui_sector "Sector" offset:[71,2]
			spinner ui_sectorFrom "Sector From: " type:#integer range:[0,360,0] fieldwidth:56 enabled:sector
			spinner ui_sectorTo "Sector To: " type:#integer range:[0,360,0] fieldwidth:56 offset:[0,-2] enabled:sector 
		)
		group "Brick:" 
		(
			spinner ui_brickLength "Length: " type:#worldunits range:[0,1e9,0] scale:0.01 fieldwidth:56
			spinner ui_brickWidth "Width: " type:#worldunits range:[0,1e9,0] scale:0.01 fieldwidth:56 offset:[0,-2] 
			spinner ui_brickHeight "Height: " type:#worldunits range:[0,1e9,0] scale:0.01 fieldwidth:56 offset:[0,-2] 
			spinner ui_brickFillet "Fillet: " type:#worldunits range:[0,1e9,0] scale:0.01 fieldwidth:56 offset:[0,2] 
			spinner ui_brickFilletSegs "Fillet Segs: " type:#integer range:[0,5,0] fieldwidth:56 offset:[0,-2] 
			
			checkbox ui_brickTaper "Taper" offset:[71,2]
			checkbox ui_brickSmooth "Smooth" offset:[71,-2]
			checkbox ui_brickMapCoords "Apply Mapping Coords." offset:[0,2] 
			checkbox ui_brickRealWorldMapSize "Real-World Map Size" offset:[0,-2]  
		)
	)
	fn round d pre:1 = (ceil(d/pre)*pre)
	fn roundFloat d pre:0.001 =
	(
		d = (d as float)/pre
		v = if (d - (v1 = floor d)) > ((v2 = ceil d) - d) then v2 else v1 
		v*pre
	)

	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
	)
	fn transformVerts mesh verts offset: angle: = 
	(
		list = for v=1 to verts.count collect
		(
			tm = transmatrix (verts[v] + offset)
			(rotateZ tm angle).pos
		)
		setmesh mesh vertices:list
		mesh
	)
	fn attachMeshes meshes = 
	(
		n = meshes.count
		while (num = n/2) > 0 do for k=1 to num do 
		(
			attach meshes[k] meshes[n]
			n -= 1
		)
		meshes[1]
	)
	fn getShift angle index:0 = 
	(
		local s = shift*angle*index
		s = mod s angle
		if s > angle/2 do s = s - angle
		s
	)
	on buildMesh do
	(
		t1 = timestamp()
		setMesh mesh numverts:0 numfaces:0
		numBricks = 0
		
		local n = numberBricksInRow()
		local h = numberRows()
		local angle = 360.0/n
		
		if n >= 3 do
		if manualUpdate then
		(
			local b = 
			(
				local start = 0, end = 0, k = n, slide = 0
				if sector do
				(
					slide = 1
					start = 360 - (round sectorFrom pre:angle) + (angle/2)
					end = 360 - (round sectorTo pre:angle) + (angle/2)
					k = (start - end)/angle
					--format "% % %
" start end k
				)
				createinstance Tube sides:k heightsegs:h capsegs:1 \
					height:(h*brickHeight) radius1:radius radius2:(radius-brickWidth) \
					slice_on:slide sliceFrom:start sliceTo:end \
					smooth:off mapcoords:(brickMapCoords > 0) realWorldMapSize:brickRealWorldMapSize
			)
			setMesh mesh b.mesh
			free b
			--format "time:% bricks:%
" (timestamp()-t1) numBricks
		)
		else
		(	
			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 = copy b.mesh 
			
			numBrickVerts = brick.numverts
			numBrickFaces = brick.numfaces
			
			local verts = #{1..numBrickVerts}
			
			local w = brickWidth/2
			local r = radius * cos(angle/2) - w
			local offset = [r,0,0]

			local vert_array = for v in verts collect 
			(
				p = (getvert brick v) + offset
				if brickTaper do 
				(
					--format "v:% % % %
" v p r (r+w)
					p.y *= p.x/(r+w)
				)
				p
			)
			
			local meshes = #()
			offset = [0,0,0]
			if useClone then
			(
				local bricks = #() 
				for k=0 to n-1 do
				(
					ang = k*angle
					if not sector or (ang >= sectorFrom and ang <= sectorTo) do
					(
						transformVerts brick vert_array offset:offset angle:(90 - ang)
						numBricks += 1
						append bricks (copy brick)
					)
				)
				if numBricks > 0 do
				(
					setmesh brick (attachMeshes bricks)
					offset = [0,0,0]
					
					vert_array = for v=1 to brick.numverts collect (getvert brick v)
					
					for z=0 to h-1 do
					(
						offset.z = brickHeight*z
						s = getShift angle index:z
						transformVerts brick vert_array offset:offset angle:-s
						append meshes (copy brick)
					)
					numBricks *= h 
				)
			)
			else
			(
				for z=0 to h-1 do
				(
					offset_z = brickHeight*z
					s = getShift angle index:z
						
					for k=0 to n-1 do
					(
						ang = k*angle
						if not sector or (ang >= sectorFrom and ang <= sectorTo) do
						(
							--offset.x = random -0.2 0.2
							offset.z = offset_z --+ (random -0.1 0.1)
							transformVerts brick vert_array offset:offset angle:(90 - ang - s)
							numBricks += 1
							append meshes (copy brick)
						)
					)
				)
			)
			if numBricks > 0 do setmesh mesh (attachMeshes meshes)
			free b
			free meshes
			format "time:% bricks:%
" (timestamp()-t1) numBricks
		)
	)

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

during manual creation i use tube instance for faster preview. using #stop of tool creation i build the real mesh …

nice, it’s a great tutorial

Page 3 / 3