Books and more books


#1

Hey guys another fun and collaborative tool here. I figured why not!
I’ve recently come across some cool book shelve filling tools, but sadly there were all seemingly missing basic features/controls that I’d expect to see. Aside from that, some cost way to much $$$ which we all know, not many of us have lying around waiting to get spent on a little mxs.

Any who lets get to it.
I’ve gone ahead and began to hard code a basic book layout tool.
The script creates a plane as a shelf, then distributes the books according to the settings.

For now I’m just hard-coding everything like I have in the past and then I’ll develop a UI once this gets far enough along. I’d love to take in everyones contributions and ideas to make this tool like many past ones, a solid tool that users can find useful.

Now for the task lists

Things Completed

  • Books distribute randomly from the back of the shelf to the front base on desired settings
  • Struct implementation to store the node and its dimensions.

Things To Do!

  • Add a random rotation with a range control for Y
  • Along with the random Y rotation, adjust books to fit snug against one another
  • Allow for random number of books to be placed lying flat on the shelf, face down
  • Add ‘N’ number of books until the shelf is full

The next thing to tackle is figuring out how to aligns books against one another whom have a varying Y rotation on them.


delete objects
clearlistener()

shelf = plane length:20 width:60 pos:[0,0,10] wirecolor:[150,215,230] 

struct bookData (node, thick, depth, height)
curBooks = #()

disableSceneRedraw()
for i = 1 to 20 do 
(
	mybook = box width:(random 0.5 3.0) height:(random 8.0 20.0) length:(random 8.0 15.0) pos:[(-3*i),0,0] wirecolor:[150,230,90]
	
	bb = nodeLocalBoundingBox mybook
	thick = abs (bb[1].x - bb[2].x)
	depth = abs (bb[1].y - bb[2].y)
	height = abs (bb[1].z - bb[2].z)
	append curBooks (bookData node:myBook thick:thick depth:depth height:height)
)
enableSceneRedraw()

/*Start the calculating*/
bb = nodeLocalBoundingBox shelf
shelfWidth = abs (bb[1].x - bb[2].x)
shelfDepth = abs (bb[1].y - bb[2].y)

offset = 0.0

for b = 1 to curBooks.count do 
(
	book = curBooks[b]
	shelfCorner = [bb[1].x,bb[2].y,shelf.pos.z] --back left corner of shelf

	book.node.pos = shelfCorner + [(book.thick/2.0),-(book.depth/2.0),0] --place book in furthest back corner of shelf
	
	--now adjust books position so there is no collision with previously placed books
	book.node.pos.x += offset
	
	--now adjust the books position depth wise based on the backFront 
	backFront =( random 0.0 1.0) -- 0.0:back 1.0:front
	book.node.pos.y -= (backFront*(shelfDepth-book.depth))

	offset += book.thick --continue to count offset from previous books
)



#2

no, no, no… not again… why does this idea so excite young developers?


#3

Haha, it’s something I’ve personally never done.
I’d be more than glad to work on something that someone would find useful, that wouldn’t be a book script.

I’m open to any suggestions for new tools that would be unique and different from anything previously created.


#4

i can sell you an idea…
all stars in the space are most known by position. our forefathers defined constellations. but… today we can ‘pseudo randomly’ generate the new ones. and name them! is it not cool? :slight_smile: pointless? probably. but much better than do ‘how to put books to shelves making them look that you’ve read them’ :wink:


#5

So in short a galaxy of stars creator? with constellations?


#6

yes! be God!


#7

Here is something I’ve been wanting to do for awhile. It would allow for quickly throwing down hills for proxy placement in environments.

A mesh object that has a spinner for radius and then another spinner which would control the height.

As the height increases the loops between the center point and the outer ring would move in the fashion of an arch.
You’ll see in the background a read object which is incorrect. That method’s verts are moving linearly which is not what I’d want. You can look at the oilTank it’s similiar to what I’m talking about.

Update

You could have 3 spinners
1 for radius
2 for center height
3 for controller the interpolation from the outer ring to the center point.

So users could make it linear or arch/curved.


#8

Here we go Denis.
I’ve got some basic stuff setup here for this so far.

How do I then implement an arch in the loops as they reach the top end point?


----Created by John Martini & Grant Miller

plugin simpleObject Mound
	name:"Mound"
	category:"Joker_Martini"
	classID:#(0x5b0fad29, 0x62323fc1)

