[Closed] Scripting an Edit poly Psuedo Booleen
Let me begin by saying I am reading the docs on this one and am just taking a break to ask if there is anyone who could point me in the right direction. Possibly save me some time if they know a faster easier way.
Now on to the issue:
My team is creating alot of nav meshes for AI and I’ve began making tools to help them in production. Each are added to a tool bar I have and now I’m looking into a script I can place under a button…and select something like a building or house and the navmesh, or terrain, beneath it and have it cut the shape from the terrain. The script should leave the building intact, but really just use the edge.
Slow method on this is to select the edges on the building make it a shape shape merge it into the scene and delete the center poly…toooooo long.
So does any one have any idea exactly what Im needing form this to make it work on two object?
I’m just trying to get my head around what I can do in max script on an edge or vertice level.
I know I havent given much detail on the scripting I have done on this so far, but overall I’m looking into simple methods like creating arrays from selected edges. But I would feel better if I knew I was heading in the right direction and that edit poly and maxscript can handle this?
Hi, I’m not exactly sure what you need to do…but using max script you have pretty much complete control over the mesh, or mesh creation.
Perhaps getting all the verts from the edges at the bottom of your building as an array, then looping through each one, raycasting in the -z direction to find where they interupt the terrain and cutting a vert into the terrain mesh at that point might work
If you start from an outline, that seems feasible.
You transform your outline into a series of vertices. In the right order of course.
You calculate the position of each point on the ground. There are commands like intersectRay for that.
You select the faces under the building with his bounding box.
For each couple of points, you create an new edge with a command like polyOp.cutFace
You select the face inside of the initial outline. That could be more difficult.
You could calculate 2 distances:
- the distance between the center of the outline and the center of the face
- the distance between the center of the outline and the point of intersection with the outline
If the first distance is lower than the second then the face will be inside the outline. (It does work only with a convex outline)
Next you delete faces.
EDIT: sorry Moosley I wrote my text at the same time as you
i’m glad to hear the gathering of verts and using ray intersection “I deas…this is the direction I was trying to convey Im heading in.
But I probably wasnt too clear in my description.
I’ll try and wrap up this portion of the code, then I foresee my next issue will be to get the new section Ive made in the mesh to delete.
Pretty Pixel:
I see you covered this in your description, but Im not too familiar with how I will accomplish getting the distance to determine what polys should be deleted. I’ll need to look at that more in depth…
thanks to all of you.
After reflexion, it seems that It is not necessary to calculate the intersection with surface.
The tool polyOp.cutFace seems already to do it.
polyOp.cutFace <Poly poly> <int face> <point3 start> <point3 destination> \ <point3 projdir>
I did not test it but <point3 projdir> seems to be a projection vector.
I suppose if you use [0,0,-1] that create automatically the vertical intersection with the surface (?)
I have just created a kind of ‘shape merge’ function
-
create a plane named Plane01
-
convert it to poly
-
create a circle named Circle01
-
adjust interpolation to 2 or 3
-
move the circle completely inside the plane
-
convert it to poly
-
select all edges of the circle
-
evaluate the script
struct vectorizedOutline
(
edges=#(),
verts=#(),
vertsPos=#()
)
fn getFirstItem theBitArray = (for i in theBitArray do return i)
fn vectorizeEdgeList obj theEdges =
(
edgesString=#()
vertsString=#()
vertsPosString=#()
if theEdges.numberset!=0 do (
theEdgesMem=copy theEdges
currentEdge=getFirstItem theEdges
currentVerts=polyOp.getEdgeVerts obj currentEdge
currentVert=currentVerts[1]
nextVert=currentVerts[2]
append vertsString currentVert
append vertsPosString (polyOp.getVert obj currentVert)
while theEdges.numberset!=0 do (
theEdges[currentEdge]=false
append edgesString currentEdge
append vertsString nextVert
append vertsPosString (polyOp.getVert obj nextVert)
edgeList=(polyOp.getEdgesUsingVert obj #{nextVert})*theEdgesMem
edgeList[currentEdge]=false
if edgeList.numberset==0 do exit
currentEdge=getFirstItem edgeList
currentVerts=polyOp.getEdgeVerts obj currentEdge
if currentVerts[1]==nextVert
then ( currentVert=currentVerts[1] ; nextVert=currentVerts[2] )
else ( currentVert=currentVerts[2] ; nextVert=currentVerts[1] )
)
)
vectorizedOutline edges:edgesString verts:vertsString vertsPos:vertsPosString
)--fn
fn cutOutline obj posArray projVector =
(
outlineEdges=#{}
if posArray.count!=0 do (
polyOp.setEdgeSelection obj #{}
theCenter=[0,0,0]
for pos in posArray do theCenter+=pos
theCenter/=posArray.count
obj2=snapshot obj
retArray=intersectRayEx obj2 (ray theCenter projVector)
if retArray==undefined do ( retArray=intersectRayEx obj2 (ray theCenter -projVector) )
if retArray!=undefined do (
face=retArray[2]
theFaceVerts=(meshop.getVertsUsingFace obj2 #{face})as array
firstVert=theFaceVerts[1]
delete obj2
newVert=firstVert
for pos in posArray do ( newVert=polyOp.cutVert obj newVert pos projVector )
outlineEdges=polyOp.getEdgeSelection obj
theFirstEdge=getFirstItem outlineEdges
outlineEdges[theFirstEdge]=false
polyOp.setEdgeSelection obj outlineEdges
)
)
outlineEdges
)--fn
objShape=$Circle01
objGround=$Plane01
theOutline=vectorizeEdgeList objShape (polyOp.getEdgeSelection objShape)
outlineEdges=cutOutline objGround theOutline.vertsPos [0,0,-1]
max views redraw
The edges selection is returned by the function.
Now The only thing which remains to be made is to select the faces inside the outline…
Here a version which removes the inelegant edges.
fn cutOutline obj posArray projVector =
(
outlineEdges=#{}
if posArray.count>1 do (
badNewEdges=#{}
polyOp.setEdgeSelection obj #{}
theCenter=[0,0,0]
for pos in posArray do theCenter+=pos
theCenter/=posArray.count
obj2=snapshot obj
retArray=intersectRayEx obj2 (ray theCenter projVector)
if retArray==undefined do ( retArray=intersectRayEx obj2 (ray theCenter -projVector) )
if retArray!=undefined
then (
face=retArray[2]
theFaceVerts=(meshop.getVertsUsingFace obj2 #{face})as array
newVert=theFaceVerts[1]
delete obj2
oldEdgesBitarray=#{1..polyOp.getNumEdges obj}
newVert=polyOp.cutVert obj newVert posArray[1] projVector
badNewEdges+=polyOp.getEdgeSelection obj
polyOp.setEdgeSelection obj #{}
for i=2 to posArray.count do (
pos=posArray[i]
newVert=polyOp.cutVert obj newVert pos projVector
thisNewEdges=polyOp.getEdgesUsingVert obj #{newVert}
if (thisNewEdges*oldEdgesBitarray).numberset==0 do badNewEdges+=thisNewEdges
outlineEdges+=polyOp.getEdgeSelection obj
polyOp.setEdgeSelection obj #{}
)
bit30=bit.set 0 30 true
polyOp.setEdgeFlags obj #{1..polyOp.getNumEdges obj} 0 mask:bit30
polyOp.setEdgeFlags obj outlineEdges bit30
badNewEdges-=outlineEdges
polyOp.setEdgeSelection obj badNewEdges
obj.Remove selLevel:#Edge
outlineEdges=polyOp.getEdgesByFlag obj bit30
polyOp.setEdgeSelection obj outlineEdges
)
else delete obj2
)
outlineEdges
)--fn
I might be thinking too simplisticly, but here is what I would do:
*Create a large plane with, say, 20×20 segments.
*Add a Noise Modifier on top and adjust to get some funny terrain-like mesh
*Create a Box (or any other closed volume representing the building) and place on the mesh, intersecting enough at the base.
Now open the MAXscript Listener and type in:
$Plane01 – $Box01
SURPRISE!
Instant boolean subtraction. The plane should now have a hole where the box penetrated.
This (as all booleans) might not work in all 100% of cases, but it is much faster than scripting own cutting operations. Plus, the higher the mesh density, the better the result.
Note that the original plane was converted to an Editable Mesh. You might want to create a clone of the original terrain node, perform all booleans on it, then replace the mesh of the original node with the TriMesh of the boolean result.
The only thing left is to create the projection volume of your buildings. If the bases of your objects are easily traceable, you can create a shape, extrude to intersect the terrain, boolean.
Hope this gives you an alternative approach to your problem…
Cheers,
Bobo
I am surprised.
I am happy :o)
yes nice trick
I am also interested by the cutting of a form on the surface of a poly. (for other reasons)
The boolean meshes work really well. It is a pity that sometimes the faces are not deleted.
That is a little frustrating because the method is so easy.
Do you know why the faces are not always deleted ?
Are there a way to prevent that ?
I have another question: Are there methods to select the faces inside an outline ?