Announcements

Starting in December, we will archive content from the community that is 10 years and older. This FAQ provides more information.

Making sure faces do not extrude into one another

Anonymous

Making sure faces do not extrude into one another

Anonymous
Not applicable

I'm working on a greebling script as my first attempt at writing a complex Python script for Maya. However, I have an issue where faces extrude into other pieces of geometry and I'm not sure how to remedy it. I was thinking locators could be used but I'm not sure how efficient that would be. I've been testing it using a cube scaled to 12 in XYZ, with 3 subdivisions in width, height and depth. Here's the code:

import maya.cmds as cmds
import math
import random as rand

terrainPlane = cmds.ls(sl = True, o = True) [0]
cycles = 1


def greeble(terrainPlane,cycles):
    print ('Cycle ' + str(cycles))
    facesNo = cmds.ls('{}.f[:]'.format(terrainPlane), fl=True)
    facesTotalNo = len(facesNo)
    print ('Total Faces: ' + str(facesTotalNo))
        
    cmds.select(clear = True)
        
    
    greebleRange =(facesTotalNo/(cycles *2))
    print ('Greeble Range: ' + str(greebleRange))

    for i in range (0,greebleRange):
        randomFace = rand.randint(0,facesTotalNo)
        print ('Random Face ' + str(i) + ':' + str(randomFace) + ' of ' + str(greebleRange))
        cmds.select('{}.f[{}]'.format(terrainPlane,randomFace),add = True)
        cmds.filterExpand(ex = True, sm = 34)
        print ('Greeble Range: ' + str(greebleRange))
        
        tkMultiplier = ((greebleRange/(10*cycles))*1+(4*(cycles-1)))
        print ('tkMultiplier: ' + str(tkMultiplier))
        
        tkUpper = greebleRange/(2*cycles)
        print ('tkUpper: ' + str(tkUpper))
        
        tkVal = rand.uniform(0,tkUpper/tkMultiplier)
        print ('tkVal: ' + str(tkVal))
        
        cmds.polyExtrudeFacet(tk = tkVal,keepFacesTogether = True,d = 1)
        cmds.scale(scaleXYZ = (rand.uniform(0.6,10.5)))
        cmds.select(clear = True)
        
    cmds.select(clear = True)
    cmds.select(terrainPlane)
    cmds.polySubdivideFacet(divisions = 1)
    cycles = cycles + 1
    
for i in range(0,2): 
    greeble(terrainPlane,cycles)    

Apologies if the code is a bit rough, I've been trying to work a proof of concept version before refining the full script.

 

0 Likes
Reply
Accepted solutions (1)
735 Views
6 Replies
Replies (6)

mcw0
Advisor
Advisor

When you say "faces extrude into other pieces of geometry", I'm assuming you have more than 1 mesh.  And the penetration issue is not with the same piece of geometry...as in penetrating itself.  In this case, you can check how close one mesh is to another with the "nearestPointOnMesh" node.  I prefer this node to Maya's "closestPointOnMesh" as I've had wrong results.  

 

Use your extrusion vector, whether it's the normal or user specific, and determine how far along that vector you are to another mesh.  Then only extrude that distance.

0 Likes

Anonymous
Not applicable

I've been doing it on one mesh. As it randomly selects faces and polyExtrude thickness values, some of the extruded faces that aren't outward-facing extend into others on the same mesh. I'm just not sure how to limit the thickness values for each extrusion to stop things from clipping into one another. Would nearestPointOnMesh still be a solution when used on the same mesh?

mcw0
Advisor
Advisor

nearestPointOnMesh will still work for a single mesh.  But you will have to track the normal so you don't get your starting point.  Because your starting point will be the nearest point.  You don't want that.  You want to project along that starting point's normal or whatever vector you are extruding along to look for collisions.

0 Likes

Anonymous
Not applicable

That makes sense to me. How would I go about checking along the extrusion vector for the collisions? 

0 Likes

mcw0
Advisor
Advisor
Accepted solution

First, decide on an increment by which to advance along the vector.  For example 0.1.  And let's say that our starting point is 0, 0, 0 and our vector is <<1,0,0>> for simplicity's sake.  Now, you also have to set a maximal distance as you don't want to go to infinity if there is no collision.

 

float $increment = 0.1;

vector $v = <<1,0,0>>;

float $pos[] = {0.0, 0.0, 0.0};

float $max = 5.0;

string $npm = "nearestPointOnMesh";

float $dist = 0.0;

int $count = 1;

while($dist< $max)

{

    vector $v1 = $v * $increment * $count;

    float $x = $v1.x;

    float $y = $v1.y;

    float $z = $v1.z;

    float $extrudePos[] = {($p[0]+$x), ($p[1]+$y), ($p[2]+$z)};

    setAttr -type double3 ($npm+".inPosition") $extrudePos[0]$extrudePos[1] $extrudePos[2];

    float $nearestPos[] = `getAttr ($npm+".position")`;

 

    //  GET DISTANCE BETWEEN EXTRUDED POSITION AND NEAREST POSITION

    //  GET DOT PRODUCT OF EXTRUDE VECTOR AND SURFACE VECTOR AT NEAREST POINT

    //  IF DOT IS NEGATIVE AND DIST IS ZERO, THEN YOU'VE FOUND YOUR SPOT

    

 

    $count++;

}

 

 

 

0 Likes

mcw0
Advisor
Advisor

Sorry, noticed an error.  It should be...

while( ($increment*$count) < $max )

And obviously, if you find your point, then you need an escape mechanism out of the while loop.

0 Likes