-- -- -- -- --The Mound Mesh Creator Script-- -- -- -- --
(
	parameters paramBlock rollout:paramRollout 
	(
		radius1 type:#worldunits animatable:true	ui:uiRadius1 default:0
		radius2 type:#worldunits animatable:true	ui:uiRadius2 default:0
		segments type:#integer animatable:true ui:uiSegments default:8
		subdivs type:#integer animatable:true	ui:uiSubDivs default:0
		height type:#worldunits animatable:true ui:uiHeight default:0
		
		on radius1 set val do 
		(
			if radius1 < 0 then radius1 = 0
		)
		
		on radius2 set val do 
		(
			if radius2 < 0 then radius2 = 0
		)
	)
	-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
	rollout paramRollout "Parameters" 
	(
		spinner	uiRadius1 "Radius 1:" range:[-1e+6, 1e+6, 0]
		spinner	uiRadius2	"Radius 2:" range:[-1e+6, 1e+6, 20]
		spinner	uiSegments "Segments:"	range:[3, 200, 0] type:#integer
		spinner	uiSubDivs	"Loops:" range:[0, 200, 0] type:#integer
		spinner uiHeight "Height:" range:[0, 100, 0] type:#worldunits
	)
	-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 

	-- function for creating faces
	-- OPTIONS: mesh, face index, vertices as point3, material id
	fn createface msh fcndx vrts edgvis faceid = 
	(	
		local edg
		setface msh fcndx [vrts.x, vrts.y, vrts.z]
		if edgvis.x == 1 then edg = true else edg = false
		setedgevis msh fcndx 1 edg
		if edgvis.y == 1 then edg = true else edg = false
		setedgevis msh fcndx 2 edg
		if edgvis.z == 1 then edg = true else edg = false
		setedgevis msh fcndx 3 edg
		setfacesmoothgroup msh fcndx 0
		setfacematid msh fcndx faceid
		
	)
	fn FlipObjNormal obj =
	(
		for f =1 to obj.numFaces do --for each face in the mesh
		(
			verts=getface obj f -- get its 3 vertices as a point3
			local tmp=verts.x -- swap the first and third vertices
			verts.x=verts.z -- which flips the normal
			verts.z=tmp -- (right-hand rule), and 
			setface obj f verts -- store the new vertex order for the face
		)
		update obj -- update object so 3ds Max sees the changes
	)
	-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
	on buildmesh do 
	(	
		local varVertices = segments * (subdivs + 2)
		local varFaces = (segments * (subdivs + 1)) * 2
		local varVertCount = 1, varFaceCount = 1
		tmesh = trimesh()
		setmesh tmesh numverts:varVertices numfaces:varFaces
------- [draw vertices]
		local vertX, vertY, radius, theta, radadd, radstep, crcl
		radadd = ((radius2 - radius1) as float) / (subdivs + 1)
		radstep = (subdivs + 2)
		radius = radius1
		
------ arch implementation
		arch = 0
		for crcl = 1 to radstep do 
		(
			for theta = 0 to 359 by (360.0 / segments) do 
			(
				vertX = cos(theta) * radius
				vertY = sin(theta) * radius
				setvert tmesh varVertCount [vertX, vertY, (arch)]; varVertCount += 1
			)
			radius += radadd 
			arch += (height/(radstep-1))
			print radstep
			print (height/radstep)
		)

------- [draw faces]
		local curVert = 1, curFace, segCheck = 1
		for curFace = 1 to varFaces by 2 do 
		(		
			if segCheck == segments then 
				(
					segCheck = 0
					conVert = curVert - (segments - 1)
					createface tmesh curFace [curVert, curVert + segments, conVert + segments] [1, 1, 0] 1
					createface tmesh (curFace + 1) [conVert + segments, conVert, curVert] [1, 1, 0] 1
				) 
				else 
				(
					createface tmesh curFace [curVert, curVert + segments, curVert + segments + 1] [1, 1, 0] 1
					createface tmesh (curFace + 1) [curVert + segments + 1, curVert + 1, curVert] [1, 1, 0] 1
			)
			
			curVert += 1; segCheck += 1
		)

		
------- [set mesh]
		setmesh mesh tmesh
		
------- [weld center if inner radius = 0]
		if radius1 == 0 then 
		(
			local i
			local weldVerts = for i = 1 to segments collect i
			meshop.weldvertset mesh weldVerts
		)
------- Flips normals		
		if (radius1 > radius2) then
		(
			FlipObjNormal mesh
			flipped = true
		)
------- Flips normals End Utility

	)
	
	-------------------------------------------------------------------------------
	tool create 
	(
		on mousepoint click do 
		(
			case click of 
			(
				1: nodeTM.translation = gridpoint 
				3: #stop
			)
		)
		
		on mousemove click do 
		(
			case click of 
			(
				2: 
				(
					radius2 = (distance nodeTM.position gridpoint)
					if abs(griddist.y) > radius2 then radius2 = abs(griddist.y)
					if radius2 < 0 then radius2 = 0
				)
				3: 
				(
					radius1 = (distance nodeTM.position gridpoint)
					if radius1 < 0 then radius1 = 0
				)
			)
		)
	)
)
delete objects
select (mound radius1:20.0 height:10.0 subdivs:10)
completeredraw()


#9

cool, call it boob factory :wink:


#10

