[Closed] Pipes Generator
So I’ve search around on the inter-web and didn’t find to many great pipe generator tools and on top of that I’ve been unable to find any good ones fore free. I’m going to start a thread here on cgtalk where I will begin to build a develop and free and openly coded tool. Anyone is more than welcome to share their input and ideas as I’m always open to making things as good as we can. I’ve started a very rough base so far. Take a look.
The download zip is needed.
Right now each pipe is being randomly selected when being created next which is purely for the purpose of quick testing reasons. I will eventually give the control for users to pick which pipe is to be created next as well as having the option to just randomly grow pipes.
try(destroyDialog rlCreate)catch()
rollout rlCreate "Boxes"
(
local cs = $SmallCornerCtrl
local s = $SmallCtrl
local m = $MediumCtrl
local t = $LargeCtrl
button btnCreate "Create"
on btnCreate pressed do (
if selection.count >= 1 then
(
ends = #()
for o in selection where classof o == Point AND findString o.name "End" != undefined do
(
pipes = #(cs,s,m,t)
p = pipes[random 1 pipes.count]
local newPipes
if not (maxOps.cloneNodes p expandHierarchy:true newNodes:&newPipes) then throw "Not good!"
pipeCtrl = newPipes[1]
pipeCtrl.transform = copy o.transform
for c in newPipes where classof c == Point AND findstring c.name "End" != undefined do append ends c
)
select ends
)
else
(
pipes = #(cs,s,m,t)
p = pipes[random 1 pipes.count]
ends = #()
local newPipes
if not (maxOps.cloneNodes p expandHierarchy:true newNodes:&newPipes) then throw "Not good!"
pipeCtrl = newPipes[1]
pipeCtrl.pos = [0,0,0]
for c in newPipes where classof c == Point AND findstring c.name "End" != undefined do append ends c
select ends
)
)
)
createDialog rlCreate
Thanks.
Rough but working!!
Added parenting so you can rotate pipes and effect the pipes which are growing from that particular one.
try(destroyDialog rlCreate)catch()
rollout rlCreate "Boxes"
(
local cs = $SmallCornerCtrlStart
local s = $SmallCtrlStart
local m = $MediumCtrlStart
local t = $LargeCtrlStart
local cros = $CrossCtrlStart
button btnCreate "Create"
on btnCreate pressed do (
if selection.count >= 1 then
(
ends = #()
for o in selection where classof o == Point AND findString o.name "End" != undefined do
(
pipes = #(cs,s,m,t,cros)
p = pipes[random 1 pipes.count]
maxOps.cloneNodes p expandHierarchy:true cloneType:#copy actualNodeList:&refPipes newNodes:&newPipes
pipeCtrl = newPipes[1]
pipeCtrl.transform = copy o.transform
--link children
for p in newPipes where classof p == circle AND findString p.name "Start" !=undefined do p.parent = (o.parent.parent)
for c in newPipes where classof c == Point AND findstring c.name "End" != undefined do append ends c
)
select ends
)
else
(
pipes = #(cs,s,m,t)
p = pipes[random 1 pipes.count]
newPipes = #()
maxOps.cloneNodes p expandHierarchy:true cloneType:#copy actualNodeList:&refPipes newNodes:&newPipes
pipeCtrl = newPipes[1]
pipeCtrl.pos = [0,0,0]
ends = for c in newPipes where classof c == Point AND findstring c.name "End" != undefined collect c
select ends
)
)
)
createDialog rlCreate
search this forum. I am pretty sure i remember a pipe generator maxscript project some time ago
Yeah I had come across it already but in my mind it was not as good as it could be. That is why I’m going to take the concept of pipe generation and make it more user friendly and much more stable.
there is a little addition to your code:
local rots = #(-90,0,90,180)
on btnCreate pressed do (
if selection.count > 0 then
(
ends = #()
for o in selection where classof o == Point AND findString o.name "End" != undefined do
(
pipes = #(cs,s,m,t,cros)
p = pipes[random 1 pipes.count]
maxOps.cloneNodes p expandHierarchy:true cloneType:#copy actualNodeList:&refPipes newNodes:&newPipes
pipeCtrl = newPipes[1]
pipeCtrl.transform = copy (prerotatez o.transform rots[random 1 rots.count])
Very cool.
I was just going to add the random rotation to.
I’m going to start building out a UI and from there figure out a good way to make this more useable and give more options. Such as a preview and also the option of having … auto generate pipes.
Controls?
Does anyone have any particular opinions on what type of controls they would like to have for this.
My ideas were:
- Ability to use custom pipes.
- Ability to Auto generate pipe system (grow)
- Auto generate next pipe (with collision detection)
- Option to generate specific pipes at any given time
- Rotation Controls
As far as anything else that is all I can think up.
It would be cool to somehow grow pipes around and object but that may be for another day haha.
Hey guys. Things are coming together nicely here. In the newest update you’ll see a UI now.
To try it out download the attached file and run the script. Once the script is up and running select all the objects in the scene and hit ‘Add’. Then clear your selection and hit Generate.
Workings:
Based on the items selected in your list that controls which pipe type will be created. If you have more than one item selected it will randomly pick one of the pipes to create.
Things I’d like to add.
A control which drives the rotation of the pipes to limit their rotation. So users can grow pipes just on the X but with slight rotation say -30 to +30. If users use 360 then it will create it all directions.
Secondly I need to create a script which selects the last children of the entire pipe tree so users can quickly select the ends and continue building. In short a script which selects only children whom don’t have children. But the initial selection before running the script could take place anywhere in the hierarchy.
Lastly I’d like to add some sort of preview option and raycast intersection detection system to help drive which pipe gets randomly generated. Which that would come an option where users could pick whether or not they care if it intersects.
I’d love to get some feedback and ideas from you guys. Thanks again for the help so far guys.
try(destroyDialog rlPipesGenerator)catch()
rollout rlPipesGenerator "Pipes Generator"
(
local pipeList = #()
local rots = #(-90,0,90,180)
fn getChildren node = (
local tmpArr = #()
for c in node.children do
(
append tmpArr c
join tmpArr (getChildren c)
)
tmpArr
)
fn checkStart node = (if classof node == Point AND findString node.name "Start" != undefined then true else false)
fn checkEnd node = (
children = getChildren node
endNodes = for o in children where classof o == Point AND findString o.name "End" != undefined collect o
if endNodes.count >= 1 then true else false
)
fn getEnds arr = (
local tmpArr = #()
tmpArr = if arr.count >= 1 then (for o in arr where classof o == Point AND findString o.name "End" != undefined collect o) else #()
tmpArr
)
fn fnAddItmsLst lst arr = ( -- add Objects to list if they meet requirements
curSel = getCurrentSelection() as array
tmpArr = for p in curSel where (checkStart p) AND (checkEnd p) collect p
if tmpArr.count >= 1 do
(
for o in tmpArr do (appendIfUnique arr o)
lst.items = for i in arr collect i.name -- update list with array
)
)
fn fnRemoveItmsLst lst arr = ( -- remove objects from list
local currSel = lst.selection
for i = lst.items.count to 1 by -1 where currSel[i] do (deleteItem arr i)
lst.items = for i in arr collect i.name -- update list with array
lst.selection = #{}
)
label lbPipes "Available Pipes:" pos:[10,10]
multilistbox lstPipes "" items:#() width:140 height:10 pos:[10,30]
button btnInfo "Info ?" height:20 width:60 pos:[150,30]
button btnAdd "Add" height:58 width:60 pos:[150,50]
button btnRemove "Remove" height:58 width:60 pos:[150,108]
button btnGeneratePipes "Generate Pipes" width:200 height:30
on btnInfo pressed do (
infoMessage = stringStream ""
format "%
" "Items which are added to the list must meet the following requirements:" to:infoMessage
format "
%" "1. The object being added must be a Point Helper." to:infoMessage
format "
%" "2. The object's name must contain the word 'Start'." to:infoMessage
format "
%" "3. The object added must contain atleast one children 'Point Helper' object." to:infoMessage
format "
%" "4. The child object's names must contain the word 'End'." to:infoMessage
format "
%" "NOTE: There can be more than one child point helper object." to:infoMessage
messagebox infoMessage
)
on btnAdd pressed do (fnAddItmsLst lstPipes pipeList)
on btnRemove pressed do (fnRemoveItmsLst lstPipes pipeList)
on btnGeneratePipes pressed do (
if selection.count >= 1 then
(
prevEnds = getEnds (selection as array)
newEnds = #()
for o in prevEnds do (
--Randomly choose a pipe based on list selection
items = if (lstPipes.selection) != undefined then (lstPipes.selection) as array else 1
idx = items[random 1 items.count]
_pipe = pipeList[idx]
maxOps.cloneNodes _pipe expandHierarchy:true cloneType:#copy actualNodeList:&refPipes newNodes:&newPipes
pipeCtrl = newPipes[1]
pipeCtrl.transform = copy (prerotatez o.transform rots[random 1 rots.count])
for p in newPipes where (checkStart p) do p.parent = o --link children
join newEnds (getEnds newPipes)
)
select newEnds
)else(
--Randomly choose a pipe based on list selection
items = if (lstPipes.selection) != undefined then (lstPipes.selection) as array else 1
idx = items[random 1 items.count]
_pipe = pipeList[idx]
maxOps.cloneNodes _pipe expandHierarchy:true cloneType:#copy actualNodeList:&refPipes newNodes:&newPipes
pipeCtrl = newPipes[1]
pipeCtrl.pos = [0,0,0]
pipeCtrl.transform = (prerotatez (matrix3 1) rots[random 1 rots.count])
select (getEnds newPipes)
)
)
)
createDialog rlPipesGenerator 220 210 style:#(#style_SysMenu, #style_ToolWindow)
if i would build anything using ‘blocks’ i do it by using containers. that will give me automatic updates and enabling of proxy display.
Making each pipe into a container? Seems like that would make it a bit harder to track the start and ends of the pipes though.
no difference. you can check selected container and use any object from its hierarchy to get a connection point.
collision detection… you really don’t need it. if you use ‘multiple of N’ block size you can setup the 3d grid, and mark it’s cells as taken every time when you generate a new piece. if cell on the way of growing is taken try to turn on free way or stop growing this branch (set some ‘ending’ piece for example).
Yeah I was thinking about adding an end cap piece to then help make sense of a pipe suddenly ending.
I’ll have to look into the container stuff as its new to me and I’ve never even looked at it before.
i think that the main goal of the pipe generator for you is to learn anything new. that’s why i throw you containers…