Notifications
Clear all

[Closed] Books and more books

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
)


19 Replies

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

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.

1 Reply
(@denist)
Joined: 11 months ago

Posts: 0

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? pointless? probably. but much better than do ‘how to put books to shelves making them look that you’ve read them’

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

1 Reply
(@denist)
Joined: 11 months ago

Posts: 0

yes! be God!

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.

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()

cool, call it boob factory

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

align:#rigth

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

Page 1 / 2