here is my version:


  /* denisT collection 2013 */
  
  plugin simpleObject ConePlus name:"ConePlus"
  classID:#(0x00001967, 0x1023099b)
  category:"Standard Plus" 
  version:1
  (
  	local coneobject 
  	parameters plus rollout:plus
  	(
  		radius1 type:#worldUnits default:0 ui:ui_radius1
  		radius2 type:#worldUnits default:0 ui:ui_radius2
  		height type:#worldUnits default:0 ui:ui_height
  		bias type:#float default:0 ui:ui_bias
  		biasPower type:#float default:10 animatable:off ui:ui_biasPower
  		heightsegs type:#integer default:1 ui:ui_heightsegs
  		capsegs type:#integer default:1 ui:ui_capsegs
  		sides type:#integer default:16 ui:ui_sides
  		smooth type:#boolean default:on ui:ui_smooth
  		mapCoords type:#boolean default:on ui:ui_mapCoords
  		realWorldMapSize type:#boolean default:off ui:ui_realWorldMapSize 
  	)
  	rollout plus "Parameters" 
  	(
  		spinner ui_radius1 "Radius 1: " type:#worldUnits range:[0,1e9,0] fieldwidth:52 align:#rigth offset:[8,0]
  		spinner ui_radius2 "Radius 2: " type:#worldUnits range:[0,1e9,0] fieldwidth:52 align:#rigth offset:[8,-2]
  		spinner ui_height "Height: " type:#worldUnits  range:[0,1e9,0] fieldwidth:52 align:#rigth offset:[8,2]
  		spinner ui_bias "Height Bias: " type:#float  range:[-1,1,0] scale:0.01 fieldwidth:52 align:#rigth offset:[8,-2]
  		spinner ui_biasPower "Bias Power: " range:[1,100,0] type:#float scale:0.1 fieldwidth:52 align:#right offset:[8,-2] tooltip:"Bias Power"
  		spinner ui_heightsegs "Height Segments: " type:#integer range:[1,256,0] fieldwidth:52 align:#rigth offset:[8,4]
  		spinner ui_capsegs "Cap Segments: " type:#integer range:[1,256,0] fieldwidth:52 align:#rigth offset:[8,0]
  		spinner ui_sides "Sides: " type:#integer range:[3,256,0] fieldwidth:52 align:#rigth offset:[8,0]
  		checkbox ui_smooth "Smooth" align:#left offset:[83,4]
  		checkbox ui_mapCoords "Generate Mapping Coords." align:#left offset:[-8,4]
  		checkbox ui_realWorldMapSize "Real-World map Size" align:#left offset:[-8,0]
  	)
  	on buildmesh do 
  	(
  		fn fastValue f bias:0.0 power:1 = 
  		(
  			if bias < 0 then 1 - (pow (1 - f) (1 - power*bias)) else (pow f (1 + power*bias))
  		)
  
  		if coneobject == undefined do coneobject = createinstance cone 
  		coneobject.radius1 = radius1	
  		coneobject.radius2 = radius2
  		coneobject.height = height
  		coneobject.heightsegs = heightsegs	
  		coneobject.capsegs = capsegs
  		coneobject.sides = sides
  		coneobject.smooth = smooth	
  		coneobject.mapCoords = mapCoords
  		coneobject.realWorldMapSize = realWorldMapSize
  		mesh = coneobject.mesh
  		
  		for k=1.0 to heightsegs-1 do
  		(
  			s = (k*sides+2) + (capsegs-1)*sides
  			e = ((k+1)*sides+1) + (capsegs-1)*sides
  			verts = #{s..e}
  			z = height*(fastValue (k/heightsegs) bias:bias power:biasPower)
  			for v in verts do 
  			(
  				p = getvert mesh v
  				setvert mesh v [p.x,p.y,z]
  			)
  		)
  		update mesh
  	)
  	tool create
  	(
  		on mousePoint click do case click of
  		(
  			1: nodeTM.translation = gridPoint
  			4: #stop
  		)
  		on mouseMove click do case click of
  		(
  			2: radius1 = amax (abs gridDist.x) (abs gridDist.y)
  			3: height = gridDist.z
  			4: radius2 = amax (abs gridDist.x) (abs gridDist.y)
  		)
  	)
  )
  

i can realize Slice as well but lazily to do it :slight_smile:


#11

align:#rigth

:wink: :wink: :wink: :wink:


#12

who cares… rigth is OK. right alignment is default for spinners anyway :wink:


#13

slice… ok, ok… here is it:


/* denisT collection 2013 */

