Notifications
Clear all
[Closed] Holey Tube
Jun 27, 2013 5:13 pm
This a geo plugin I made for fun. Feel free to check it out. It’s free and I’d love to see what ways we could improve upon this and features we could possibly add. It was a fun one to make.
Still in its rough draft stages.
--c/pi/2
plugin simpleObject HoleyTube
name:"HoleyTube"
category:"Standard Primitives"
classID:#(0x512e8ff9, 0x57aefc78)
(
parameters main rollout:rltParams
(
holeRadius type:#worldUnits default:3 ui:uiHoleRadius
holesPerSection type:#integer default:1 ui:uiHolesPerSection
holeSegs type:#integer default:8
XPadding type:#worldUnits default:6 ui:uiXPadding
YPadding type:#worldUnits default:6 ui:uiYPadding
XSegs type:#integer default:2 ui:uiXSegs
--YSegs type:#integer default:0 ui:uiYSegs
numHoles type:#integer default:8 ui:uiNumHoles
numRings type:#integer default:2 ui:uiNumRings
ringOffset type:#integer default:0 ui:uiRingOffset
)
rollout rltParams "Parameters"
(
group "Section Settings:"
(
spinner uiHoleRadius "Hole Radius:" range:[.001,1e9,0] type:#worldUnits
spinner uiHolesPerSection "Holes/Section:" range:[1,1e9,1] type:#integer
spinner uiXPadding "X Padding:" range:[0,1e9,0] type:#worldunits offset:[0,6]
spinner uiYPadding "Y Padding:" range:[0,1e9,0] type:#worldunits
spinner uiXSegs "X Segments:" range:[0,1e9,0] type:#integer
--spinner uiYSegs "Y Segments:" range:[0,1e9,0] type:#integer
)
group "Tube Settings:"
(
spinner uiNumHoles "Holes/Ring:" range:[1,1e9,1] type:#integer
spinner uiNumRings "N° of Rings:" range:[1,1e9,1] type:#integer offset:[0,6]
spinner uiRingOffset "Ring Offset:" range:[0,1e9,0] type:#integer
)
fn checkRadius =
(
if uiHoleRadius.value > uiXPadding.value do uiXPadding.value = uiHoleRadius.value
if uiHoleRadius.value > uiYPadding.value do uiYPadding.value = uiHoleRadius.value
)
fn checkPadding =
(
if uiXPadding.value < uiHoleRadius.value do uiHoleRadius.value = uiXPadding.value
if uiYPadding.value < uiHoleRadius.value do uiHoleRadius.value = uiYPadding.value
)
on uiHoleRadius changed val do checkRadius()
on uiYPadding changed val do checkPadding()
on uiXPadding changed val do checkPadding()
)
fn FlipNodeNormals 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
)
fn BendPoint p angle:0.0 height:0.0 direction:0.0 =
(
if angle != 0.0 then
(
factor = angle/height
radius = (180.0/pi/factor)
dirMatrix = rotateXMatrix -direction
value = [0,0,-radius]*dirMatrix
rotateMatrix = rotateYMatrix
tm = translate ((rotateMatrix (factor*p)[1]) * dirMatrix) value
p[1] = 0
p = (p - value)*(inverse dirMatrix)*tm
return p
)else(
return p
)
)
fn transformVerts mesh offset:0.0 angle:0.0 =
(
for v = 1 to mesh.numVerts do
(
vPos = meshop.getVert mesh v
tm = transmatrix (vPos + offset)
vPos = (rotateY tm angle).pos
meshop.setVert mesh #{v} vPos
)
mesh
)
fn genHoles =
(
local tmpVerts = #()
local holeAngle = 360.0 / holeSegs
for h = 0 to holesPerSection-1 do
(
for c = 1 to holeSegs do
(
local x = holeRadius * cos((c-1) * -holeAngle)
local y = holeRadius * sin((c-1) * -holeAngle)
tm = rotateZ (transmatrix [x,y,0]) -90 --used to offset so frist vert is in the corner
vPos = (tm * (matrix3 1)).pos
offset = h * (XPadding * (2)) + XPadding
vPos+= [offset,YPadding,0]--offset to make it start at [0,0,0]
append tmpVerts vPos
)
/* Create Frame Points */
--if its the 1st hole then run this for the frame creation
if h == 0 then
(
for c = 1 to holeSegs do
(
vPos = case c of
(
1: [0,-YPadding,0]
2: [-XPadding,-YPadding,0]
3: [-XPadding,0,0]
4: [-XPadding,YPadding,0]
5: [0,YPadding,0]
6: [XPadding,YPadding,0]
7: [XPadding,0,0]
8: [XPadding,-YPadding,0]
)
vPos+= [XPadding,YPadding,0] --offset to make it start at [0,0,0]
append tmpVerts vPos
)
)else(
for c = 1 to holeSegs do
(
offset = h * (XPadding * (2)) + XPadding
vPos = case c of
(
1: [0,-YPadding,0]
2: [-XPadding,-YPadding,0]
3: [-XPadding,0,0]
4: [-XPadding,YPadding,0]
5: [0,YPadding,0]
6: [XPadding,YPadding,0]
7: [XPadding,0,0]
8: [XPadding,-YPadding,0]
)
vPos+= [offset,YPadding,0] --offset to make it start at [0,0,0]
if c != 2 AND c != 3 AND c != 4 do
(
append tmpVerts vPos
)
)
)
)
/* Create Side Seg Points */
for i = 1 to XSegs do
(
local xStartPos = (holesPerSection*2)*XPadding
local xOffset = xStartPos + (XPadding*i)
for s = 0 to 2 do --3 verts for each seg
(
offset = YPadding*s
vPos = [xOffset,(-offset+(YPadding*2)),0]
append tmpVerts vPos
)
)
/* Offset for radius */
partLength = (XPadding * XSegs) + (holesPerSection * 2 * XPadding)
circum = ((XPadding * XSegs) + (holesPerSection * 2 * XPadding))*numHoles
radius = circum/pi/2
ang = 360.0/numHoles
tmpVerts = for v in tmpVerts collect (
v = BendPoint v angle:ang height:partLength
v += [0,0,radius] --offset for radius
v
)
return tmpVerts
)
fn genMesh =
(
/*Set Vertices*/
local verticesArr = #()
/* Create Hole Points */
join verticesArr (genHoles())
/* Set Faces */
local facesArr = #()
/*Set Hole Faces for linear holes*/
local loops = 8 --number of loops to make section (usually half of the ver count since each poly is made of 2 tris
for s = 0 to holesPerSection-1 do
(
start = if s > 0 then (16+((s-1)*13)+1) else 1 --starting vert
end = if s > 0 then (start +7) else s*(loops*2)+loops --end vert
check = 1
for v = start to end do --each disc
(
if v < end then --less then
(
if s != 0 then
(
case check of
(
1: (append facesArr [v+1, v, v+loops]; append facesArr [v+loops , v+loops+1-10 , v+1 ])
2: (append facesArr[v+1, v, v+loops-10]; append facesArr [v+loops-10 , v+loops+1-12 , v+1 ])
3: (append facesArr[v+1, v, v+loops-12]; append facesArr [v+loops-12 , v+loops+1-14 , v+1 ])
4: (append facesArr[v+1, v, v+loops-14]; append facesArr [v+loops-14 , v+loops+1-3 , v+1 ])
5: (append facesArr[v+1, v, v+loops-3]; append facesArr [v+loops-3 , v+loops+1-3 , v+1 ])
6: (append facesArr[v+1, v, v+loops-3]; append facesArr [v+loops-3 , v+loops+1-3 , v+1 ])
7: (append facesArr[v+1, v, v+loops-3]; append facesArr [v+loops-3 , v+loops+1-3 , v+1 ])
)
)
else
(
append facesArr [v+1, v, v+loops]
append facesArr [v+loops , v+loops+1 , v+1 ]
)
)else(
--makes a complete loop like a disc
if s != 0 then
(
append facesArr [ 1+v-loops , v , v+loops-3]
append facesArr [v+loops-3 , v+1, 1+v-loops ]
)else(
append facesArr [ 1+v-loops , v , v+loops]
append facesArr [v+loops , v+1, 1+v-loops ]
)
)
check += 1
)
format "
"
)
/* X-PADDING FACES */
if XSegs != 0 do
(
local sVert = 16 + (holesPerSection-1)*(16-3)-3+1 --first vert which will be used to create x-pad faces
local eVert = sVert + (XSegs)*3-1 --total vert count including the verts used to create x-pad faces - minus last set
local endCount = sVert+2 --segs of the framed circle
local count = 3
for l = sVert to eVert do
(
if l < endCount then --less then
(
--format "% - %
" [l+1, l, l+count] [l+count , l+count+1 , l+1 ]
append facesArr [l+1, l, l+count]
append facesArr [l+count , l+count+1 , l+1 ]
)else(
--only needed if planning on connecting start/end edges like a tube
endCount += count --reset strip of verts
)
)
)
/*Set Mesh*/
mainMesh = setMesh mesh verts:verticesArr faces:facesArr
triCount = (holesPerSection*16)+(XSegs*2*2) -- total tri count
for f in #{1..triCount} do setEdgeVis mesh f 3 false
/*Dupe Meshes to make complete ring*/
local meshes = #()
for i = 1 to (numHoles-1) do
(
local newMesh = copy mesh
local angleOffset = (360.0/numHoles)*i
newMesh = transformVerts newMesh angle:angleOffset
append meshes newMesh
)
/*Attach Duped Meshes*/
for m in meshes do
(
meshop.attach mesh m
free m
)
free meshes
/*Dupe Meshes to make complete ring*/
local ringMeshes = #()
for i = 1 to (numRings-1) do
(
local newMesh = copy mesh
local twistOffset = ( 360.0 / (numHoles * (holesPerSection*2 + XSegs )) ) * i
local posOffset = (YPadding*2)*i
newMesh = transformVerts newMesh offset:[0,posOffset,0] angle:(twistOffset*ringOffset)
append ringMeshes newMesh
)
/*Attach Duped Meshes*/
for m in ringMeshes do
(
meshop.attach mesh m
free m
)
free ringMeshes
/*Weld all the clones*/
meshop.weldVertsByThreshold mesh #{1..(mesh.numverts)} (units.decodeValue ".0001cm")
/*Smooth Normals*/
meshop.autoSmooth mesh #all 360.0
/*Flip Normals*/
FlipNodeNormals mesh
update mesh
)
on buildMesh do (genMesh())
tool create
(
on mousePoint click do case click of
(
1: (numHoles = 4; coordSys grid (nodeTM.translation = first_pos = gridPoint))
2: #stop
)
on mouseMove click do case click of
(
2: (
numHoles = amax (abs gridDist.x) (abs gridDist.y)
if altKey do
(
nodeTM.translation = [0,0,0]
)
)
)
)
)
-- delete objects
-- clearlistener()
-- m = HoleyTube()
-- m.vertexticks = true
-- select m
-- for o in selection do
-- (
-- convertTo o editable_poly
-- for v = 1 to o.numverts do
-- (
-- vPos = polyop.getVert o v
-- t = text size:2.0 pos:vPos text:(v as string) wirecolor:yellow
-- )
-- )
1 Reply
Jun 27, 2013 5:13 pm
Great stuff.
I get an error in 3dsmax 2014×64. My System Unit Setup is set to Meters.
Maxscript Scripted Plugin Handler Exception…
– Runtime error: Unable to decode value: “.0001cm”
/*Weld all the clones*/
meshop.weldVertsByThreshold mesh #{1..(mesh.numverts)} (units.decodeValue ".0001cm")