Deze zelfstudie is een inleiding tot het gebruik van externe MEL-bestanden en procedures, functies, loops en interactie met scripts in de Maya-werkruimte. We bespreken de basiscoderingspraktijken en stellen een handig geometrisch object samen dat erg moeilijk te maken is zonder scripting.
In deze zelfstudie maken we een extern scriptbestand met vier "procedures" - onafhankelijke scripts die bedoeld zijn om specifieke doelen te bereiken. De eerste procedure neemt een willekeurig aantal objecten geselecteerd in de Maya-viewport en maakt een geketende hiërarchie voor eenvoudige dubbele transformaties. Het tweede script zal geselecteerde objecten on-oud maken en de derde verplaatst de draaipunten van geselecteerde objecten naar de oorsprong van de wereldruimte. Met deze drie scripts kunt u gemakkelijk enkele interessante effecten creëren met meerdere objecten. De vierde procedure combineert alle eerste drie om een 'Fermat's Spiral' te maken, vergelijkbaar met de complexe werveling op zonnebloemkoppen..
Open Maya. Voor de duur van deze tutorial gebruik ik Maya 2010, maar dezelfde opdrachten zouden moeten werken voor de meeste versies van Maya. Begin met het maken van een kubus in het midden van het kijkvenster.
Ga naar 'Bewerken'> 'Dupliceer speciaal' en klik op het optievak om dit dialoogvenster te openen. Maak negen kopieën.
Ga naar 'Venster> Hypergraph-hiërarchie'. We moeten nu de kubussen samenvoegen om een "ketting" te maken. Klik hiervoor eerst op 'pCube2' en klik vervolgens op 'pCube1' en druk op 'p' op je toetsenbord. Dit ouders het eerste geselecteerde object (pCube2) naar de tweede geselecteerde (pCube1).
Ga door met dit proces (selecteer het kind, dan de ouder en vervolgens 'p' om ze samen te ketenen) voor elk van onze kubussen. Eenmaal voltooid, moet elk object in het midden van de hiërarchie één bovenliggende en één onderliggende kubus hebben en de algemene hiërarchie er als volgt uitzien:
Sluit het venster 'Hypergraph-hiërarchie'. Selecteer alle objecten door met een selectiekader over de kubussen in het midden van de viewport te slepen. Houd vervolgens alle blokken geselecteerd en verplaats ze en draai ze.
Omdat de transformaties van elke kubus nu relatief zijn ten opzichte van de kubus één stap hoger in de keten, kunt u met de resulterende dubbele transformatie de kubussen op een zeer unieke manier verplaatsen - kleine vertalingen worden snel grote wijzigingen.
Met alle nog geselecteerde kubussen, druk je op 'Shift-P' op je toetsenbord om de kubussen te de-parenteren. We hebben nu alle belangrijke stappen doorlopen die we met ons script willen automatiseren. Dus begin een nieuw Maya-bestand en open een teksteditor. Mijn persoonlijke favoriet is Notepad ++, dat zelfs een MEL-taalplug-in beschikbaar heeft. Voel je vrij om elke gewenste teksteditor te gebruiken, maar voor nu gebruik ik het goede oude Microsoft Kladblok. Notepad is eenvoudig, maar het klopt.
Ga je gang en sla je bestand op. Zorg er bij het opslaan van een MEL-document voor dat u "Alle bestanden" kiest onder "opslaan als type". Sla uw document op als een .mel-bestand in uw Maya-scripts-map. Ik gebruik EdW_DoubleTransform.mel als mijn bestandsnaam.
Om een procedure te maken, moet u vooraf een aantal dingen weten. Eerst moet u een "scope" definiëren voor de procedure. Scope bepaalt waar een procedure kan worden geopend vanuit. Een "lokaal" bereik betekent dat de code alleen toegankelijk is voor andere procedures binnen hetzelfde .mel-bestand. "Globaal" betekent dat de procedure beschikbaar is voor andere scriptbestanden en de gebruiker en ook in het geheugen is geladen. Over het algemeen gebruik ik veel wereldwijde procedures. Dit is niet de absoluut beste codeermethode, maar ik vind het leuk om mijn procedures beschikbaar te hebben voor meerdere scripts. Ten tweede moet u een naam kiezen voor uw procedure. Probeer in het algemeen iets unieks en beschrijvends te kiezen - als de procedure globaal is, wil je niet dat de naam in conflict komt met een andere procedure in een ander script. Ik gebruik meestal een soort initialen in de naam en omdat het script dat we schrijven 'DoubleTransform' heet, ga ik in dit geval met 'dt'. Op de meest eenvoudige manier is dit de procedure die we aan het bouwen zijn:
global proc dt_makeParentChain () // acties van het script;
Het eerste dat we met onze procedure doen, is een variabele definiëren die uiteindelijk een lijst met objectnamen zal bevatten. In MEL worden variabelen aangeduid met een dollarteken ($) vóór de naam van de variabele. Er zijn verschillende soorten gegevens die een variabele kan bevatten: tekenreeksen, gehele getallen die gehele getallen worden genoemd, decimale getallen met een drijvende komma, vectorwaarden, enzovoort. De syntaxis voor het declareren van een variabele is deze:
dataType $ variableName;
Voor nu maken we een lege stringvariabele:
string $ selectedObjects;
Als we willen, kunnen we ook gegevens aan de variabele in dezelfde regel code toewijzen. Dubbele aanhalingstekens worden gebruikt om tekenreeksen te definiëren.
string $ selectedObjects = "dit is een reeks tekst";
een enkelvoudig gelijkteken betekent "stel de variabele in op". Een dubbel-gelijkteken betekent "is gelijk aan" en wordt gebruikt bij het vergelijken van variabelen.
Om onze nieuwe variabele te testen, moeten we een afdrukopdracht toevoegen. Hiermee wordt een tekenreeks uitgevoerd naar de Scripteditor wanneer het script wordt uitgevoerd. In dit geval printen we gewoon de inhoud van de variabele '$ selectedObjects'.
print $ selectedObjects;
Voeg een opmerking toe aan uw nieuwe procedure. Ik heb de neiging om vóór elke procedure een opmerking toe te voegen, zodat ik ze later snel kan vinden. Sommige van mijn scripts hebben tientallen procedures en opmerkingen maken het debuggen en wijzigen van code veel eenvoudiger. De volledige code zou er nu als volgt uit moeten zien:
// Maak ouderketen algemeen proc dt_makeParentChain () string $ selectedObjects = "dit is een tekstregel"; print $ selectedObjects; ;
Sla het bestand op en ga terug naar Maya. Wanneer Maya voor het eerst opstart, scant het de map met scripts en laadt het een lijst met alle bestanden daar. Als u een script aan de map hebt toegevoegd terwijl Maya al open is, weet het systeem niet dat het bestand bestaat. In dit geval heb je twee opties, of herstart Maya, of je kunt de opdracht "rehash" gebruiken om Maya te dwingen die lijst met bestanden bij te werken. We gebruiken de tweede methode, dus ga naar 'Window> General Editors> Script Editor', typ het volgende:
rehash;
Druk nu op 'Ctrl-Enter' om de opdracht uit te voeren.
Om je script te testen, moet je het in Maya "initialiseren". De opdracht "opnieuw instellen" vertelt maya dat het bestand bestaat en de opdracht "source" vertelt Maya om het script in het geheugen te laden. Typ het volgende in de scripteditor:
bron EdW_DoubleTransform.mel;
Typ vervolgens de opdracht voor de procedure die we in het script hebben gemaakt:
dt_makeParentChain;
Dit is wat u in de scripteditor zou moeten krijgen na het uitvoeren van de procedure:
Nu we een werkende procedure hebben samengesteld, zoeken we de pseudocode uit voor wat we met die procedure willen doen in ons definitieve script:
Om een lijst te krijgen van de objecten die in het Maya-venster zijn geselecteerd, gebruikt u de lijstopdracht "ls". Lijst wordt meestal gebruikt met een vlag die de opdracht geeft om te grijpen naar wat momenteel is geselecteerd in de maya-viewport, -sl. Probeer enkele objecten in de maya-viewport te selecteren en typ de volledige opdracht (hieronder weergegeven) in de scripteditor, vergeet niet op 'Ctrl-Enter' te drukken om de opdracht uit te voeren.
ls -sl;
Het lijstcommando voert een aantal strings uit die de volledige lijst met geselecteerde objecten vertegenwoordigen. Om deze informatie nuttig voor ons te maken, moeten we het resultaat van de opdracht "lijst" naar een variabele schrijven. Om dit te doen, wikkelt u de lijstopdracht in vinkjes (Let op, het vinkje, ook wel een aanhalingsteken genoemd, bevindt zich meestal boven de tabtoets op het toetsenbord ... zorg ervoor dat u de enkele aanhalingstekens naast de Enter toets). Het omzetten van een commando in vinkjes vertaalt zich als "de uitvoer van". Ons commando zou er nu als volgt uit moeten zien:
string $ selectedObjects = 'ls -sl';
De variabele $ selectedObjects is een enkele reeks tekst. Wat we echt nodig hebben is iets dat een string-array wordt genoemd - een geordende lijst met strings die zich in een enkele variabele bevinden. Om van onze string een string-array te maken, gebruikt u vierkante haakjes bij het declareren van de variabele:
string $ selectedObjects [] = 'ls -sl';
Wanneer we nu naar de variabele verwijzen, kunnen we de hele array gebruiken:
$ selectedObjects // alle tekenreeksen in de array
... Of een individuele tekenreeks binnen de array, door een index te leveren - de positie van de tekenreeks die we in de array zelf willen hebben. De indexwaarden in MEL beginnen altijd bij nul, zoals hieronder weergegeven:
print $ selectedObjects [0]; // geeft de eerste string in de array terug print $ selectedObjects [2]; // retourneert de derde reeks in de array
We hebben ook een manier nodig om erachter te komen hoeveel objecten in de array zitten. U kunt de opdracht "size" gebruiken om dat te doen. Laten we een nieuwe variabele maken om deze informatie op te slaan. Een geheel getal wordt vertegenwoordigd door een geheel getal, dat altijd in MEL wordt aangeduid als een "int":
int $ numSelectedObjects = 'size ($ selectedObjects)';
Nu hebben we een manier nodig om elk object op te baseren op basis van zijn plaats in de array. Er zijn een aantal manieren om dit te doen, maar voor nu gebruiken we een standaard "voor" -lus. For-loops zijn gebruikelijk bij het programmeren als een manier om een actie een aantal keren uit te voeren. De syntaxis van een for-loop die tien keer loopt is deze:
voor (int $ i = 0; $ i < 9; $i++) //action to be done ;
De lusstructuur bestaat uit drie delen. $ i = 0 definieert een integer variabele, $ i
voor ($ i = 0; $ i < $numSelectedObjects; $i++) //action to be performed ;
We moeten nu een 'bovenliggende' opdracht gebruiken om de hiërarchieketen te maken. De syntaxis voor deze opdracht is als volgt:
ouder childObject parentObject;
Dus in ons geval zou het hoofdcommando zijn:
voor ($ i = 1; $ i < $numSelectedObjects; $i++) parent $selectedObjects[(i-1)] $selectedObjects[i]; ;
Met onze lus voltooid, moeten we nu het laatste object in de selectie deselecteren, met behulp van de opdracht "select" met de vlag "deselecteren". Om de index van het laatst geselecteerde object te berekenen, nemen we het totale aantal objecten, en dan, omdat de index van een array in Maya begint bij 0, 1 aftrekken.
selecteer -selecteer $ selectedObjects [($ numSelectedObjects - 1)];
En daarmee is onze eerste procedure nu voltooid:
// Maak ouderketen algemeen proc dt_makeParentChain () string $ selectedObjects [] = 'ls -sl'; int $ numSelectedObjects = 'size ($ selectedObjects)'; voor ($ i = 1; $ i < $numSelectedObjects; $i++) parent $selectedObjects[($i - 1)] $selectedObjects[$i]; ; select -deselect $selectedObjects[($numSelectedObjects - 1)]; ;
Maak onder 'dt_makeParentChain' een nieuwe procedure om de geselecteerde objecten niet meer te koppelen. De onderstaande code bevat de geselecteerde objecten voor de wereld, wat hetzelfde is als het onouderoud maken van de objecten.
global proc dt_unParentSelected () parent -w; ;
Onze derde procedure automatiseert het verplaatsen van het draaipunt van een object naar de oorsprong. Net als voorheen beginnen we met het opstellen van de procedure:
global proc dt_pivotToOrigin () // procedure-acties;
Vervolgens gebruiken we dezelfde techniek als in de eerste procedure om een lijst met geselecteerde objecten naar een variabele te schrijven:
string $ selectedObjects [] = 'ls -sl';
We moeten nu een lus toevoegen. Hoewel we dezelfde soort for-loop zouden kunnen gebruiken als in het eerste script, laten we in plaats daarvan een for-each lus gebruiken. Een "for-each" -lus is een gespecialiseerde versie van de for-lus die eenmaal wordt uitgevoerd voor elke waarde in een array. U kunt er ook een variabele schrijven die de waarde van de huidige index vertegenwoordigt. De syntaxis ziet er als volgt uit:
for ($ each in $ arrayVariable) // doe deze actie met $ each;
De variabele $ elke bevat de waarde van de huidige index van de array. Voor ons script is dit hoe de code eruit zou moeten zien:
for ($ thisObj in $ selectedObjects) // verplaats de spil van $ thisObj;
Deze zelfde techniek kan worden gebruikt om elke maya-opdracht voor een willekeurig aantal geselecteerde objecten te automatiseren.
Met de variabele $ thisObj kunnen we nu het object selecteren dat momenteel wordt bekeken door de lus:
selecteer -r $ thisObj;
Om het draaipunt naar de oorsprong te verplaatsen, kunnen we de opdracht "xform" gebruiken en de -rp (rotatePivot) en -sp (scalePivot) -vlaggen op 0 op de X-, Y- en Z-as terugzetten:
xform -ws -rp 0 0 0 -sp 0 0 0;
De belangrijkste onderdelen van het script zijn nu voltooid en uw code, die alle drie de procedures bevat, zou er als volgt uit moeten zien:
// Maak ouderketen algemeen proc dt_makeParentChain () string $ selectedObjects [] = 'ls -sl'; int $ numSelectedObjects = 'size ($ selectedObjects)'; voor ($ i = 1; $ i < $numSelectedObjects; $i++) parent $selectedObjects[($i - 1)] $selectedObjects[$i]; ; select -deselect $selectedObjects[($numSelectedObjects - 1)]; ; // Un-Parent Objects global proc dt_unParentSelected() parent -w; ; // Move Pivot to Origin global proc dt_pivotToOrigin() string $selectedObjects[] = 'ls -sl'; for($thisObj in $selectedObjects) select -r $thisObj; xform -ws -rp 0 0 0 -sp 0 0 0; ; ;
We gaan nu een vierde procedure maken die de vorige drie zal gebruiken om een interessante geometrische progressie te creëren genaamd "Fermat's Spiral", gebaseerd op de hoekrelatie van de Gulden Snede, phi. Het is een vorm die veel voorkomt in de natuur, en het volgt allerlei interessante geometrische regels. Laten we beginnen met het schrijven van de pseudocode:
Dus laten we om te beginnen een nieuw procedureoverzicht maken:
global proc dt_fermatSpiral ()
Nu gaan we een bol maken met 8 radiale en 8 hoogtedivisies en de resulterende transform- en vormknooppunten naar een stringarray schrijven zodat we ze kunnen volgen. De meeste opdrachten waarmee geometrie wordt gemaakt, voeren twee tekenreeksen uit: de naam van het transformatieknooppunt en de naam van het vormknooppunt. Voor het grootste deel wilt u werken met de transform-node-tekenreeks, die wordt opgeslagen in de index [0] in de array-array $ seedSphere die hieronder wordt gemaakt:
string $ seedSphere [] = 'polySphere -sx 8 -sy 8';
We gaan nu een lege tekenreeksreeksvariabele maken:
string $ allSpheres [];
Open vervolgens een for-lus die 1.000 keer wordt uitgevoerd:
voor ($ i = 1; $ i<1000; $i++)
We moeten nu onze nieuw gecreëerde bol dupliceren en de resulterende transform- en vormknooppunten naar een variabele schrijven:
string $ duplicatedSphere [] = 'duplicate';
Hier voegen we de naam van ons gedupliceerde transformatieknooppunt toe aan het einde van de array $ allSpheres. U kunt de opdracht "size" gebruiken om te bepalen hoeveel objecten al in de array zitten en het resultaat gebruiken als index voor onze nieuwe waarde.
$ allSpheres [size ($ allSpheres)] = $ duplicatedSphere [0];
Hier selecteren we alle gemaakte sferen en voeren we de eerder door ons gemaakte ouderketenopdracht uit:
selecteer -r $ allSpheres; dt_makeParentChain;
Na het parenting van de bollen samen, selecteren we ze opnieuw en verplaatsen ze alle .05 in X met de opdracht "move":
selecteer -r $ allSpheres; verplaats 0,05 0 0;
Na het opnieuw instellen van de oorsprongspositie met behulp van onze eerder gemaakte "pivotToOrigin" -procedure, selecteren we de bollen een laatste keer en roteren ze 137,5 graden in Y. Voer daarna ons onaangeroerde script uit:
dt_pivotToOrigin; selecteer -r $ allSpheres; draai 0 137.5 0; dt_unParentSelected;
En dat voltooit onze laatste procedure. Ons volledige script zou er dus als volgt uit moeten zien:
// Maak ouderketen algemeen proc dt_makeParentChain () string $ selectedObjects [] = 'ls -sl'; int $ numSelectedObjects = 'size ($ selectedObjects)'; voor ($ i = 1; $ i < $numSelectedObjects; $i++) parent $selectedObjects[($i - 1)] $selectedObjects[$i]; ; select -deselect $selectedObjects[($numSelectedObjects - 1)]; ; // Un-Parent Objects global proc dt_unParentSelected() parent -w; ; // Move Pivot to Origin global proc dt_pivotToOrigin() string $selectedObjects[] = 'ls -sl'; for($thisObj in $selectedObjects) select -r $thisObj; xform -ws -rotatePivot 0 0 0 -scalePivot 0 0 0; ; ; //Create Fermat's Spiral of Spheres global proc dt_fermatSpiral() string $seedSphere[] = 'polySphere -sx 8 -sy 8'; string $allSpheres[]; for ($i=1; $i<1000; $i++) string $duplicatedSphere[] = 'duplicate'; $allSpheres[size($allSpheres)] = $duplicatedSphere[0]; ; select -r $allSpheres; dt_makeParentChain; select -r $allSpheres; move 0.05 0 0; dt_pivotToOrigin; select -r $allSpheres; rotate 0 137.5 0; dt_unParentSelected; ;
En daarmee zijn we klaar! Sla het script op en voer het 'rehash' / 'source'-proces opnieuw uit, zoals hierboven beschreven. Voer vervolgens de volgende opdracht in Maya's scripteditor in, druk op 'Ctrl-Enter' en wacht een paar seconden:
dt_fermatSpiral ();
En daar heb je Fermat's Spiral, volledig gebouwd met behulp van MEL. Probeer in de laatste procedure met verschillende hoeken, vormen en transformaties te spelen - je kunt allerlei interessante patronen krijgen!