plugin simpleObject ConePlus name:"ConePlus"
classID:#(0x00001967, 0x1023099b)
category:"Standard Plus" 
version:1
(
	local coneobject 
	parameters params rollout:params
	(
		radius1 type:#worldUnits default:0 ui:ui_radius1
		radius2 type:#worldUnits default:0 ui:ui_radius2
		height type:#worldUnits default:0 ui:ui_height
		bias type:#float default:0 ui:ui_bias
		biasPower type:#float default:10 ui:ui_biasPower
		heightsegs type:#integer default:1 ui:ui_heightsegs
		capsegs type:#integer default:1 ui:ui_capsegs
		sides type:#integer default:16 ui:ui_sides
		smooth type:#boolean default:on ui:ui_smooth
		sliceOn type:#boolean default:off ui:ui_sliceOn
		sliceFrom type:#float default:0 ui:ui_sliceFrom 
		sliceTo type:#float default:0 ui:ui_sliceTo
		mapCoords type:#boolean default:on ui:ui_mapCoords
		realWorldMapSize type:#boolean default:off ui:ui_realWorldMapSize 

		on sliceOn get val do try
		(
			this.params.ui_sliceFrom.enabled = this.params.ui_sliceTo.enabled = val
		)
		catch (false)
	)
	rollout params "Parameters" 
	(
		spinner ui_radius1 "Radius 1: " type:#worldUnits range:[0,1e9,0] fieldwidth:52 align:#right offset:[8,0]
		spinner ui_radius2 "Radius 2: " type:#worldUnits range:[0,1e9,0] fieldwidth:52 align:#right offset:[8,-2]
		spinner ui_height "Height: " type:#worldUnits range:[0,1e9,0] fieldwidth:52 align:#right offset:[8,2]
		spinner ui_bias "Height Bias: " type:#float range:[-1,1,0] scale:0.01 fieldwidth:52 align:#right offset:[8,-2]
		spinner ui_biasPower "Bias Power: " range:[1,100,0] type:#float scale:0.1 fieldwidth:52 align:#right offset:[8,-2] tooltip:"Bias Power"
		spinner ui_heightsegs "Height Segments: " type:#integer range:[1,256,0] fieldwidth:52 align:#right offset:[8,4]
		spinner ui_capsegs "Cap Segments: " type:#integer range:[1,256,0] fieldwidth:52 align:#right offset:[8,0]
		spinner ui_sides "Sides: " type:#integer range:[3,256,0] fieldwidth:52 align:#right offset:[8,0]
		checkbox ui_smooth "Smooth" align:#left offset:[83,4]
		checkbox ui_sliceOn "Slice On" align:#left offset:[83,2]
		spinner ui_sliceFrom "Slice From: " type:#float enabled:sliceOn range:[-1e9,1e9,0] scale:0.1 fieldwidth:52 align:#right offset:[8,0]
		spinner ui_sliceTo "Slice To: " type:#float enabled:sliceOn range:[-1e9,1e9,0] scale:0.1 fieldwidth:52 align:#right offset:[8,-2]
		checkbox ui_mapCoords "Generate Mapping Coords." align:#left offset:[-8,4]
		checkbox ui_realWorldMapSize "Real-World map Size" align:#left offset:[-8,0]
	)
	on buildmesh do 
	(
		fn fastValue f bias:0.0 power:1 = 
		(
			if bias < 0 then 1 - (pow (1 - f) (1 - power*bias)) else (pow f (1 + power*bias))
		)

		if coneobject == undefined do coneobject = createinstance cone 
		coneobject.radius1 = radius1	
		coneobject.radius2 = radius2
		coneobject.height = height
		coneobject.heightsegs = heightsegs	
		coneobject.capsegs = capsegs
		coneobject.sides = sides
		coneobject.smooth = smooth	
		coneobject.sliceOn = sliceOn	
		coneobject.sliceFrom = sliceFrom
		coneobject.sliceTo = sliceTo	
		coneobject.mapCoords = mapCoords
		coneobject.realWorldMapSize = realWorldMapSize
		mesh = coneobject.mesh
		
		for k=1.0 to heightsegs-1 do
		(
			ss = if sliceOn then (sides+2) else sides
			s = (k*ss+2) + (capsegs-1)*ss
			e = ((k+1)*ss+1) + (capsegs-1)*ss 
			verts = #{s..e}
			z = height*(fastValue (k/heightsegs) bias:bias power:biasPower)
			for v in verts do 
			(
				p = getvert mesh v
				setvert mesh v [p.x,p.y,z]
			)
		)
		update mesh
	)
	tool create
	(
		on mousePoint click do case click of
		(
			1: nodeTM.translation = gridPoint
			4: #stop
		)
		on mouseMove click do case click of
		(
			2: radius1 = amax (abs gridDist.x) (abs gridDist.y)
			3: height = gridDist.z
			4: radius2 = amax (abs gridDist.x) (abs gridDist.y)
		)
	)
)


#14

That is pretty slick.
I’ll have to play around with it and see what I can learn from it in how you are making an arch.


#15

Adjust the span and the height then run


delete objects
clearlistener()
span = 200.0 
height = 30.0
h = 1.0/2.0*(span)
a = -(height) / ((span - h)^2) -- equation to get a

