Difference between revisions of "Rotation/it"

From Second Life Wiki
Jump to navigation Jump to search
(prima bozza in italiano)
 
(intestazione in italiano)
Line 1: Line 1:
{{LSL Header|ml=*}}{{RightToc}}
{{Multi-lang}}
{{LSL Header/it}}
{{RightToc}}
==Rotation==
==Rotation==
Il tipo '''rotation''' di LSL è uno dei diversi modi di rappresentare un orientamento in 3D.  (Notare che si sta scrivendo il nome del tipo in '''grassetto'''.)
Il tipo '''rotation''' di LSL è uno dei diversi modi di rappresentare un orientamento in 3D.  (Notare che si sta scrivendo il nome del tipo in '''grassetto'''.)

Revision as of 09:35, 21 October 2009

Rotation

Il tipo rotation di LSL è uno dei diversi modi di rappresentare un orientamento in 3D. (Notare che si sta scrivendo il nome del tipo in grassetto.) È un oggetto matematico chiamato quaternione (quaternion). Puoi pensare ad un quaternione come a quattro numeri, tre dei quali rappresentano la direzione verso la quale un oggetto è rivolto ed un quarto che rappresenta l’inclinizione sinistra o destra dell’oggetto intorno a questa direzione. Il vantaggio principale dell’uso dei quaternioni è che non sono suscettibili al vincolo dell’anello rotante (gimbal lock). Per le applicazioni complesse della matematica del quaternione, si veda quaternion. Per una lista di funzioni ed eventi, relativa alle rotazioni, si veda la sinossi della rotation di LSL (LSL Rotation Synopsis). Ci sono anche informazioni su ciò che permette alle immagini di trame grafiche (textures) di ruotare in altre textures.

Altre rappresentazioni

Vettore di Eulero

Un altro modo di rappresentare un angolo 3D è di usare tre numeri, <X, Y, Z>, i quali rappresentano la quantità di cui l’oggetto è ruotato intorno ad ogni asse. Ciò è usato, ad esempio, nella finestra “Modifica” ed è in genere semplice da visualizzare per le persone. È facile adattare i numeri <x, y, z> della rotazione nella finestra “Modifica” e vedere come l’oggetto si comporta. Nota che nella finestra “Modifica” i numeri sono in gradi, perciò un angolo retto è 90.

In LSL, questi tre angoli sono espressi in radianti (radians) invece che in gradi, quindi un angolo retto è PI/2 (un radiante è una sorta di grado molto largo). Notare che questi tre numeri sono un tipo vector e non tipo rotation, sebbene rappresenti la stessa informazione. Questa è definita la rappresentazione di Eulero di un angolo 3D. In LSL la rotazione intorno a z è fatta per prima, poi intorno a y e infine intorno a x.

FWD, LEFT, UP

Un altro modo di rappresentare lo stesso angolo 3D è usare tre vettori, per mostrare a cosa sta puntando la parte frontale (fwd), a cosa sta puntando la parte superiore (up) e a cosa sta puntando il lato sinistro (left). In realtà, solo due dei tre sono necessari, perché qualsiasi coppia determina il terzo.

Per buoni motivi, come l’essere in grado di combinare facilmente le rotazioni, la versione a quattro numeri, la rotation, è migliore, sebbene forse più difficile d’afferrare per un principiante. Fortunatamente è molto raro che sia necessario fare qualcosa con l’effettiva rappresentazione interna delle rotations e ci sono funzioni per convertire facilmente, in un senso e nell’altro, tra i tre tipi LSL e tra gradi e radianti.

Regola della mano destra

In LSL tutte le rotazioni sono fatte secondo la regola della mano destra. Con la tua mano destra, estendi il primo dito nel senso della direzione positiva dell’asse x. Estendi il tuo secondo dito ad angolo retto rispetto al tuo primo dito, e punterà lungo l’asse positivo di y, ed il tuo pollice, esteso ad angoli retti per entrambi che punterà lungo l’asse positivo di z. Quando si modifica un oggetto, le tre frecce colorate degli assi puntano nella direzione positiva per ogni asse (X: rossa, Y: verde, Z: blu).

http://it.wikipedia.org/wiki/Regola_della_mano_destra

