|
Random Light Start MEL tutorial av Kjetil H Kulander
Dette skriptet er ment å brukes på en mengde lys som skal slås på i tilfeldig rekkefølge i en bestemt tidsperiode. Siden skriptet bruker visibility attributen til å slå på lysene kan skriptet også brukes hvis det er objekter i scenen som skal bli synlige.
Skriptet legger til en attributt på hvert av de markerte objektene som heter "frameOn". Attributtens verdi sier hvilken frame "visibility" settes til "on". Attributten "frameOn" får en tilfeldig verdi mellom hva du setter som "min" og "max" i vinduet som kommer frem når du kjører skriptet. Hvis ønskelig kan denne verdien endres i ettertid.
Skriptet må deles inn i to deler ( To globale prosedyrer ). Del 1 lager vinduet der du skal skrive inn "min" og "max" verdi. Del 2 gjør selve jobben med å legge til "frameOn" attributen, og legger til expression på visibility.
Del 1
Koden for å lage den første prosedyreren ser slik ut:
global proc randomLightStart()
{
}
"global" betyr at følgende prosedyre kan kjøres "manuelt". Siden dette er prosedyren som skal kjøres for å få frem vinduet må den derfor være tilgjengelig. Hvis en prosedyre ikke er global er den kun tilgjengelig fra koden til en global prosedyre i samme script. "randomLightStart" er navnet på prosedyren. Hvis man skriver dette navnet i "Command Line" vil koden mellom tegnene "{" og "}" kjøres.
Resten av koden i del 1 skal dermed skrives mellom "{" og "}".
string $lightAttrWindow = `window -title lightAttr`;
"string $lightAttrWindow" lager en string variabel som heter $lightAttrWindow. Når man kjører en kommando i Maya returneres det alltid en et "resultat". I dette tilfellet er kommandoen "window -title lightAttr" og resultatet er navnet på vinduet kommandoen lager. Siden det er resultatet fra kommandoen og ikke kommandoen som skal lagres i variabelen må kommandoen skrives mellom tegnene "`". Som alltid avsluttes en skript linje med tegnet ";". Navnet på vinduet som ble laget er nå lagret i variabelen, og vi har da tilgang til dette vinduet senere i scriptet.
columnLayout;
Kommandoen "columnLayout" lager en layout i vinduet. Man må ha en layout for å kunne plassere elementer i vinduet. Man har mange forskjellige typer layouts. Hva slags layout man bruker bestemmer hvordan elementene blir plassert i vinduet. I dette tilfellet brukes en columnLayout som plasserer elementene under hverandre i en kolonne.
global string $minInt;
global string $maxInt;
Akuratt som at prosedyrer kan være globale og lokale kan også variabler være det. $minInt og $maxInt må være tilgjengelig for prosedyre nr. 2. Derfor må de være globale. En lokal variabel er kun tilgjengelig i prosedyren som den blir laget.
text min;
$minInt = `intField -v 0`;
text max;
$maxInt = `intField -v 100`;
"text" er kommandoen for å lage tekst i vinduet. "min" er så selve teksten.
"$minInt" er den globale string variabelen som nettopp ble laget. Den får her en verdi som er resultatet av kommandoen "intField -v 0". intField kommandoen lager et felt der man kan skrive inn "min" verdien (hva som er minste verdi for når lysene skal slås på). "-v 0" gir feltet verdien 0.
button -l randomize -c "lightAttr($minInt, $maxInt)";
"button" er kommandoen for å lage en knapp. "-l" (forkortelse av label) er flag for hva som skal stå på knappen. Det som står etter en flag er argumenter; i dette tilfellet hva som skal stå på knappen: "randomize". "-c" er flag for hvilken kommando som skal kjøres når man klikker på knappen. "lightAttr" er en prosedyre som er en del av dette skriptet.
Argumentene "($minInt, $maxInt)" er informasjon fra denne prosedyren som skal overføres og brukes i prosedyren "lightAttr". "lightAttr" må vite hvilken verdi som er skrevet inn i feltene for "min" og "max". Variablene som brukes her er string variabler som kun inneholder navnet til feltene. De inneholder ikke noen informasjon om hvilken verdi som er skrevet inn. "lightAttr" må derfor bruke informasjon om navnet til feltene for å selv sjekke hva som ble skrevet inn.
showWindow;
Hittil er informasjon om vinduet og elementene kun lagret i minnet. For at vinduet skal bli synlig kjøres kommandoen "showWindow".
window -e -width 25 -height 140 $lightAttrWindow;
Størrelsen på vinduet er nå helt tilfeldig siden vi ikke brukte noen flag for størrelse når vi laget vinduet. I stedet for å bestemme størrelsen på vinduet når det lages redigerer vi størelsen på vinduet etter at det er laget. "window" med flag "-e"(edit) betyr av vi skal redigere et eksisterende vindu. "$lightAttrWindow" er vinduet som skal redigeres. Grunnen til at vi gjør det på denne kanskje litt ulogiske måten er; Maya har en standard preferanse som sier at Maya skal huske størrelse og posisjon på vinduene. Når dette valget er på, så ignoreres innstillingene for størrelse i skriptet. Den enkleste løsningen blir da å redigere størrelsen på vinduet etter at det er laget.
En alternativ måte er at skriptet sjekker hva preferansen "Remember Size and Position" er. Få skriptet til å slå den av før vinduet lages, og sette den tilbake helt i slutten av skriptet. Når du lager skript som må endre preferansene, så husk alltid å få skriptet til å sette preferansene tilbake til hva det var før skriptet ble kjørt.
Del 2
global proc lightAttr(string $minInt, string $maxInt)
{
}
Som i del 1 så lages prosedyren på denne måten. Den må være global siden prosedyren kjøres som en kommando når man klikker på knappen. Den kjøres ikke som en direkte del av den første prosedyren.
Annerledes fra del 1 så har denne prosedyren argumentene "(string $minInt, string $maxInt)". Argumentene er variabler som får tildelt en verdi når prosedyren kjøres. I dette tilfellet to string variabler som inneholder navnet på feltene der man skriver inn "min" og "max" verdi.
Resten av koden i del 2 skal dermed mellom "{" og "}":
int $min = `intField -q -v $minInt`;
int $max = `intField -q -v $maxInt`;
"intField" er en kommando som behandler int fields. En kommando kan ha en av 3 forskjellige egenskaper; Den kan lage noe, den kan redigere noe, eller den kan spørre om noe. F. eks.: intField med flag "-c" lager en ny intField. intField med flag "-e" redigerer verdien i en allerede eksisterende intField. intField med flag "-q" spør om hva verdien i en eksisterende intField er. Kommandoen "`intField -q -v $maxInt`" sjekker altså hvilken verdi som er skrevet inn i feltet med navnet som er lagret i variabelen $maxInt.
string $lights[] = `ls -sl`;
"`ls -sl`" lister opp alle objekter som er markert. "ls" er kommando for å liste opp noe, og "-sl" er flag for hva som skal listes opp (selected'e objekter). Listen lagres så i en string variabel. Tegnene "[]" bak navnet på variabelen betyr at variabelen er en "array". En array-variabel er en tabell som inneholder flere oppføringer av typen variabel.
string $expression;
string $visibility;
string $frameOn;
Tre nye string variabler lages uten å få noe innhold. Disse variablene skal brukes senere i skriptet.
for($counter = 0; $counter < size($lights); $counter++)
{
}
Dette er koden for en samling av koder som skal kjøres mange ganger. I dette tilfellet skal samme kode kjøres på hvert av de markerte objektene. "for" er navnet på typen loop. Koden mellom "(" og ")" er en tilstand som beskriver hvor mange ganger koden skal repeteres.
"$counter = 0;" lager en int variabel som brukes som informasjon om hvor mange ganger koden er repetert.
Denne koden sjekker forholdet mellom hvor mange ganger koden har kjørt og hvor mange ganger den skal kjøres: "$counter < size($lights);". "size" er kommando for å sjekke størrelsen på en variabel. Når man sjekker størrelsen på en array-variabel får man antall oppføringer i tabellen. Siden denne variabelen inneholder markerte objekter får vi hvor mange objekter som var markert. Når $counter's verdi er større enn antall objekter stopper loopen, og skriptet fortsetter med koden etter loopen.
"$counter++" gjør at $counter's verdi øker med 1 hver gang loopen kjøres.
Det som skrives mellom "{" og "}" er selve koden som skal repeteres.
$visibility = $lights[$counter] + ".visibility";
$frameOn = $lights[$counter] + ".frameOn";
Navnet på objektets visibility attributt lagres i variabelen $visibility. Tallet man skriver mellom "[" og "]" bak en array bestemmer hvilken del av tabellen som leses. Siden $counter's verdi øker for hver gang loopen kjører vil vi for hver gang få neste objekt i tabellen (Loopen kjører like mange ganger som antall objekter).
Når man skal lagre tekst i en string variabel skriver man teksten mellom """ og """. Hvis teksten ligger i en variabel gjøre man ikke det. Ved å bruke " + " legger man sammen flere forskjellige tekst linjer.
addAttr -ln frameOn -at long -k 1 $lights[$counter];
"addAttr" er kommando for å legge til en attributt. "-ln" er flag for navnet til attributten som skal lages. "frameOn" er så selve navnet på attributten. "-at" er flag for attributt type. Denne attributten skal være type "long". "-k 1" betyr at attributten skal være "keyable" og dermed være tilgjengelig i channelBox'en. Til slutt må vi spesifisere hvilket objekt som skal ha den nye attributten: "$lights[$counter]".
setAttr ($lights[$counter] + ".frameOn") (rand($min, $max));
"setAttr" er kommando for å gi en attributt ny verdi. Først spesifiserer man hvilken attributt som skal få en verdi "($lights[$counter] + ".frameOn")". Og så hvilken verdi attributten skal få "(rand($min, $max))".
$expression = "if (frame < "+ $frameOn +")\n{\n"+ $visibility +" = 0;\n}\nelse\n{\n"+ $visibility +" = 1;\n}";
Et uttrykk (expression) blir lagret i string variabelen $expression. Når man skriver uttrykk som en del av et skript må det skrives på en litt klønete måte. Alt må skrives på en linje. Man bruker koden "\n" for å få en ny linje i uttrykket. Man må dele fra hverandre tekst og tekst som er lagret i variabler. Etter at skriptet er kjørt og uttrykket er lagte på et av lysene vil uttrykket se slik ut i Expression Editor:
if (frame < directionalLight1.frameOn)
{
directionalLight1.visibility = 0;
}
else
{
directionalLight1.visibility = 1;
}
Med if/else kan vi kjøre forskjellige koder basert på en tilstand. "frame < directionalLight1.frameOn" er tilstanden. Hvis aktiv frame er mindre en verdien til attributten "frameOn" på lyset kjøres følgende kode; "directionalLight1.visibility = 0" . Hvis aktiv frame er mer en "frameOn" kjøres koden som kommer etter "else"; "directionalLight1.visibility = 1".
expression -s $expression;
Når uttrykket er lagret i en string variabel lages selve uttrykket med kommandoen "expression". "-s" er flag for teksten som skal være i uttrykket. "$expression" er variabelen som inneholder uttrykket.
Den ferdige koden
global proc randomLightStart()
{
string $lightAttrWindow = `window -title lightAttr`;
columnLayout;
global string $minInt;
global string $maxInt;
text min;
$minInt = `intField -v 0`;
text max;
$maxInt = `intField -v 100`;
button -l randomize -c "lightAttr($minInt, $maxInt)";
showWindow;
window -e -width 25 -height 140 $lightAttrWindow;
}
global proc lightAttr(string $minInt, string $maxInt)
{
int $min = `intField -q -v $minInt`;
int $max = `intField -q -v $maxInt`;
string $lights[] = `ls -sl`;
string $expression;
string $visibility;
string $frameOn;
for($counter = 0; $counter < size($lights); $counter++)
{
$visibility = $lights[$counter] + ".visibility";
$frameOn = $lights[$counter] + ".frameOn";
addAttr -ln frameOn -at long -k 1 $lights[$counter];
setAttr ($lights[$counter] + ".frameOn") (rand($min, $max));
$expression = "if (frame < "+ $frameOn +")\n{\n"+ $visibility +" = 0;\n}\nelse\n{\n"+ $visibility +" = 1;\n}";
expression -s $expression;
}
}
|