for i = 0.0 to span by 5.0 do
(
	x = i --distance out from center
	arch = (a*((x - h)^2)) + height
	
	b= box height:2.0 width:2.0 length:2.0 wirecolor:[1*i,120,120] pos:[i/(2),0,arch]
	
)


#16

new version includes Radius Bias


/* denisT collection 2013 */

plugin simpleObject ConePlus name:"ConePlus"
classID:#(0x00001967, 0x1023099b)
category:"Standard Plus" 
version:1
(
	local coneobject 
	parameters params rollout:params
	(
		radius1 type:#worldUnits default:0 ui:ui_radius1
		radius2 type:#worldUnits default:0 ui:ui_radius2
		radiusBias type:#float default:0 ui:ui_radiusBias
		radiusBiasPower type:#float default:10 ui:ui_radiusBiasPower

		height type:#worldUnits default:0 ui:ui_height
		heightBias type:#float default:0 ui:ui_heightBias
		heightBiasPower type:#float default:10 ui:ui_heightBiasPower

		heightsegs type:#integer default:1 ui:ui_heightsegs
		capsegs type:#integer default:1 ui:ui_capsegs
		sides type:#integer default:16 ui:ui_sides
		smooth type:#boolean default:on ui:ui_smooth
		sliceOn type:#boolean default:off ui:ui_sliceOn
		sliceFrom type:#float default:0 ui:ui_sliceFrom 
		sliceTo type:#float default:0 ui:ui_sliceTo
		mapCoords type:#boolean default:on ui:ui_mapCoords
		realWorldMapSize type:#boolean default:off ui:ui_realWorldMapSize 

		on sliceOn get val do try
		(
			this.params.ui_sliceFrom.enabled = this.params.ui_sliceTo.enabled = val
		)
		catch (false)
	)
	rollout params "Parameters" 
	(
		spinner ui_radius1 "Radius 1: " type:#worldUnits range:[0,1e9,0] fieldwidth:52 align:#right offset:[8,0]
		spinner ui_radius2 "Radius 2: " type:#worldUnits range:[0,1e9,0] fieldwidth:52 align:#right offset:[8,-2]
		spinner ui_radiusBias "Radius Bias: " type:#float range:[-1,1,0] scale:0.01 fieldwidth:52 align:#right offset:[8,-2]
		spinner ui_radiusBiasPower "Radius Power: " range:[1,100,0] type:#float scale:0.1 fieldwidth:52 align:#right offset:[8,-2]
		spinner ui_height "Height: " type:#worldUnits range:[0,1e9,0] fieldwidth:52 align:#right offset:[8,6]
		spinner ui_heightBias "Height Bias: " type:#float range:[-1,1,0] scale:0.01 fieldwidth:52 align:#right offset:[8,-2]
		spinner ui_heightBiasPower "Height Power: " range:[1,100,0] type:#float scale:0.1 fieldwidth:52 align:#right offset:[8,-2]
		spinner ui_heightsegs "Height Segments: " type:#integer range:[1,256,0] fieldwidth:52 align:#right offset:[8,6]
		spinner ui_capsegs "Cap Segments: " type:#integer range:[1,256,0] fieldwidth:52 align:#right offset:[8,-2]
		spinner ui_sides "Sides: " type:#integer range:[3,256,0] fieldwidth:52 align:#right offset:[8,-2]
		checkbox ui_smooth "Smooth" align:#left offset:[83,6]
		checkbox ui_sliceOn "Slice On" align:#left offset:[83,2]
		spinner ui_sliceFrom "Slice From: " type:#float enabled:sliceOn range:[-1e9,1e9,0] scale:0.1 fieldwidth:52 align:#right offset:[8,0]
		spinner ui_sliceTo "Slice To: " type:#float enabled:sliceOn range:[-1e9,1e9,0] scale:0.1 fieldwidth:52 align:#right offset:[8,-2]
		checkbox ui_mapCoords "Generate Mapping Coords." align:#left offset:[-8,4]
		checkbox ui_realWorldMapSize "Real-World map Size" align:#left offset:[-8,0]
	)
	fn domesh = 
	(
		fn fastValue f heightBias:0.0 power:1 = 
		(
			if heightBias < 0 then 1 - (pow (1 - f) (1 - power*heightBias)) else (pow f (1 + power*heightBias))
		)

		if coneobject == undefined do coneobject = createinstance cone 
		coneobject.radius1 = radius1	
		coneobject.radius2 = radius2
		coneobject.height = height
		coneobject.heightsegs = heightsegs	
		coneobject.capsegs = capsegs
		coneobject.sides = sides
		coneobject.smooth = smooth	
		coneobject.sliceOn = sliceOn	
		coneobject.sliceFrom = sliceFrom
		coneobject.sliceTo = sliceTo	
		coneobject.mapCoords = mapCoords
		coneobject.realWorldMapSize = realWorldMapSize
		mesh = coneobject.mesh
		
		for k=1.0 to heightsegs-1 do
		(
			f = k/heightsegs
			ss = if sliceOn then (sides+2) else sides
			s = (k*ss+2) + (capsegs-1)*ss
			e = ((k+1)*ss+1) + (capsegs-1)*ss 
			verts = #{s..e}
			r = radius1 + (radius2 - radius1)*(fastValue f heightBias:radiusBias power:radiusBiasPower)
			h = height*(fastValue f heightBias:heightBias power:heightBiasPower)

			for v in verts do 
			(
				d = getvert mesh v
				p = (normalize [d.x,d.y,0])*r
				setvert mesh v [p.x,p.y,h]
			)
		)
		update mesh
		mesh
	)
	on buildmesh do domesh()

	tool create
	(
		on mousePoint click do case click of
		(
			1: nodeTM.translation = gridPoint
			4: #stop
		)
		on mouseMove click do case click of
		(
			2: radius1 = amax (abs gridDist.x) (abs gridDist.y)
			3: height = gridDist.z
			4: radius2 = amax (abs gridDist.x) (abs gridDist.y)
		)
	)
	on update do domesh()
)


