Notifications
Clear all

[Closed] Sample Simple Object Plug-in

i can make it 2 times faster. but that’s probably will be the limit for this algorithm… thereby it makes 2000 bevel-edge bricks for 0.4 sec on my machine. i think it’s more than enough for sample.

working on this plugin-in i got:
#1 smart attaching makes sense for meshes
#2 i have to add c++ function to my script extension – transformvert. it’s similar to movevert but does do multiplication on matrix. why does max not have it?
#3 setmesh is a great function. why i didn’t use it before?

Set

SetMesh for normal operations or just plugins?

I like the 2000 in .4 seconds, very nice.

for many mesh/trimesh things… see mxs help:


   [left][b]setMesh[/b] <mesh> \
   [[b]vertices[/b]:<array_of_point3s>]\
   [[b]faces[/b]:<array_of_point3s>]\
   [[b]materialIDs[/b]:<array_of_integers>]\
   [[b]tverts[/b]:<array_of_point3s>]
 [/left]
 [left] 

[/left]
[left]Resets the mesh based on the given arrays. Only those portions of the mesh that are specified are reset. For example, if only the vertices: parameter is specified, the existing face data is retained. Each Point3 value in the vertices array specifies the position of the vertex in the current coordinate system. Each Point3 value in the faces array specifies the 3 vertex indices that form the face. The materialIDs array specifies the material ID to be assigned to each face. Each Point3 value in the tverts array specifies the UVW coordinates of the texture vertices. See Texture Mapping in the methods section for more information on texture vertices.

[/left]
[left]THAT’S REALLY COOL

[/left]

ain’t sure if any meat on this bone… Denis?
it w’d be not so cool result on small brick pattern
but a good base primitive at all, i think,
just not an easy task for my pure maths.

plugin Geometry BrickCylinder
	name:"BrickCylinder" 
	category:"Scripted Primitives" 
	classID:#(0x111, 0x566) version:1 
	extends:Cylinder replaceUI:[b]false[/b] 
(
	on buildMesh do
	(
		local f_arr = #{1..delegate.numfaces}
		local e_arr = smartAlgorithm() [b]--//TODO...[/b]
 
		for f in f_arr do (
			for i = 1 to 3 do
			setEdgeVis delegate f i e_arr[f][i]
		)
	)
)

as i said there is no any point for me to make a fast preview… if i would do it i do it with simple tube. the point for me is to find an algorithm of fast mesh build. and i already have pretty good result.

1 Reply
(@panayot)
Joined: 10 months ago

Posts: 0

i see… looks like my post is more personal request never mind…
well, i’ll apricate your help on this as using simple primitive and extrude it with modifiers sounds good to me…

and some question… i never used attach() in simpleObject but only boolean ops
– like…
mesh = A.mesh + B.mesh – C.mesh
– or…
setMesh mesh (A.mesh * B.mesh)
so… is there some benefit in Attach vs Booleans?

Very interesting Denis. I saw that method before, but never really looked into it.

+,-,* mesh operations are absolutely different things… they are boolean operations: union, difference, and intersection.
i’m using attach because i simply need to add some mesh to another mesh. max is doing it very fast, but after that it updates the mesh. and the updating is slow. i looked for but couldn’t find any way to suspend mesh update.

1 Reply
(@panayot)
Joined: 10 months ago

Posts: 0

Thanks for the reply and sorry for the mess.
as am busy with alot of staffs, its take me some time to see the point in this topic.

Scripted object plug-ins are so cool, too bad it’s so few of them. This is a great example though, thanks for posting!

How about a parameter that controls the “growth” of the chimney i.e. brick by brick?
Here is my clunky attempt. There must be a more elegant way of doing this?
Fixed it now, I think.



/* 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
		completion type:#float default:1.0 ui:ui_completion
		
		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
			spinner ui_completion "Completion:" type:#float range:[0,1,1] fieldwidth:56 scale:0.0001
		)
		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 = #()
			
			local limit = ((numberRows()-1) * ((completion * 10 as integer) / 10))

			for z=0 to limit as integer do
			(
				
				offset.z = brickHeight*z
				s = shift*angle*z
		
				local brickLimit
				if z != limit as integer or completion == 1.0 then
					brickLimit = 1.0
				else 
				(
					brickLimit = limit - z
					compPercentage2 = if brickLimit > 0.9999 then 1.0 else brickLimit--if compPercentage2 == 1.0 then 0.0 else compPercentage2 --this did not work for some reason
				)
				
				for k=0 to ((n-1) * (limit - z) ) 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
		)
	)
)


1 Reply
(@denist)
Joined: 11 months ago

Posts: 0

interesting idea! thanks for playing with me

Thanks for posting this script denisT it works great

here is some progress:
#1 Brick Taper added
#2 Chimney Sector added
Two methods used now: Generate by Brick and Generate By Ring (Clone method). Second method is faster but has some limitations in case of Randomization.


/* denisT script collection (2012)*/

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

	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

		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]

		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:[72,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:[72,2]
			checkbox ui_brickSmooth "Smooth" offset:[72,-2]
			checkbox ui_brickMapCoords "Apply Mapping Coords." offset:[0,2] 
			checkbox ui_brickRealWorldMapSize "Real-World Map Size" offset:[0,-2]  
		)
	)
	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
		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 = copy b.mesh 
			
			numBrickVerts = brick.numverts
			numBrickFaces = brick.numfaces
			
			local verts = #{1..numBrickVerts}
			
			local angle = 360.0/n
			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: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)
					
					h = numberRows()
					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 numberRows()-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
						(
							transformVerts brick vert_array offset:offset angle:(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: 
			(
				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
		)
	)
)

Enjoy!

Page 2 / 3