Adesso, non togliere ancora la tua mano destra, c’è un altro uso per essa, che determina la direzione di una rotazione positiva. Chiudi il pugno con la tua mano destra, il pollice esteso e puntato nella direzione positiva dell’asse al quale sei interessato. Le tue dita si srotoleranno nella direzione della rotazione positiva. Le rotazioni intorno agli assi X, Y, and Z sono spesso riferite come Roll, Pitch e Yaw (Rotolamento, Beccheggio e Imbardata), particolarmente per i veicoli.

Roll Pitch Yaw

Rotazioni Combinate

Supponi di avere due rotazioni. r1 è ruotata di 90 gradi a sinistra e r2 è ruotata di 30 gradi a destra (qualsiasi rotazione funzionerà; queste sono solo un esempio.) Puoi combinare r1 e r2 per fare r3 usando l’operatore *. Esso in realtà non le moltiplica ma le compone. <lsl> rotation r3 = r1 * r2; </lsl> Il risultato in questo caso è che r3 cercherà di ruotare di 60 gradi a sinistra.

In altre parole, per combinare le rotations, usa gli operatori di moltiplicazione e divisione. Non provare ad usare gli operatori di addizione e sottrazione sulle rotations, in quanto esse non faranno ciò che t’aspetti. L’operazione di moltiplicazione applica la rotazione nella direzione positiva, l’operazione di divisione compie una rotazione negativa. Puoi anche negare una direzione direttamente, solo negando la componente s, es. X.s = -X.s.

Diversamente da altri tipi come float, l’ordine in cui le operazioni sono fatte, non-commutativa, è importante. La ragione di ciò è semplice: l’ordine in cui fai le rotazioni è importante in RL (Real Life ossia vita reale). Per esempio, se tu avessi un dardo con quattro piume, partito dalla rotazione <0, 0, 0> con la sua coda all’origine, esso ingannerebbe sull’asse X con la sua punta diretta nella direzione positiva di X, le sue piume lungo gli assi Z e Y, e l’asse del dardo e l’asse del mondo risulterebbero allineati. Lo ruoteremo di 45 gradi intorno a X e 30 gradi intorno a Y, ma in ordine differente.

Primo, dopo aver ruotato di 45 gradi intorno a X il dardo sarà ancora sull’asse X, fermo, come se avesse girato lungo il suo asse, quindi le piume saranno a 45 gradi rispetto all’asse. Poi ruotando di 30 gradi intorno a Y si sposterà nel piano XZ per puntare giù di 30 gradi dall’asse X (ricorda che la regola della mano destra per le rotazioni ci dice che una piccola rotazione positiva intorno a Y si muove puntando in basso). Il dardo conclude puntando 30 gradi in basso, nello stesso piano verticale dal quale è partito, ma girato intorno al suo asse in modo tale che le piume non siano più sopra e sotto.

Se tu l’hai fatto in altro modo, prima ruotando di 30 gradi in Y, il dardo ruoterà in basso nel piano XZ, ma si osserverà che non è più nell’asse X; il suo asse X e quello del mondo non sono più allineati. Adesso una rotazione di 45 gradi sull’asse X ruoterà il dardo intorno alla sua coda, il punto che segue un cono di 30 deg il cui asse è lungo l’asse positivo X del mondo, per 45 gradi in alto a destra. Cercando in basso l’asse X, esso ruoterà di 30 gradi sotto, in alto e a destra, fuori dal piano XZ, per puntare sotto il 1° quadrante nel piano XY, con le sue piume che ruotano così com’erano andate.

Chiaramente questo è un risultato differente dalla prima rotazione, ma l’ordine della rotazione è solamente cambiato.

Per fare una rotazione costante hai bisogno di definire un valore rotation che può essere fatto creando un vettore (vector) con gli angoli X, Y, Z in radianti come componenti (chiamati angoli di Eulero), quindi convertendoli come rotation utilizzando la funzione llEuler2Rot. Puoi in alternativa creare direttamente una rotazione: la parte reale è il coseno della metà dell’angolo di rotazione, e la parte vettoriale è l’asse normalizzato della rotazione moltiplicato per il seno della metà dell’angolo di rotazione. Per passare da una rotazione ad un vettore (vector) con gli angoli di Eulero usa llRot2Euler.

NOTA: gli angoli in LSL sono in radianti, non gradi, ma puoi facilmente convertirli usando le costanti predefinite RAD_TO_DEG e DEG_TO_RAD. Per una rotation di 30 gradi sull’asse X dovresti usare:

rotation rot30X = llEuler2Rot(<30, 0, 0> * DEG_TO_RAD); // converte i gradi in radianti, poi converte il vector in una rotation, rot30x
vector vec30X = llRot2Euler(rot30X ); // converte la rotazione di nuovo in un vector (i valori saranno in radianti)

Differenze tra quaternioni matematici e rotazioni LSL

Ci sono un po’ di differenze tra LSL e la matematica che hanno delle conseguenze mentre programmi, ma che possono confondere le persone con una precedente conoscenza matematica. Perciò pensiamo sia giusto elencarle qui:

  • In LSL, tutti i quaternioni sono normalizzati (il prodotto scalare di R per R è sempre 1), e quindi rappresentano i modi di ruotare oggetti senza cambiare la loro dimensione. In matematica, quaternioni generici potrebbero essere non normalizzati, ed essi rappresentano affinità, e.s. un modo per ruotare e cambiare la dimensione degli oggetti.
  • In LSL, il termine s è il quarto membro della rotazione: <x, y, z, s>. In matematica, il termine s, anche chiamato "parte reale", è scritto come la prima coordinata del quaternione: (s, x, y, z).
  • La moltiplicazione è scritta in ordine inverso in LSL rispetto alla matematica. In LSL, scriverai R * S, mentre in matematica scriverai S . R.

Ordine di rotazione dei Vettori di Eulero

Dalla discussione di sopra, è chiaro che quando ci preocccupiamo delle rotazioni intorno a più di un asso, l’ordine che seguono è cruciale. Nella discussione soprastante di Eulero ciò generava un po’ di equivoci, le rotazioni individuali sui tre assi definiscono una rotation complessiva, ma ciò fa nascere una domanda: In quale ordine le rotazioni degli assi sono compiute? Lka risposta è Z, Y, X nelle coordinate globali. Se cerchi di ruotare un oggetto intorno a più assi usando la rappresentazione di Eulero, determina il giusto vectordi Eulero usando l’ordine di rotazione Z, Y, X, quindi usa la funzione llEuler2Rot per ottenere la rotation da usare in rotazioni combinate o per applicare la rotazione all’oggetto.

Rotazioni Locali e Globali (Mondo)

È importante distinguere tra la rotation relativa al mondo, e la rotation relativa all’oggetto locale stesso. Nella finestra di “Modifica”, puoi commutare in un senso e nell’altro. In uno script, devi convertire dall’uno all’altro per ottenere il comportamento desiderato.

Le rotazioni Locali sono quelle fatte intorno agli assi incorporati dell’oggetto stesso avanti/dietro, sinistra/destra, su/giù, indipendentemente da come l’oggetto è ruotato nel mondo. Le rotazioni Globali sono quelle fatte intorno agli assi del mondo, Nord/Sud, Est/Ovest, Superiore/Inferiore. Puoi vedere la differenza ruotando una primitiva, quindi modificala e cambia le impostazioni degli assi da locale a globale ed osserva come le frecce degli assi colorati cambiano.

In LSL, la differenza tra fare una rotazione locale o global è nell’ordine con cui le rotations sono valutate nell’istruzione.

Questo compie una rotazione locale di 30 gradi mettendo la costante rotation di 30 gradi alla sinistra della rotation (myRot) iniziale dell’oggetto. È come la prima operazione nel primo esempio di sopra, solo che giriamo il dardo di 30 gradi intorno alla lunghezza del suo asse.

rotation localRot = rot30X * myRot; // fa una rotazione locale moltiplicando una rotazione costante per una rotazione del mondo

Per fare una rotazione globale, usa gli stessi valori della rotation, ma nell’ordine opposto. Questa è come la seconda operazione nel secondo esempio, nel quale il dardo ruota in alto a destra sull’asse X del mondo. In questo caso, la rotazione esistente (myRot) è rutata di 30 gradi intorno all’asse globale X.

rotation globalRot = myRot * rot30X; // fa una rotazione globale moltiplicando una rotazione del mondo per una rotazione costante

Un altro modo di pensare alle rotazioni combinate

Devi pensare alla differenza tra locali e globali considerando che le rotations sono fatte nell’ordine di valutazione, che è da sinistra a destra eccetto per le espressioni tra parentesi.