#17

If radius2 = 0.0 it should weld all the center verts. Rather than having them all sit ontop of one another.


#18

i don’t think so. it should behave the same way as cone
there is a new version (i fixed topology issue when slice was on)


/* denisT collection 2013 */

plugin simpleObject ConePlus name:"ConePlus"
classID:#(0x00001967, 0x1023099b)
category:"Standard Plus" 
version:1
(
	local coneobject 
	parameters params rollout:params
	(
		radius1 type:#worldUnits default:0 ui:ui_radius1
		radius2 type:#worldUnits default:0 ui:ui_radius2
		radiusBias type:#float default:0 ui:ui_radiusBias
		radiusBiasPower type:#float default:10 ui:ui_radiusBiasPower

		height type:#worldUnits default:0 ui:ui_height
		heightBias type:#float default:0 ui:ui_heightBias
		heightBiasPower type:#float default:10 ui:ui_heightBiasPower

		heightsegs type:#integer default:1 ui:ui_heightsegs
		sides type:#integer default:16 ui:ui_sides

		capsOn type:#boolean default:on ui:ui_capsOn
		capsegs type:#integer default:1 ui:ui_capsegs

		smooth type:#boolean default:on ui:ui_smooth
		sliceOn type:#boolean default:off ui:ui_sliceOn
		sliceFrom type:#float default:0 ui:ui_sliceFrom 
		sliceTo type:#float default:0 ui:ui_sliceTo
		mapCoords type:#boolean default:on ui:ui_mapCoords
		realWorldMapSize type:#boolean default:off ui:ui_realWorldMapSize 

		on capsOn get val do 
		(
			try(this.params.ui_capsegs.enabled = val) catch (false)
			val
		)
		on sliceOn get val do 
		(
			try(this.params.ui_sliceFrom.enabled = this.params.ui_sliceTo.enabled = val) catch (false)
			val
		)
	)
	rollout params "Parameters" 
	(
		spinner ui_radius1 "Bottom Radius: " type:#worldUnits range:[0,1e9,0] fieldwidth:52 align:#right offset:[8,0]
		spinner ui_radius2 "Top Radius: " type:#worldUnits range:[0,1e9,0] fieldwidth:52 align:#right offset:[8,-2]
		spinner ui_radiusBias "Radius Bias: " type:#float range:[-1,1,0] scale:0.01 fieldwidth:52 align:#right offset:[8,-2]
		spinner ui_radiusBiasPower "Radius Power: " range:[1,100,0] type:#float scale:0.1 fieldwidth:52 align:#right offset:[8,-2]
		spinner ui_height "Height: " type:#worldUnits range:[0,1e9,0] fieldwidth:52 align:#right offset:[8,6]
		spinner ui_heightBias "Height Bias: " type:#float range:[-1,1,0] scale:0.01 fieldwidth:52 align:#right offset:[8,-2]
		spinner ui_heightBiasPower "Height Power: " range:[1,100,0] type:#float scale:0.1 fieldwidth:52 align:#right offset:[8,-2]
		spinner ui_heightsegs "Height Segments: " type:#integer range:[1,256,0] fieldwidth:52 align:#right offset:[8,6]
		spinner ui_sides "Sides: " type:#integer range:[3,256,0] fieldwidth:52 align:#right offset:[8,-2]

		checkbox ui_capsOn "Caps On" align:#left offset:[83,4]
		spinner ui_capsegs "Cap Segments: " type:#integer enabled:capsOn range:[1,256,0] fieldwidth:52 align:#right offset:[8,0]
		
		checkbox ui_smooth "Smooth" align:#left offset:[83,6]
		checkbox ui_sliceOn "Slice On" align:#left offset:[83,2]
		spinner ui_sliceFrom "Slice From: " type:#float enabled:sliceOn range:[-1e9,1e9,0] scale:0.1 fieldwidth:52 align:#right offset:[8,0]
		spinner ui_sliceTo "Slice To: " type:#float enabled:sliceOn range:[-1e9,1e9,0] scale:0.1 fieldwidth:52 align:#right offset:[8,-2]
		checkbox ui_mapCoords "Generate Mapping Coords." align:#left offset:[-8,4]
		checkbox ui_realWorldMapSize "Real-World map Size" align:#left offset:[-8,0]
	)
	fn domesh = 
	(
		fn fastValue f heightBias:0.0 power:1 = 
		(
			if heightBias < 0 then 1 - (pow (1 - f) (1 - power*heightBias)) else (pow f (1 + power*heightBias))
		)

		if coneobject == undefined do coneobject = createinstance cone 
		coneobject.radius1 = radius1	
		coneobject.radius2 = radius2
		coneobject.height = height
		coneobject.heightsegs = heightsegs	
		coneobject.capsegs = capsegs
		coneobject.sides = sides
		coneobject.smooth = smooth	
		coneobject.sliceOn = sliceOn	
		coneobject.sliceFrom = sliceFrom
		coneobject.sliceTo = sliceTo	
		coneobject.mapCoords = mapCoords
		coneobject.realWorldMapSize = realWorldMapSize
		mesh = coneobject.mesh
		
		for v=1 to mesh.numverts do 
		(
			d = getvert mesh v
			if d.z > 0 and d.z < height do
			(
				f = d.z/height
				h = height*(fastValue f heightBias:heightBias power:heightBiasPower)
				if (r = length [d.x,d.y,0]) > 0 do
				(
					f = (r-radius1)/(radius2-radius1)
					r = radius1 + (radius2-radius1)*(fastValue f heightBias:radiusBias power:radiusBiasPower)
				)
				p = (normalize [d.x,d.y,0])*r
				setvert mesh v [p.x,p.y,h]
			)
		)
		if not capsOn do 
		(
			faces = #{}
			for f=1 to mesh.numfaces do faces[f] = (getfacematid mesh f != 3)
			meshop.deletefaces mesh faces
		)
			
		update mesh
		mesh
	)
	on buildmesh do domesh()

	tool create
	(
		on mousePoint click do case click of
		(
			1: nodeTM.translation = gridPoint
			4: #stop
		)
		on mouseMove click do case click of
		(
			2: radius1 = amax (abs gridDist.x) (abs gridDist.y)
			3: height = gridDist.z
			4: radius2 = amax (abs gridDist.x) (abs gridDist.y)
		)
	)
	on update do domesh()
)


