Home Technical Talk

Mel scripting help: moving a bunch of verts to a locator

polycounter lvl 16
Offline / Send Message
onionhead_o polycounter lvl 16
Is it possible to create a simple script to make all selected vertices to snap to closest locators. I'm still new to mel scripting. any help is appreciated.

Replies

  • onionhead_o
    Options
    Offline / Send Message
    onionhead_o polycounter lvl 16
    Forgot to include a image. my bad

    here it is

    idea.jpg

    what im trying to achieve is have all the selected vertices snap to nearby locators. Im assuming with xform or getAttr to retrieve the location of the locator and then test closest distance. But I have no idea how to do it with more then 2 objects.
  • passerby
    Options
    Offline / Send Message
    passerby polycounter lvl 12
    making a loop to snap to locaters per vert is pretty easy, the part im not sure about would be figuring out what locater is the closest the vertex.
  • Drachis
    Options
    Offline / Send Message
    Drachis polycounter lvl 9
    I think you could make it happen by setting up a loop that checks each vertex against all the locators and then moves that vertex to the closest locator. My MEL is a bit rusty at the moment so I'm not going to hash together pseudocode till I get home.
  • haiddasalami
    Options
    Offline / Send Message
    haiddasalami polycounter lvl 14
    Pseudo code would be
    locators = xform all locators
    for vert in selectedVertices
        vertloc = xform vert, world space
        for int i = 0; i < size of locator array; i++
            locatorLOC = xform locator world space
            distanceTEMP = distance between locator(using locatorLOC and vert (vertloc)
            //First run so store the first distance
            if (i == 0)
                distance = distanceTEMP
                locator = locator[i]
            if distanceTEMP < distance
                distance = distanceTEMP
                locator = locator[i]
        //Eventually you'll get the closest distance and the appropriate locator
        move vert to locator
    

    That should be the most straight forward method. I can try and write it up tomorrow in code if you're stuck on something.
  • Drachis
    Options
    Offline / Send Message
    Drachis polycounter lvl 9
    that looks pretty clean
  • onionhead_o
    Options
    Offline / Send Message
    onionhead_o polycounter lvl 16
    haiddasalami: thanks man, you're a saviour. couldn't find anything close to this on google at all. Kinda still trying to understand your pseudo code tho. Im stuck on i++. what does that do? sry for being noob at coding
  • haiddasalami
    Options
    Offline / Send Message
    haiddasalami polycounter lvl 14
    The i++ is a counter that increases so at the start its 0 and once it goes through one iteration of the loop it increases so we can iterate through an array. Hopefully I explained that well. Ill try and post some real code real soon. Also just noticed some errors I didnt catch like at the start you should be using the ls command to get all the locators.
  • PolyHertz
    Options
    Offline / Send Message
    PolyHertz polycount lvl 666
    It's also where C++ gets its name from ;)
  • marks
    Options
    Offline / Send Message
    marks greentooth
    Yeah thats what I was gonna suggest.

    By subtracting the vert position from the locator position, you get a vector. There should then be a length() function to determine the length of the vector. Loop that to find the shortest vector and that gives you the closest locator to the vert. Rinse and repeat.
  • haiddasalami
    Options
    Offline / Send Message
    haiddasalami polycounter lvl 14
    Python:
    import maya.cmds as cmds
    import math
    import sys
    
    def closestVerticeToLoc():
        locators = cmds.listRelatives( cmds.ls(type="locator"), parent=True)
        
        try:
            selection = cmds.filterExpand(selectionMask =31)
            if len(selection) > 0:
                for vertice in selection:
                    vertWS = cmds.xform(vertice, query=True, ws = True, t=True)
                    for i in range(len(locators)):
                        locatorWS = cmds.xform(locators[i], query=True, ws=True, t=True)
                        distanceTEMP = distanceFUNC(vertWS[0],vertWS[1],vertWS[2],locatorWS[0],locatorWS[1],locatorWS[2])
                
                        if i == 0:
                            distance = distanceTEMP
                            closestLocator = locators[i] 
                
                        if distanceTEMP < distance: 
                            distance = distanceTEMP
                            closestLocator = locators[i]
        
                closestLocatorWS = cmds.xform(closestLocator, query=True, ws=True, t=True)
                cmds.move(closestLocatorWS[0],closestLocatorWS[1],closestLocatorWS[2],vertice, absolute=True)
        except:
            print "Please select vertices"
            
    def distanceFUNC(x1,y1,z1, x2, y2, z2):
        return math.sqrt( (x1-x2) * (x1-x2) + (y1 - y2) * (y1 - y2) + (z1-z2) * (z1-z2))
        
    closestVerticeToLoc()
    
    

    To launch, just copy and paste into a python tab in the script editor window highlight all and drag to your shelf as button. Or you can save as closestVerticeToLoc.py put into Maya scripts and run using

    import closestVerticeToLoc
    reload(closestVerticeToLoc)

    MEL:
    global proc closestVerticeToLoc()
    {
        string $selection[] = `filterExpand -sm 31`;
        if (size($selection)<1){
            warning("Nothing is selected");
        }
        select (listRelatives("-parent",`ls -type "locator"`));
        string $locators[] = `ls -selection`;
        select $selection;
        float $distance;
        string $closestLocator;
        for ($vertice in $selection) {
            vector $vertWS = `xform -query -worldSpace -translation $vertice`;
            int $i;
            for ($i=0; $i<`size($locators)`; $i++)
            {
               vector $locatorWS = `xform -query -worldSpace -translation $locators[$i]`;
               float $distanceTEMP = distanceFunc($vertWS.x,$vertWS.y,$vertWS.z,$locatorWS.x,$locatorWS.y,$locatorWS.z);
               if ($i == 0){
                   $distance = $distanceTEMP;
                   $closestLocator = $locators[$i];
               }
               
               if ($distanceTEMP < $distance){
                   $distance = $distanceTEMP;
                   $closestLocator = $locators[$i];
               } 
            }
            vector $closestLocatorWS = `xform -query -worldSpace -translation $closestLocator`;
            move -absolute ($closestLocatorWS.x) ($closestLocatorWS.y) ($closestLocatorWS.z) $vertice;
        } 
        
    }
    
    global proc float distanceFunc(float $x1, float $y1,float $z1,float $x2,float $y2,float $z2){
        return sqrt( ($x1-$x2) * ($x1-$x2) + ($y1 - $y2) * ($y1 - $y2) + ($z1-$z2) * ($z1-$z2) );
    }
    
    closestVerticeToLoc();
    

    Probably comment this later for better understanding. Also feel free to take this and expand on it. For example right now there is no checking if there are locators or not.
  • Denny
    Options
    Offline / Send Message
    Denny polycounter lvl 14
    I suggest using

    //Mel
    string $vertices[] = `filterExpand -sm 31`;

    for querying the selected vertices instead. You never know if the user might select something else which should not be selected for the script. filterExpand 31 ensures you get only selected vertices, see the docs for which number is used for other components.
  • haiddasalami
    Options
    Offline / Send Message
    haiddasalami polycounter lvl 14
    hey Denny, yeah I caught that while converting the code to mel. Anywho updated the post with both mel and python.
  • onionhead_o
    Options
    Offline / Send Message
    onionhead_o polycounter lvl 16
    Thanks a lot for everybodys help on this. The script works perfectly.

    But now i run into another problem. First I must explain the purpose for requesting this script.


    This is part of the main Script Im trying to write which is Quad fill (imitating Quad-cap max plugin by obliviboy). So far Ive been sampling many mel scripts to make this work since, I am a noob at mel. I know this is a complicated thing to do for a beginner.

    Heres my Idea or concept for making the Quad Fill work. Feel free to comment and critique:

    1)Get edge selection of the hole that needs to be filled
    2)Create locators to store the xyz location of the vertices on the border. Which will later be used to snap the quad plane back to Main mesh.

    This method might be too inefficient, but its the only way I can think of. Since I have no idea how to create a script that knows how to divide the Ngon into quads.

    3)Test if the edges are even. reason being that solving quads need even edges.
    global proc testEven () 
    {
    	int $edgeNum = `polyEvaluate -edge`;
    
    	if ($edgeNum % 2 == 0)
    	{
    	checkEqualedge;
    	}
    

    4)checkEqualedge is to test if edges can be evenly distributed on 4 sides. Mainly is to store the Subdivisions of the width and height required to create the quad plane.
    global proc checkEqualedge ()
    {
    	
    	int $fmodNum =`fmod($edgeNum,4)`
    	int $wholeNum =`$edgeNum[0] / 4`
    	int $remainder;
    	float $roundNum;`floor($edgeNum/4)`
    	
    	
    	if ($fmodNum == 0)
    	{
    		$SubDH = $WholeNum //SubDH is Subdivision Height
    		$SubDW = $WholeNum ////SubDH is Subdivision Width
    	}
    
    	else
    	{
    		$SubDH = $roundNum + 1
    		$SubDW = $roundNum
    	}
    }
    
    

    5) Get the rotation axis of the edge selection.

    The following code I found off of this site http://xyz2.net/mel/mel.005.htm
    Not sure how to get this to work. always run into invalid syntax#
    proc vector translatePolyInfoNormal( string $pin )
    {
      vector $normal;
      float $x;
      float $y;
      float $z;
    
      string $tokens[];
      int $numTokens = `tokenize $pin " " $tokens`;
    
      // Make sure we're looking at polyInfo data:
      if ( ( $numTokens > 3 ) && ( $tokens[0] == "FACE_NORMAL" ) )
      {
        // Maya performs data-type conversion here.
        $x = ($tokens[$numTokens-3]);
        $y = ($tokens[$numTokens-2]);
        $z = ($tokens[$numTokens-1]);
    
        $normal = << $x, $y, $z >>;
    
        // Normalize it.
        $normal = `unit $normal`;
      }
    
      // Return it.
      return $normal;
    }
    
    string $FaceInfo[0] = `polyInfo -fn pPlane6.f[0]`;
    
    vector $FaceNormal = translatePolyInfoNormal( $FaceInfo[0]);
    

    I need this code to get the values neccessary to move the Quad plane back to the original mesh that needed to be capped.

    6)snap the border of the Quad plane to the Main Mesh with closestVerticeToLoc created by haiddasalami

    7)Combine both Meshs and call it a day.

    Hope this is not too confusing or long to read.
  • TeZzy
    Options
    Offline / Send Message
    TeZzy polycounter lvl 12
    Hey onionhead, any progress on the quad cap script that you are working on. Been looking for something like this for a while.
  • onionhead_o
    Options
    Offline / Send Message
    onionhead_o polycounter lvl 16
    ive been stuck on some of the coding unfortunately.

    I think someone beat me to quad script.

    (Video Demo) wait till the asian ads finish..
    http://v.youku.com/v_show/id_XMTc0NjE3OTM2.html?f=4488599

    Script page
    http://www.creativecrash.com/maya/downloads/scripts-plugins/modeling/c/zhcg_polytools-for-2012-2013---2
  • Saf
    Options
    Offline / Send Message
    Saf polycounter lvl 11
    Please finish Quad fill script. I use ZhCG_PolyTools only because of this. But in Maya 2014, Python 2.7.3 is not compatible with ZhCG_PolyTools.
  • onionhead_o
    Options
    Offline / Send Message
    onionhead_o polycounter lvl 16
    i appreciate your interest and support for this script. But i cannot guarantee that the finish version will work with maya 2014, as I dont have it yet.
  • passerby
    Options
    Offline / Send Message
    passerby polycounter lvl 12
    most code built on python 2.6.4 which is what previous versions of maya uses, will work on 2.7.3 which contains mostly minar changes to python Saf.

    it is 2.x to 3.x that you got to watch out for in python, which is why a lot of people never moved away from 2.x.

    Also if the upgrade to 2014 breaks parts of your workflow, why upgrade right away?
  • Saf
    Options
    Offline / Send Message
    Saf polycounter lvl 11
    Yes, most scripts will work. But only if they are not the compiled.
    I do not upgrade to 2014 version, just looked trial.
    Quad fill a very cool thing. I just thought it would be nice to have a clean Quad fill script, not compiled ZhCG version.

    Here the idea may come in handy:

    quad_fill_001.png
  • passerby
    Options
    Offline / Send Message
    passerby polycounter lvl 12
    ah he was being stupid and distributed as pyc? instead of the py files?
  • Saf
  • rebb
    Options
    Offline / Send Message
    rebb polycounter lvl 17
    Did you contact the original author and ask him if he's ok with you decompiling his code and making it publically available ?

    I doubt people release .pyc plugins out of "stupidity", but because they are trying to protect their code ( which PYC isn't great for, as this example shows ).
  • Saf
    Options
    Offline / Send Message
    Saf polycounter lvl 11
    yes tried many times, but the author is gone from 2011
Sign In or Register to comment.