Nel caso di localRot, ciò che è successo era che si partiva da <0, 0, 0>, era fatta prima la rot30X, ruotando la primitiva sull’asse X del mondo, mentre fino a quando non è ruotata, gli assi locali e globali sono identici; essa ha l’effetto di fare la rotazione sull’asse locale X dell’oggetto. Quindi la seconda rotation myRot era fatta da ciò che aveva ruotato la primitiva alla sua originale rotazione, ma adesso con l’aggiuntiva rotazione sull’asse X. Tutto ciò sembra come se la primitiva avesse ruotato in loco, intorno al suo asse X, con le rotazioni Y e Z immutate, insomma una rotazione locale.

Nel caso del globalRot, si parte ancora da <0, 0, 0>, dapprima l’oggetto è ruotato alla sua originale rotazione (myRot), ma ora gli assi dell’oggetto e gli assi del mondo non sono più allineati! Quindi, la seconda rotation rot30x fa esattamente ciò che fece nel caso locale, ruota l’oggetto di 30 gradi sull’asse X del mondo, ma l’effetto è di ruotare l’oggetto attraverso un cono sull’asse X del mondo poiché l’asse X dell’oggetto e l’asse X del mondo non sono gli stessi nello stesso tempo. Tutto ciò sembra come se la primitiva avesse ruotato di 30gradi sull’asse X del mondo, quindi una rotazione globale.

La Divisione delle rotations ha l’effetto di compiere la rotazione nella direzione opposta, moltiplicare di 330 gradi una rotation è lo stesso che dividere per 30 gradi una rotation.

L’uso di Rotations

Puoi accedere alle componenti individuali di una rotation R attraverso R.x, R.y, R.z, & R.s (non R.w). la parte scalare R.s è il coseno della metà dell’angolo di rotazione. La parte vettoriale (R.x,R.y,R.z) è il prodotto dell’asse normalizzato della rotazione ed il seno della metà dell’angolo di rotazione. Puoi generare una rotation inversa negando i membri x,y,z (oppure negando il valore di s). A parte questo, puoi anche usare una rotation come un deposito di valori float, ogni rotation memorizza quattro di loro ed una list consistenti di rotation è più efficiente che una list consistente di floats, anche se c’è uno sforzo in più per scompattarli.

rotation rot30X = llEuler2Rot(<30, 0, 0> * DEG_TO_RAD ); // Creare una rotazione costante
rotation rotCopy = rot30X; // Nel copiarla dentro rotCopy, copia tutti e 4 le componenti float
float X = rotCopy.x; // Assegna le componenti individuali della rotazione
float Y = rotCopy.y;
float Z = rotCopy.z;
float S = rotCopy.s;
rotation anotherCopy = <X, Y, Z, S>; // Fa un’altra rotazione dalle componenti


C’è una costante predefinita per una rotation zero ZERO_ROTATION che puoi usare direttamente oppure, se hai bisogno d’invertire una rotation R, dividere ZERO_ROTATION per R. Come promemoria di sopra, ciò funziona dapprima ruotando alla posizione zero, poi dato che è una divisione, ruotando nel senso opposto alla rotation originale, quindi facendo la rotazione inversa.

rotation rot330X = <-rot30X.x, -rot30X.y, -rot30X.z, rot30X.s>; // inverte una rotazione - NOTA che la componente s non è negata
rotation another330X = ZERO_ROTATION / rot30X; // inverte una rotazione attraverso una divisione, con lo stesso risultato di rot330X
rotation yetanother330X = <rot30X.x, rot30X.y, rot30X.z, -rot30X.s>; // non letteralemente lo stesso ma funziona ugualmente.

Primitive Radice o Singole, Primitive Collegate, Allegati

La ragione per discutere sulle rotazioni di primitive singole o collegate è che per cose come porte nei veicoli, il moto desiderato è spostare la porta in relazione al veicolo, indipendentemente da quale sia la rotazione del veicolo complessivo. Mentre è possibile fare ciò con le rotazioni globali, esso potrebbe diventare subito noioso. Ci sono generalmente tre sistemi di coordinate in cui una primitiva può esistere: tutte sole, parte di una serie di collegamenti (linkset), oppure parte di un allegato (attachment). Quando una primitiva è sola, e.s., non una parte di un insieme di collegamenti (linkset), essa si comporta come una primitiva radice; quando è parte di un allegato (attachment), agisce diversamente ed è un po’ rotta.