#19

could always make it an option.


#20

Here is some additional fun…radial noise controls.
You’ll see I commented out some code I had implemented to resemble what you had there, but it kept throwing errors when it was un-commented.

Anywho it works great. Fun to mess with.


plugin simpleObject ConePlus name:"ConePlus"
classID:#(0x00001967, 0x1023099b)
category:"Standard Plus" 
version:1
(
	local coneobject 
	parameters params rollout:params
	(
		radius1 type:#worldUnits default:0 ui:ui_radius1
		radius2 type:#worldUnits default:0 ui:ui_radius2
		radiusBias type:#float default:0 ui:ui_radiusBias
		radiusBiasPower type:#float default:10 ui:ui_radiusBiasPower
		
		noiseFrequency type:#float default:1 animatable:off ui:ui_noiseFrequency
		noisePhase type:#float default:0 animatable:off ui:ui_noisePhase
		noiseScale type:#float default:1 animatable:off ui:ui_noiseScale
		
		height type:#worldUnits default:0 ui:ui_height
		heightBias type:#float default:0 ui:ui_heightBias
		heightBiasPower type:#float default:10 ui:ui_heightBiasPower
		
		heightsegs type:#integer default:1 ui:ui_heightsegs
		capsegs type:#integer default:1 ui:ui_capsegs
		sides type:#integer default:16 ui:ui_sides
		smooth type:#boolean default:on ui:ui_smooth
		
		sliceOn type:#boolean default:off ui:ui_sliceOn
		sliceFrom type:#float default:0 ui:ui_sliceFrom 
		sliceTo type:#float default:0 ui:ui_sliceTo
		mapCoords type:#boolean default:on ui:ui_mapCoords
		realWorldMapSize type:#boolean default:off ui:ui_realWorldMapSize 
		
		on sliceOn get val do try
		(
			this.params.ui_sliceFrom.enabled = this.params.ui_sliceTo.enabled = val
		)
		catch (false)
	)
	rollout params "Parameters" 
	(
		spinner ui_radius1 "Radius 1: " type:#worldUnits range:[0,1e9,0] fieldwidth:52 align:#right offset:[8,0]
		spinner ui_radius2 "Radius 2: " type:#worldUnits range:[0,1e9,0] fieldwidth:52 align:#right offset:[8,-2]
		spinner ui_radiusBias "Radius Bias: " type:#float range:[-1,1,0] scale:0.01 fieldwidth:52 align:#right offset:[8,-2]
		spinner ui_radiusBiasPower "Radius Power: " range:[1,100,0] type:#float scale:0.1 fieldwidth:52 align:#right offset:[8,-2]
		spinner ui_noiseScale "Noise Scale: " range:[-1e9,1e9,0] type:#float scale:0.01 fieldwidth:54 align:#right offset:[8,6] tooltip:"Noise Scale"
		spinner ui_noiseFrequency "Noise Frequency: " range:[0,1e9,0] type:#float scale:0.01 fieldwidth:54 align:#right offset:[8,-2] tooltip:"Noise Frequency" 
		spinner ui_noisePhase "Noise Phase: " range:[-1e9,1e9,0] type:#float scale:0.1 fieldwidth:54 align:#right offset:[8,-2] tooltip:"Noise Phase"
		spinner ui_height "Height: " type:#worldUnits range:[0,1e9,0] fieldwidth:52 align:#right offset:[8,6]
		spinner ui_heightBias "Height Bias: " type:#float range:[-1,1,0] scale:0.01 fieldwidth:52 align:#right offset:[8,-2]
		spinner ui_heightBiasPower "Height Power: " range:[1,100,0] type:#float scale:0.1 fieldwidth:52 align:#right offset:[8,-2]
		spinner ui_heightsegs "Height Segments: " type:#integer range:[1,256,0] fieldwidth:52 align:#right offset:[8,6]
		spinner ui_capsegs "Cap Segments: " type:#integer range:[1,256,0] fieldwidth:52 align:#right offset:[8,-2]
		spinner ui_sides "Sides: " type:#integer range:[3,256,0] fieldwidth:52 align:#right offset:[8,-2]
		checkbox ui_smooth "Smooth" align:#left offset:[83,6]		
		checkbox ui_sliceOn "Slice On" align:#left offset:[83,2]
		spinner ui_sliceFrom "Slice From: " type:#float enabled:sliceOn range:[-1e9,1e9,0] scale:0.1 fieldwidth:52 align:#right offset:[8,0]
		spinner ui_sliceTo "Slice To: " type:#float enabled:sliceOn range:[-1e9,1e9,0] scale:0.1 fieldwidth:52 align:#right offset:[8,-2]
		checkbox ui_mapCoords "Generate Mapping Coords." align:#left offset:[-8,4]
		checkbox ui_realWorldMapSize "Real-World map Size" align:#left offset:[-8,0]
	)
	fn domesh = 
	(
		fn fastValue f heightBias:0.0 power:1 = 
		(
			if heightBias < 0 then 1 - (pow (1 - f) (1 - power*heightBias)) else (pow f (1 + power*heightBias))
		)
		
		if coneobject == undefined do coneobject = createinstance cone 
		coneobject.radius1 = radius1	
		coneobject.radius2 = radius2
-- 		coneobject.noiseFrequency = noiseFrequency
-- 		coneobject.noisePhase = noisePhase
-- 		coneobject.noiseScale = noiseScale
		coneobject.height = height
		coneobject.heightsegs = heightsegs	
		coneobject.capsegs = capsegs
		coneobject.sides = sides
		coneobject.smooth = smooth	
		coneobject.sliceOn = sliceOn	
		coneobject.sliceFrom = sliceFrom
		coneobject.sliceTo = sliceTo	
		coneobject.mapCoords = mapCoords
		coneobject.realWorldMapSize = realWorldMapSize
		mesh = coneobject.mesh
		
		for k=1.0 to heightsegs-1 do
		(
			f = k/heightsegs
			ss = if sliceOn then (sides+2) else sides
			s = (k*ss+2) + (capsegs-1)*ss
			e = ((k+1)*ss+1) + (capsegs-1)*ss 
			verts = #{s..e}
			noise = ((noise3 ([f*noiseFrequency,0,noisePhase]))*10*noiseScale)
			r = radius1 + (radius2 - radius1)*(fastValue f heightBias:radiusBias power:radiusBiasPower) + noise
			h = height*(fastValue f heightBias:heightBias power:heightBiasPower)
			
			
			print noise	
				
			for v in verts do 
			(
				d = getvert mesh v
				p = (normalize [d.x,d.y,0])*r
				setvert mesh v [p.x,p.y,h]
			)
		)
		update mesh
		mesh
	)
	on buildmesh do domesh()

	tool create
	(
		on mousePoint click do case click of
		(
			1: nodeTM.translation = gridPoint
			4: #stop
		)
		on mouseMove click do case click of
		(
			2: radius1 = amax (abs gridDist.x) (abs gridDist.y)
			3: height = gridDist.z
			4: radius2 = amax (abs gridDist.x) (abs gridDist.y)
		)
	)
	on update do domesh()
)