Sample Simple Object Plug-in

Become a member of the CGSociety

Connect, Share, and Learn with our Large Growing CG Art Community. It's Free!

THREAD CLOSED
 
Thread Tools Search this Thread Display Modes
  01 January 2012
Arrow Sample Simple Object Plug-in

following this discussion http://forums.cgsociety.org/showthr...?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.
 
  01 January 2012
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...
 
  01 January 2012
Cool! Although its extremely slow for me in Max 2010 64bit. Takes seconds to update anything/create it.
 
  01 January 2012
Originally Posted by Kickflipkid687: Cool! Although its extremely slow for me in Max 2010 64bit. Takes seconds to update anything/create it.


i know. i'm thinking about a way of optimization. vertex transformation kills the performance. maybe attaching too.
 
  01 January 2012
Maybe do a sort of Proxy while editing/creating that is lower poly, then on end, create the higher poly mesh?
 
  01 January 2012
Originally Posted by Kickflipkid687: Maybe do a sort of Proxy while editing/creating that is lower poly, then on end, create the higher poly mesh?

yes. it's the right way. but i'm not looking for easy ways
 
  01 January 2012
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.
 
  01 January 2012
attach mesh is the bottleneck...
 
  01 January 2012
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]
 
  01 January 2012
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:%\n" (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
		)
	)
)
 
  01 January 2012
Still is a bit laggy for me, but definitely faster.
 
  01 January 2012
Can this access multiple cores then?
 
  01 January 2012
Originally Posted by Kickflipkid687: Still is a bit laggy for me, but definitely faster.


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?
 
  01 January 2012
Set
Originally Posted by denisT: 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?


SetMesh for normal operations or just plugins?

I like the 2000 in .4 seconds, very nice.
 
  01 January 2012
Originally Posted by Kickflipkid687: SetMesh for normal operations or just plugins?

for many mesh/trimesh things... see mxs help:

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

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.

THAT'S REALLY COOL


Last edited by denisT : 01 January 2012 at 12:44 AM.
 
Thread Closed share thread



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off
CGSociety
Society of Digital Artists
www.cgsociety.org

Powered by vBulletin
Copyright 2000 - 2006,
Jelsoft Enterprises Ltd.
Minimize Ads
Forum Jump
Miscellaneous

All times are GMT. The time now is 02:54 PM.


Powered by vBulletin
Copyright ©2000 - 2017, Jelsoft Enterprises Ltd.