Getting and setting rotations of prims
Function Ground (rez'ed) Prims Attached Prims
Root Children Root Children
llGetRot
llGPP:PRIM_ROTATION
llGetObjectDetails
global rotation of prim global rotation of prim global rotation of avatar global rotation of avatar * global rotation of prim (Not Useful)
llGetLocalRot
llGPP:PRIM_ROT_LOCAL
global rotation of prim rotation of prim relative to root prim rotation of attachment relative to attach point rotation of prim relative to root prim
llGetRootRotation global rotation of prim global rotation of root prim global rotation of avatar global rotation of avatar
llSetRot*
llSPP:PRIM_ROTATION*
set global rotation complicated, see llSetRot set rotation relative to attach point set rotation to root attachment rotation * new_rot.
llSetLocalRot*
llSPP:PRIM_ROT_LOCAL*
set global rotation set rotation of prim relative to root prim set rotation relative to attach point set rotation of prim relative to root prim
llTargetOmega
ll[GS]PP:PRIM_OMEGA
spin linkset around prim's location spin prim around its location spin linkset around attach point spin prim around its location
Physical objects which are not children in a linkset will not respond to setting rotations.
†  For non-Physical objects llTargetOmega is executed on the client side, providing a simple low lag method to do smooth continuous rotation.

Ruotare Vettori

In LSL, ruotare un vector è molto utile se si vuole muovere un oggetto in un arco o circolo quando il centro della rotazione non è il centro dell’oggetto.

Ciò sembra molto complesso, ma è molto meno di ciò che incontra l’occhio. Ricorda dalla discussione di sopra della rotazione del dardo (dart), e sostituisci il dardo fisico con un vector la cui origine è la coda del dardo, e le cui componenti in X, Y, e Z descrivono la posizione della punta del dardo. Ruotando il dardo intorno alla sua codasi muove anche la punta del dardo ed un arco il cui centro di rotazione è la coda del dardo. Esattamente nello stesso modo, ruotando un vector, che rappresenta una misura, dal centro di una primitiva ruota una primitiva attraverso uno stesso arco. Tutto ciò sembra come se l’oggetto ruotasse su una posizione misurata attraverso il vector dal centro della primitiva.

Posizione di un Oggetto Ruotato intorno ad un Punto Relativo

<lsl>rotation vRotArc = llEuler2Rot( <30.0, 0.0, 0.0> * DEG_TO_RAD );

//-- crea una rotazione costante, 30 gradi sull’asse X

vector vPosOffset = <0.0, 1.0, 0.0>;

//-- crea una misura di un metro nella direzione positiva di Y

vector vPosRotOffset = vPosOffset * vRotArc;

//-- ruota la misura per avere un moto causato dalla rotazione

vector vPosOffsetDiff = vPosOffset - vPosRotOffset;

//-- ottiene la differenza locale tra la misura corrente e quela ruotata

vector vPosRotDiff = vPosOffsetDiff * llGetRot();

//-- ruota le differenze nelle misure affinché siano relative alle rotazioni globali

vector vPosNew = llGetPos() + vPosRotDiff;

//-- trova le nuove posizioni delle primitive aggiungendo la differenza della misura ruotata

rotation vRotNew = vRotArc * llGetRot();

//-- trova rot pr continuare a mostrare il punto di misura</lsl>
in pratica, la stessa cosa che:

<lsl>llSetPrimitiveParams( [PRIM_POSITION, llGetPos() + (vPosOffset - vPosOffset * vRotArc) * llGetRot(),

                      PRIM_ROTATION, vRotArc * llGetRot()] );</lsl>
  • Il metodo di sopra risulta nell’oggetto orbitante avere sempre lo stesso lato rivolto al centro. Un alternativa che preserva da una rotazione orbitante è quella che segue

<lsl>llSetPrimitiveParams( [PRIM_POSITION, llGetPos() + (vPosOffset - vPosOffset * vRotArc) * llGetRot()]; vPosOffset = vPosOffset * vRotArc;</lsl> Nota Bene: Fare ciò è un movimento, quindi non tralasciare le problematiche relative allo spostamento di una primitiva fuori dal mondo, sotto terra, a più di 10 m, ecc. Anche per ottenere un’orbita piena, avrai bisogno di ripetere i passi elencati (magari in un temporizzatore (timer)).

Posizione di un Punto Relativo intorno ad un Oggetto Ruotato

Per avere un punto relativo al lato mostrato dagli oggetti (com’è usato nei luoghi per costruire) <lsl>vector vPosOffset = <0.0, 0.0, 1.0>;

//-- crea una misura di un metro nella direzione positiva di Z

vector vPosRotOffset = vPosOffset * llGetRot();

//-- ruota la misura affinché sia relativa alla rotazione dell’oggetto

vector vPosOffsetIsAt = llGetPos() + vPosRotOffset;

//-- ottiene la posizione della regione della misura ruotata</lsl>
in pratica, la stessa cosa che:

<lsl>llRezAtRoot( "Object", llGetPos() + vPosOffset * llGetRot(), ZERO_VECTOR, llGetRot(), 0 );</lsl>

Informazioni Utili

<lsl>integer IsRotation(string s) {

   list split = llParseString2List(s, [" "], ["<", ">", ","]);
   if(llGetListLength(split) != 9)//we must check the list length, or the next test won't work properly.
       return 0;
   return !((string)((rotation)s) == (string)((rotation)((string)llListInsertList(split, ["-"], 7))));
   //Stabilisce il segno dell’elemento S della rotazione
   //Se funziona o interrompe la rotazione allora i valori non coincideranno
   //Se la rotazione è già interrotta allora il segno non avrà effetto ed il valore coinciderà
   //si convertirà al tipo stringa in modo da catturare gli zero negativi che consentono di supportare <0,0,0,0>

}//Strife Onizuka</lsl>


// Calcola un punto alla distanza d nella direzione dell’avatar id che gli si mostra <lsl>vector point_in_front_of( key id, float d ) {

   list pose = llGetObjectDetails( id, [ OBJECT_POS, OBJECT_ROT ] );
   return ( llList2Vector( pose, 0 ) + < d, 0.0, 0.0 > * llList2Rot( pose, 1 ) );

}// Mephistopheles Thalheimer</lsl>


// Materializza un oggetto alla distanza d dalla fine dell’asse z. // L’oggetto è orientato a colui che lo materializza

<lsl>rez_object_at_end( string o, float d ) {

   vector s = llGetScale();
   
   if( llGetInventoryType( o ) == INVENTORY_OBJECT )
   {
       llRezObject( o, llGetPos() + llRot2Up( llGetRot() ) * ( s.z / 2.0 + d ) , ZERO_VECTOR, llGetRot(), 0 );
   }

}// Mephistopheles Thalheimer</lsl>

// Fuzioni utili convertite a LSL da questa pagina:

// Scala una rotazione: <lsl>rotation ScaleQuat(rotation source, float ratio) { return llAxisAngle2Rot(llRot2Axis(source), ratio * llRot2Angle(source)); }</lsl>

// Costringe una rotazione ad un piano dato, definito dal suo perpendicolare, che è molto utile per i veicoli che rimangono orizzontali alternativamente: <lsl>rotation ConstrainQuat2Plane(rotation source, vector normal) { return llAxisAngle2Rot(normal, <source.x, source.y, source.z> * normal * llRot2Angle(source)); } // Jesrad Seraph</lsl>

// Funzione per la combinazione di rotazioni da Slerp: <lsl>rotation BlendQuats(rotation a, rotation b, float ratio) { return llAxisAngle2Rot(llRot2Axis(b /= a), ratio * llRot2Angle(b)) * a; }</lsl>

Costanti

ZERO_ROTATION

ZERO_ROTATION = <0.0, 0.0, 0.0, 1.0>;
Una costante di rotazione che rappresenta un angolo di Eulerodi <0.0, 0.0, 0.0>.

DEG_TO_RAD

DEG_TO_RAD = 0.01745329238f;
Una costante di tipo float che quando moltiplicata per un angolo in gradi dà l’angolo in radianti.

RAD_TO_DEG

RAD_TO_DEG = 57.29578f;
Una costante di tipo float che quando moltiplicata per un angolo in radianti dà l’angolo in gradi.


RotationCategoria:LSL_MathCategoria:LSL_Math/3DCategoria:LSL Rotation