Difference between revisions of "Rotation/pl"

From Second Life Wiki
Jump to navigation Jump to search
 
(10 intermediate revisions by 2 users not shown)
Line 5: Line 5:
Orientacja jest reprezentowana przez pojęcie matematyczne nazywane {{LSLG|quaternion|kwaternionem}}.  Można myśleć o kwaternionie jako o czterech liczbach, z których pierwsze trzy reprezentują kierunek w którym obiekt jest skierowany (rozumiany jako wektor 3D), a czwarta z nich to nachylenie (kąt obrotu) w lewo lub w prawo w płaszczyźnie normalnej (prostopadłej) do kierunku skierowania.  
Orientacja jest reprezentowana przez pojęcie matematyczne nazywane {{LSLG|quaternion|kwaternionem}}.  Można myśleć o kwaternionie jako o czterech liczbach, z których pierwsze trzy reprezentują kierunek w którym obiekt jest skierowany (rozumiany jako wektor 3D), a czwarta z nich to nachylenie (kąt obrotu) w lewo lub w prawo w płaszczyźnie normalnej (prostopadłej) do kierunku skierowania.  
Podstawową zaletą kwaternionów jest to, ze nie powodują one błędów typu [http://en.wikipedia.org/wiki/Gimbal_Lock gimbal lock] (związanych z równoległością prostych w przestrzeni trójwymiarowej).  
Podstawową zaletą kwaternionów jest to, ze nie powodują one błędów typu [http://en.wikipedia.org/wiki/Gimbal_Lock gimbal lock] (związanych z równoległością prostych w przestrzeni trójwymiarowej).  
Jeżeli chcesz zapoznać się ze szczegółami matematycznymi, zobacz {{LSLG|quaternion|kawternion}}.
Jeżeli chcesz zapoznać się ze szczegółami matematycznymi, zobacz {{LSLG|quaternion|kwaternion}}.
{{LSLG|Rotation Synopsis}} to lista użytecznych funkcji i zdarzeń (events) odnoszących się do obrotów.
{{LSLG|Rotation Synopsis}} to lista użytecznych funkcji i zdarzeń (events) odnoszących się do obrotów.
Jest też informacja o obracaniu tekstur, {{LSLG|texture|tutaj}}
Jest też informacja o obracaniu tekstur, {{LSLG|texture|tutaj}}
Line 17: Line 17:


==Reguła prawej dłoni==
==Reguła prawej dłoni==
W LSL'u wszystkie obroty są wykonywane zgodnie z regułą '''prawej dłoni'''. Ustawiamy dłoń z palcami wyprostowanymi wzdłuż osi OX. Następnie zginamy palce, z wyjątkiem kciuka, wskazując zwrot osi OY. Odwiedziny kciuk wskazuje zwrot osi OZ w układzie prawoskrętnym. Podczas edycji obiektu trzy kolorowe strzałki wskazują dodatni kierunek każdej osi (X: czerwona, Y: zielona, Z: czerwona).
W LSL'u wszystkie obroty są wykonywane zgodnie z regułą '''prawej dłoni'''. Ustawiamy dłoń z palcami wyprostowanymi wzdłuż osi OX. Następnie zginamy palce, z wyjątkiem kciuka, wskazując zwrot osi OY. Odwiedziny kciuk wskazuje zwrot osi OZ w układzie prawoskrętnym. Podczas edycji obiektu trzy kolorowe strzałki wskazują dodatni kierunek każdej osi (X: czerwona, Y: zielona, Z: niebieska).


[http://pl.wikipedia.org/wiki/Regu%C5%82a_prawej_d%C5%82oni#Matematyka Reguła Prawej Dłoni]  
[http://pl.wikipedia.org/wiki/Regu%C5%82a_prawej_d%C5%82oni#Matematyka Reguła Prawej Dłoni]  
Line 42: Line 42:
Stałą typu '''rotation''' można utworzyć przez stworzenie {{LSLG|vector|wektora}} z wartościami X, Y, Z składowych obrotu wyrażonych w radianach (tzw. kąt Euler'a) a następnie zmieniając go w typ '''rotation''' używając funkcji {{LSLG|llEuler2Rot}}. Można też stworzyć wartość typu '''rotation''' bezpośrednio: Część rzeczywista to cosinus połowy kąta obrotu, część wektorowa jest znormalizowaną osią obrotu pomnożoną przez sinus połowy kąta obrotu. Do przekształcenia typu '''rotation''' na kąt Eulera typu {{LSLG|vector}} służy funkcja {{LSLG|llRot2Euler}}.
Stałą typu '''rotation''' można utworzyć przez stworzenie {{LSLG|vector|wektora}} z wartościami X, Y, Z składowych obrotu wyrażonych w radianach (tzw. kąt Euler'a) a następnie zmieniając go w typ '''rotation''' używając funkcji {{LSLG|llEuler2Rot}}. Można też stworzyć wartość typu '''rotation''' bezpośrednio: Część rzeczywista to cosinus połowy kąta obrotu, część wektorowa jest znormalizowaną osią obrotu pomnożoną przez sinus połowy kąta obrotu. Do przekształcenia typu '''rotation''' na kąt Eulera typu {{LSLG|vector}} służy funkcja {{LSLG|llRot2Euler}}.


'''NOTE:''' angles in LSL are in radians, not degrees, but you can easily convert by using the built-in constants [[#RAD_TO_DEG|RAD_TO_DEG]] and [[#DEG_TO_RAD|DEG_TO_RAD]]. For a 30 degree '''rotation''' around the X axis you might use:
'''UWAGA:''' Kąty w LSL'u są wyrażane w radianach a nie w stopniach, ale można użyć predefiniowanych stałych [[#RAD_TO_DEG|RAD_TO_DEG]] i [[#DEG_TO_RAD|DEG_TO_RAD]]. Żeby uzyskać trzydziestopniową wartość typu '''rotation''' dookoła osi X axis można użyć następującej konstrukcji:


<div id="box"><div style="padding: 0.5em">
<div id="box"><div style="padding: 0.5em">
{| cellpadding=0 cellspacing=0
{| cellpadding=0 cellspacing=0
|-
|-
|rotation rot30X ||= {{LSLG|llEuler2Rot}}(<30, 0, 0> * DEG_TO_RAD);||// convert the degrees to radians, then convert that {{LSLG|vector}} into a rotation, rot30x
|rotation rot30X ||= {{LSLG|llEuler2Rot}}(<30, 0, 0> * DEG_TO_RAD);||// zminia stopnie na radiany a potem {{LSLG|vector|wektor}} w obrót: rot30x
|-
|-
|{{LSLG|vector}} vec30X ||= {{LSLG|llRot2Euler}}(rot30X );||// convert the rotation back to a {{LSLG|vector}} (the values will be in radians)
|{{LSLG|vector}} vec30X ||= {{LSLG|llRot2Euler}}(rot30X );||// zmienia obrót z powrotem w {{LSLG|vector|wektor}} (wartości kątów będą w radianach)
|}
|}
</div></div>
</div></div>


== Order of rotation for Euler Vectors ==
== Kolejność obrotów dla wektorów Eulera ==


From the above discussion, it's clear that when dealing with rotations around more than one axis, the order they are done in is critical. In the ''Euler'' discussion above this was kind of glossed over a bit, the individual rotations around the three axis define an overall ''rotation'', but that begs the question: What axis order are the rotations done in? The answer is '''Z, Y, X''' in global coordinates. If you are trying to rotate an object around more than one axis at a time using the ''Euler'' representation, determine the correct ''Euler'' {{LSLG|vector}} using the Z, Y, X rotation order, then use the {{LSLG|llEuler2Rot}} function to get the '''rotation''' for use in combining rotations or applying the rotation to the object.
Z powyższych rozważań wynika jasno, żę kiedy obracamy obiekty wokół więcej niż jednej osi, kolejność tych obrotów ma zasadnicze znaczenie. Ten temat został ominięty przy traktowaniu wektora Eulerowskiego jako ''całkowitego obrotu'', ale nasuwa się pytanie: W jakiej kolejności wykonywane są obroty wokół poszczególnych osi? Odpowiedzią jest: '''Z, Y, X''' wg współrzędnych świata. Jeżeli obracasz obiekt wokół więcej niż jednej osi na raz, używając reprezentacji ''Eulerowkiej'', musisz ustalić {{LSLG|vector|wektor}} ''Eulera'' używając porządku obrotów Z, Y, X, a następnie funkcji {{LSLG|llEuler2Rot}}, żeby uzyskać typ '''rotation''', niezbędny do składania obrotów, lub zastosowania obrotu na obiekcie.


== Local vs Global (World) rotations ==
== Obroty lokalne i globalne (wg współrzędnych świata) ==


It is important to distinguish between the '''rotation''' relative to the world, and the '''rotation''' relative to the local object itself. In the editor, you can switch back and forth from one to the other. In a script, you must convert from one to the other to get the desired behavior.
Ważne jest, aby rozróżniać obroty w układzie współrzędnych świata (globalnych) od tych w układzie współrzędnych obiektu (lokalnych). W edytorze można przełączać z jednego ukłądu na drugi i odwrotnie. W skrypcie trzeba dokonywać przekształceń celem uzyskania pożądanych efektów.  


'''Local''' rotations are ones done around the axes embedded in the object itself forward/back, left/right, up/down, irrespective of how the object is rotated in the world. '''Global''' rotations are ones done around the world axes, North/South, East/West, Higher/Lower. You can see the difference by rotating a prim, then edit it and change the axes settings between local and global, notice how the colored axes arrows change.
'''Lokalne''' obroty są dokonywane wokół osi przypisanych do obiektu: przód/tył, lewo/prawo i góra/dół, bez uwzględniania jak obiekt jest obrócony względem współrzędnych globalnych. '''Globalne''' obroty są dokonywane wokół osi świata: Północ/Południe, Wschód/Zachód, Wyżej/Niżej. Różnicę najłatwiej obserwować obracając prim'a, a następnie edytując go i zmieniając układ współrzędnych pomiędzy lokalnym i globalnym. Należy zwrócić uwagę jak zmieniają kolorowe strzałki wskaźnika.


In LSL, the difference between doing a '''local''' or '''global''' rotation is the order the '''rotations''' are evaluated in the statement.
W LSL'u rodzaj obrotu (lokalny czy globalny) jest określony przez kolejność w jakiej obroty są ustawione w wyrażeniu.


This does a '''local''' 30 degree rotation by putting the constant 30 degree '''rotation''' to the left of the object's starting '''rotation''' (myRot). It is like the first operation in the first example above, just twisting the dart 30 degrees around its own long axis.  
Przykład poniżej pokazuje '''lokalny''' obrót o 30 stopni. Jest to spowodowane kolejnością - stał '''obrót''' o 30 stopni jest po lewej stronie operatora a '''obrót''' startowy obiektu (myRot) po prawej. Ten przykład ilustruje pierwsze przekształcenie przypadku  I powyżej.  


<div id="box"><div style="padding: 0.5em">
<div id="box"><div style="padding: 0.5em">
{| cellpadding=0 cellspacing=0
{| cellpadding=0 cellspacing=0
|-
|-
|rotation localRot = ||rot30X * myRot;||// do a local rotation by multiplying a constant rotation by a world rotation
|rotation localRot = ||rot30X * myRot;||// wykonuje lokalny obrót przemnażając stały obrót przez obrót we współrzędnych świata
|}
|}
</div></div>
</div></div>


To do a '''global''' rotation, use the same '''rotation''' values, but in the opposite order. This is like the second operation in the second example, the dart rotating up and to the right around the world X axis. In this case, the existing rotation (myRot) is rotated 30 degrees around the global X axis.
Żeby wykonać obrót '''globalny''' należy użyć tych samych wartości, ale w odwrotnej kolejności. Jest to ilustracja drugiego przekształcenia z przypadku II powyżej


<div id="box"><div style="padding: 0.5em">
<div id="box"><div style="padding: 0.5em">
{| cellpadding=0 cellspacing=0
{| cellpadding=0 cellspacing=0
|-
|-
|rotation globalRot || = myRot * rot30X;||// do a global rotation by multiplying a world rotation by a constant rotation
|rotation globalRot || = myRot * rot30X;||// wykonuje globalny obrót przemnażając obrót we współrzędnych świata przez stały obrót
|}
|}
</div></div>
</div></div>


== Another way to think about combining rotations ==
== Inny sposób spojrzenia na obroty ==


You may want to think about this '''local''' vs '''global''' difference by considering that '''rotations''' are done in evaluation order, that is left to right except for parenthesized expressions.
Może być łatwiej zrozumieć obroty '''lokalne''' i '''globalne''' zauważając, że operacje obrotu są wykonywane w kolejności przetwarzania - od lewej do prawej, z wyjątkiem wyrażeń w nawiasach.


In the localRot case, what happened was that starting from <0, 0, 0>, the rot30X was done first, rotating the prim around the world X axis, but since when it's unrotated, the local and global axes are identical it has the effect of doing the rotation around the object's local X axis. Then the second '''rotation''' myRot was done which rotated the prim to its original rotation, but now with the additional X axis rotation baked in. What this looks like is that the prim rotated in place, around its own X axis, with the Y and Z rotations unchanged, a '''local''' rotation.
W powyższym skrypcie ustawiającym zmienną localRot, zaczynając od <0, 0, 0>, najpierw wykonany został obrót rot30X, co spowodowało obrót prim'a wokół osi X '''świata''', ale osie obiektu i świat pokrywały się, więc efekt jest identyczny z obrotem wokół osi obiektu. Nasepnie został wykonany '''obrót''' myRot, który przekształca obiekt do pozycji początkowej, ale z "wbudowanym" dodatkowym obrotem wokół osi X i niezmienionym położeniem osi Y i Z. W wyniku powstaje obrót '''lokalny'''


In the globalRot case, again starting from <0, 0, 0>, first the object is rotated to its original rotation (myRot), but now the object's axes and the world's axes are no longer aligned! So, the second '''rotation''' rot30x does exactly what it did in the local case, rotates the object 30 degrees around the world X axis, but the effect is to rotate the object through a cone around the world X axis since the object's X axis and the world's X axis aren't the same this time. What this looks like is that the prim pivoted 30 degrees around the world X axis, hence a '''global''' rotation.
W skrypcie z globalRot, znów zaczynamy od <0,0,0>, ale najpierw obiekt obracany jest o myRot, co powoduje, że osie świata i obiektu nie są już tożsame. Tak więc następny '''obrót''', rot30X (który wykonuje dokładnie to samo co poprzednio), działa na obiekt wokół osi X '''świata''', czego efektem jest poza obróceniem również przemieszczenie obiektu. Efektem końcowym jest obrót '''globalny'''


'''Division''' of '''rotations''' has the effect of doing the rotation in the opposite direction, multiplying by a 330 degree '''rotation''' is the same as dividing by a 30 degree '''rotation'''.
'''Dzielenie''' '''obrotów''' daje efekt wykonania obrotów w przeciwną stronę. Pomnożenie przez '''obrót''' o 330 stopni jest równoznaczne z podzielniem przez '''obrót''' o 30 stopni.


==Using Rotations ==
== Używanie obrotów ==


You can access the individual components of a '''rotation''' '''R''' by '''R.x, R.y, R.z, & R.s''' ('''not''' R.w). The scalar part R.s is the cosine of half the angle of rotation. The vector part (R.x,R.y,R.z) is the product of the normalized axis of rotation and the sine of half the angle of rotation. You can generate an inverse '''rotation''' by negating the x,y,z members (or by making the s value negative). As an aside, you can also use a '''rotation''' just as a repository of {{LSLG|float}} values, each '''rotation''' stores four of them and a {{LSLG|list}} consisting of '''rotation''' is more efficient than a {{LSLG|list}} consisting of {{LSLG|float}}s, but there is overhead in unpacking them.
Można uzyskać dostęp do poszczególnych składowych '''obrotu''' '''R''' używając konstrukcji '''R.x, R.y, R.z, & R.s''' ('''nie'''R.w). Część skalarna R.s jest cosinusem połowy kąta obrotu. Część wektorowa (R.x,R.y,R.z) jest iloczynem znormalizowanego wektora osi obrotu i sinusa połowy kąta obrotu. Można stworzyć '''obrót''' przeciwny albo poprzez zanegownie wszystkich trzech składowych x,y i z, albo przez zanegowanie składowej s. Można też używać typu '''rotation''' do przechowywania po prostu czterech wartości typu {{LSLG|float/pl|float}}. Ma to znaczenie w przypadku korzystania z {{LSLG|list/pl|list}}list. Lista zmiennych typu '''rotation''' jest bardziej wydajna pamięciowo niż lista złożona ze zmiennych typu {{LSLG|float/pl|float}}, ale oczywiście kosztuje więcej cykli procesora przy "rozpakowywaniu".


<div id="box"><div style="padding: 0.5em">
<div id="box"><div style="padding: 0.5em">
{| cellpadding=0 cellspacing=0
{| cellpadding=0 cellspacing=0
|-
|-
|rotation rot30X ||= {{LSLG|llEuler2Rot}}(<30, 0, 0> * [[#DEG_TO_RAD|DEG_TO_RAD]] );||// Create a rotation constant
|rotation rot30X ||= {{LSLG|llEuler2Rot}}(<30, 0, 0> * [[#DEG_TO_RAD|DEG_TO_RAD]] );||// Tworzy stałą typu rotation
|-
|-
|rotation rotCopy ||= rot30X;||// Just copy it into rotCopy, it copies all 4 float components
|rotation rotCopy ||= rot30X;||// Kopiuje ją do zmiennej rotCopy, kopiując wszystkie cztery składowe.
|-
|-
|float X ||= rotCopy.x;||// Get out the individual components of the rotation
|float X ||= rotCopy.x;||// Wyciąga poszczególne składowe obrotu
|-
|-
|float Y ||= rotCopy.y;||
|float Y ||= rotCopy.y;||
Line 112: Line 112:
|float S ||= rotCopy.s;||
|float S ||= rotCopy.s;||
|-
|-
|rotation anotherCopy ||= <X, Y, Z, S>;||// Make another rotation out of the components
|rotation anotherCopy ||= <X, Y, Z, S>;||// tworzy inny obrót z tych składowych
|}
|}
</div></div>
</div></div>




There is a built in constant for a zero '''rotation''' [[#ZERO_ROTATION|ZERO_ROTATION]] which you can use directly or, if you need to invert a '''rotation R''', divide [[#ZERO_ROTATION|ZERO_ROTATION]] by '''R'''. As a reminder from above, this works by first rotating to the zero position, then because it is a divide, rotating in the opposite sense to the original  '''rotation''', thereby doing the inverse rotation.
Istnieje wbudowana stała '''obrót''' zerowy [[#ZERO_ROTATION|ZERO_ROTATION]], której można użyć bezpośrednio, lub jeżeli potrzbujesz odwrócić '''obrót R''', podziel [[#ZERO_ROTATION|ZERO_ROTATION]] przez '''R'''. Przypominając rozważania z poprzednich akapitów, mechanizm jest tu następujący: Najpierw wykonywany jest obrót zerowy, potem dzielenie (które daje obrót przeciwny) przez obrót '''R'''
<div id="box"><div style="padding: 0.5em">
<div id="box"><div style="padding: 0.5em">
{| cellpadding=0 cellspacing=0
{| cellpadding=0 cellspacing=0
|-
|-
|rotation rot330X ||= <-rot30X.x, -rot30X.y, -rot30X.z, rot30X.s>;||// invert a rotation - NOTE the s component isn't negated
|rotation rot330X ||= <-rot30X.x, -rot30X.y, -rot30X.z, rot30X.s>;||// obrót przeciwny - UWAGA składowa s nie została zanegowana
|-
|-
|rotation another330X ||= [[#ZERO_ROTATION|ZERO_ROTATION]] / rot30X;||// invert a rotation by  division, same result as rot330X
|rotation another330X ||= [[#ZERO_ROTATION|ZERO_ROTATION]] / rot30X;||// obrót przeciwny wykonany dzieleniem, taki sam rezultat jak wyżej
|-
|-
|rotation yetanother330X ||= <rot30X.x, rot30X.y, rot30X.z, -rot30X.s>;||// not literally the same but works the same.
|rotation yetanother330X ||= <rot30X.x, rot30X.y, rot30X.z, -rot30X.s>;||// Nie dokładnie to samo, ale taki sam efekt.
|}
|}
</div></div>
</div></div>


==Single or Root Prims vs Linked Prims vs Attachments ==
== Pojedyncze lub główne primy a primy dołączone a dostawki (attachments) ==
 
Niektóre rzeczy, jak na przykład drzwi pojazdów, powinny obracać się względem pojazdu, niezależnie od tego, jak ustawiony jest sam pojazd. Można to zrobić obrotami globalnymi, ale jest to męczące i nudne.
Z tego powodu istnieją trzy układy współrzędnych w których prim może być obracany: pojedynczy prim, dołączony do {{LSLG|linkset|zestawu}}, lub będący {{LSLG|attachment|dostawką }}. Prim będący głównym w {{LSLG|linkset|zestawie}} zachowuje się jak pojedyńczy. Prim będący {{LSLG|linkset|dostawką}} zachowuje się inaczej niż pozostałe i nie zawsze działa poprawnie


The reason for talking about single or linked prim rotations is that for things like doors on vehicles, the desired motion is to move the door relative to the vehicle, no matter what the rotation of the overall vehicle is. While possible to do this with global rotations, it would quickly grow tedious.
There are generally three coordinate systems a prim can be in: all alone, part of a {{LSLG|linkset}}, or part of an {{LSLG|attachment}}. When a prim is alone, i.e., not part of a {{LSLG|linkset}}, it acts like a root prim; when it is part of an {{LSLG|attachment}}, it acts differently and is a bit broken.


{{LSLRotGetSet}}
{{LSLRotGetSet}}


==Rotating Vectors ==
==Obracanie wektorów ==


In LSL, rotating a {{LSLG|vector}} is very useful if you want to move an object in an arc or circle when the center of rotation isn't the center of the object.
Obracanie wektorów może być potrzebne w przypadku poruszania obiektu (używając LSL'a) po okręgu lub łuku, jeżeli oś obrotu nie jest osią tego obiektu.


This sounds very complex, but there is much less here than meets the eye. Remember from the above discussion of rotating the [[#Combining Rotations|dart]], and replace the physical dart with a {{LSLG|vector}} whose origin is the tail of the dart, and whose components in X, Y, and Z describe the position of the tip of the dart. Rotating the dart around its tail moves the tip of the dart through and arc whose center of rotation is the tail of the dart. In exactly the same way, rotating a {{LSLG|vector}} which represents an offset from the center of a prim rotates the prim through the same arc. What this looks like is the object rotates around a position offset by the {{LSLG|vector}} from the center of the prim.
Może to brzmieć skomplikowanie, ale tylko pozornie. Wystarczy [[#Składanie obrotów|rzutkę]] z przykładów wyżej zamienić na {{LSLG|vector|wektor}}, którego początkiem są pióra rzutki a współrzędne X,Y i Z to położenie jej szpica. Obracanie rzutki wokół końca przesuwa szpic w stożku, którego wierzchołkiem są pióra rzutki. W dokładnie ten sam sposób obracanie {{LSLG|vector|wektor'a}}, który reprezentuje przesunięcie względem środka obiektu (prim'a), obraca prim w takim samym stożku. Daje to taki efekt, że środek prim'a przesunięty o {{LSLG|vector|wektor}} staje się przecięciem osi obrotów.
<div id="box"><div style="padding: 0.5em">
<div id="box"><div style="padding: 0.5em">
{| cellpadding=0 cellspacing=0
{| cellpadding=0 cellspacing=0
|-
|-
|rotation rot6X ||= {{LSLG|llEuler2Rot}}(<30, 0, 0> * [[#DEG_TO_RAD|DEG_TO_RAD]] );||// create a rotation constant, 30 degrees around the local X axis
|rotation rot6X ||= {{LSLG|llEuler2Rot}}(<30, 0, 0> * [[#DEG_TO_RAD|DEG_TO_RAD]] );||// Tworzy stałą typu obrót o wartości 30 stopni dookoła lokalnej osi X
|-
|-
|vector offset ||= <0, 1, 0>;||// create an offset one meter in the global positive Y direction
|vector offset ||= <0, 1, 0>;||// Tworzy przesunięcie o jeden metr w kierunku dodatnim globalnej osi Y
|-
|-
|vector rotatedOffset || = offset * rot6X;||// rotate the offset to get the motion caused by the rotations
|vector rotatedOffset || = offset * rot6X;||// Obraca przesunięcie, żeby uzyskać ruch spowodowany przez obroty
|-
|-
|vector newPos || = {{LSLG|llGetPos}}() + (offset - rotatedOffset) * {{LSLG|llGetRot}}();||// move the prim position by the rotated offset amount
|vector newPos || = {{LSLG|llGetPos}}() + (offset - rotatedOffset) * {{LSLG|llGetRot}}();||// przesuwa obiekt w położenie odpowiadające obróconemu przesunięciu
|-
|-
|rotation newRot|| = rot6X * {{LSLG|llGetRot}}();||// change rot to continue facing offset point
|rotation newRot|| = rot6X * {{LSLG|llGetRot}}();||// zmienia rot, tak żeby dalej był zwrócony w stronę punktu przesunięcia
|}
|}
</div></div>
</div></div>
<lsl>
<lsl>
//-- same as:
//-- Te same efekty daje:
llSetPrimitiveParams( [PRIM_POSITION, llGetPos() + (gPosOffset - gPosOffset * gRotArc) * llGetRot(),
llSetPrimitiveParams( [PRIM_POSITION, llGetPos() + (gPosOffset - gPosOffset * gRotArc) * llGetRot(),
                       PRIM_ROTATION, gRotArc * llGetRot() );
                       PRIM_ROTATION, gRotArc * llGetRot() );
</lsl>
</lsl>
'''Nota Bene:''' Doing this is a move, so don't forget about issues of moving a prim off world, below ground, more than 10 meters etc.
'''Nota Bene:''' Wykonanie takiego skryptu daje w efekcie ruch, więc należy rozważyć takie konsekwencje jak wyrzucenie obiektu poza świat, pod ziemię, lub dalej niż 10 metrów itd.


To get a point relative to the objects current facing (such as used in rezzors)
Żeby uzyskać przesunięcie względem aktualnego przodu obiektu (np. w rezzor'ach) można użyć następującej konstrukcji
<div id="box"><div style="padding: 0.5em">
<div id="box"><div style="padding: 0.5em">
{| cellpadding=0 cellspacing=0
{| cellpadding=0 cellspacing=0
|-
|-
|rotation rotFacing ||= {{LSLG|llGetRot}}();||// get the objects current rotation
|rotation rotFacing ||= {{LSLG|llGetRot}}();||// pobiera obecny obrót obiektu
|-
|-
|vector offset ||= <0, 0, 1>;||// create an offset one meter in the global positive Z direction
|vector offset ||= <0, 0, 1>;||// tworzy przesunięcie o 1m w dodatnim kierunku globalnej osi Z
|-
|-
|vector rotatedOffset || = offset * rotFacing;||// rotate the offset to be relative to object rotation
|vector rotatedOffset || = offset * rotFacing;||// obraca przesunięcie tak, by było względem rotacji obiektu
|-
|-
|vector correctOffset || = {{LSLG|llGetPos}}() + rotatedOffset;||// get the global position of the local offset
|vector correctOffset || = {{LSLG|llGetPos}}() + rotatedOffset;||// odczytuje globalne położenie lokalnego przesunięcia
|}
|}
</div></div>
</div></div>
<lsl>
<lsl>
//-- same as:
//-- to samo co:
vector correctOffset = llGetPos() + offset * llGetRot();
vector correctOffset = llGetPos() + offset * llGetRot();
</lsl>
</lsl>


== Constants ==
== Stałe ==
=== [[ZERO_ROTATION]] ===
=== [[ZERO_ROTATION]] ===
ZERO_ROTATION = <0.0, 0.0, 0.0, 1.0>;<br/>
ZERO_ROTATION = <0.0, 0.0, 0.0, 1.0>;<br/>
A rotation constant representing a Euler angle of <0.0, 0.0, 0.0>.
Stała typu rotation reprezentująca kąt Euler'a <0.0, 0.0, 0.0>.


=== [[DEG_TO_RAD]] ===
=== [[DEG_TO_RAD]] ===
DEG_TO_RAD = 0.01745329238f;<br/>
DEG_TO_RAD = 0.01745329238f;<br/>
A float constant that when multiplied by an angle in degrees gives the angle in radians.
Stała typu float, która pomnożona przez kat w stopniach da kąt w radianach.


=== [[RAD_TO_DEG]] ===
=== [[RAD_TO_DEG]] ===
RAD_TO_DEG = 57.29578f;<br/>
RAD_TO_DEG = 57.29578f;<br/>
A float constant when multiplied by an angle in radians gives the angle in degrees.
Stała typu float, która pomnożona przez kat w radianach da kąt w stopniach.
 


[[Category:LSL_Types|Rotation]][[Category:LSL_Math]][[Category:LSL_Math/3D]][[Category:LSL_Constants]]
[[Category:LSL_Types/pl|Rotation]][[Category:LSL_Math/pl]][[Category:LSL_Math/3D/pl]][[Category:LSL_Constants/pl]]

Latest revision as of 02:59, 25 March 2008

Obroty

LSL'owy typ rotation jest używany do przedstawienia trójwymiarowej orientacji. Orientacja jest reprezentowana przez pojęcie matematyczne nazywane kwaternionem. Można myśleć o kwaternionie jako o czterech liczbach, z których pierwsze trzy reprezentują kierunek w którym obiekt jest skierowany (rozumiany jako wektor 3D), a czwarta z nich to nachylenie (kąt obrotu) w lewo lub w prawo w płaszczyźnie normalnej (prostopadłej) do kierunku skierowania. Podstawową zaletą kwaternionów jest to, ze nie powodują one błędów typu gimbal lock (związanych z równoległością prostych w przestrzeni trójwymiarowej). Jeżeli chcesz zapoznać się ze szczegółami matematycznymi, zobacz kwaternion. Rotation Synopsis to lista użytecznych funkcji i zdarzeń (events) odnoszących się do obrotów. Jest też informacja o obracaniu tekstur, tutaj

Inne reprezentacje

Innym sposobem przedstawienia obrotów jest użycie trzech liczb, <X, Y, Z>, które reprezentują kąty (wyrażone w radianach) o które obiekt jest obracany dookoła każdej z osi. Ten rodzaj przedstawienia używany jest w okienku Edycji, i jest generalnie łatwy w wizualizacji. Uwaga, te trzy liczby to typ vector a nie rotation, choć reprezentują tę samą informację. Ten sposób przedstawienia rotacji nazywamy Eulerowskim.

Trzecim rodzajem reprezentacji jest użycie trzech wektorów, wskazujących gdzie jest skierowany przód, góra i lewa strona obiektu. W rzeczywistości potrzebne są tylko dwa z trzech wektorów, ponieważ z dowolnych dwóch da się trzeci wyliczyć.

Z pewnych powodów, takich jak np. możliwość składania obrotów, cztero-liczbowa wersja, rotation, jest lepsza, chociaż na początku może być trudniejsza to wyobrażenia sobie. Na szczęście bardzo rzadko występuje konieczność posługiwania się wewnętrzną reprezentacją obrotów, ponieważ są funkcje konwertujące różne sposoby reprezentacji.

Reguła prawej dłoni

W LSL'u wszystkie obroty są wykonywane zgodnie z regułą prawej dłoni. Ustawiamy dłoń z palcami wyprostowanymi wzdłuż osi OX. Następnie zginamy palce, z wyjątkiem kciuka, wskazując zwrot osi OY. Odwiedziny kciuk wskazuje zwrot osi OZ w układzie prawoskrętnym. Podczas edycji obiektu trzy kolorowe strzałki wskazują dodatni kierunek każdej osi (X: czerwona, Y: zielona, Z: niebieska).

Reguła Prawej Dłoni

Prawa ręka jeszcze się przyda, do ustalenia kierunku dodatniego obrotu. Palce pięści prawej dłoni, z kciukiem ustawionym w osi obrotu który nas interesuje, wskazują kierunek dodatnigo obrotu wokół tej osi. Obroty wzdłuż osi X, Y i Z są często określane jako "beczka", "nurkowanie" i "zboczenie" (Roll, Pitch, and Yaw), sczególnie dotyczy to pojazdów.

Kierunek obrotów wg Reguły Prawej Dłoni

Składanie obrotów

Do składania obrotów używa się operatorów mnożenia i dzielenia. Nie należy używać dodawania i odejmowania dla obrotów, ponieważ nie dają one spodziewanych rezultatów. Mnożenie obraca w kierunku dodatnim, podczas gdy dzielenie w kierunku ujemnym. Można też odwrócić obrót bezpośrednio, poprzez pomnożenie składowej S przez -1. Np. X.s = -X.s.

W przeciwieństwie do innych typów, np. float, kolejność wykonywania obrotów ma znaczenie.(non-commutative). Spowodowane jest to prostym zjawiskiem - W RL'u kolejność w jakiej wykonuje się obroty również ma znaczenie. Jeżeli weźmiemy rzutkę (strzałkę) z czterema piórami, z początkowym obrotem <0, 0, 0>, której tylna część jest punktem zero, będzie ona leżała wzdłuż osi X, skierowana szpicem w kierunku dodatnim, z piórami wzdłuż osi Z i Y. Osie rzutki i osie świata są równoległe. Obrócimy teraz naszą rzutkę o 45 stopni dookoła osi X i 30 stopnia dookoła osi Y dwa razy, zmieniając kolejność.

Przypadek I: Po obróceniu o 45 stopni dookoła osi X, rzutka dalej leży na tej osi, tylko z piórami pod kątem 45 stopni do osi Z i Y. Obrócenie rzutki o 30 stopni dookoła osi Y przesunie ją w płaszczyźnie XZ, tak by czubek był odchylony o 30 stopni od osi X w dół (wg reguły prawej dłoni, małe wartości obrotu wokół osi Y opuszczają czubek w dół). Rzutka jest teraz skierowana pod kątem 30 stopni w dół, w tej samej płaszczyźnie pionowej, obrócona wokół swojej długiej osi, tak że pióra nie są już skierowane pionowo i poziomo.

Przypadek II:

Jeżeli wykonamy te same obroty w odwrotnej kolejności, czyli najpierw o 30 stopni wokół Y, rzutka obróci się w dół w płaszczyźnie XZ i nie będzie już leżała na osi X. Układy współrzędnych rzutki i świata nie są już równoległe. Teraz obrót o 45 stopni dookoła osi X spowoduje że tył strzałki pozostanie w miejscu, a czubek będzie nachylony w górę i w prawo pod kątem 30 i 45 stopni względem odpowiednich osi. Pióra rzutki nie są obrócone względem osi długiej rzutki.

W oczywisty sposób efekty końcowe różnią się, chociaż jedyną różnicą jest kolejność przekształceń.

Stałą typu rotation można utworzyć przez stworzenie wektora z wartościami X, Y, Z składowych obrotu wyrażonych w radianach (tzw. kąt Euler'a) a następnie zmieniając go w typ rotation używając funkcji llEuler2Rot. Można też stworzyć wartość typu rotation bezpośrednio: Część rzeczywista to cosinus połowy kąta obrotu, część wektorowa jest znormalizowaną osią obrotu pomnożoną przez sinus połowy kąta obrotu. Do przekształcenia typu rotation na kąt Eulera typu vector służy funkcja llRot2Euler.

UWAGA: Kąty w LSL'u są wyrażane w radianach a nie w stopniach, ale można użyć predefiniowanych stałych RAD_TO_DEG i DEG_TO_RAD. Żeby uzyskać trzydziestopniową wartość typu rotation dookoła osi X axis można użyć następującej konstrukcji:

rotation rot30X = llEuler2Rot(<30, 0, 0> * DEG_TO_RAD); // zminia stopnie na radiany a potem wektor w obrót: rot30x
vector vec30X = llRot2Euler(rot30X ); // zmienia obrót z powrotem w wektor (wartości kątów będą w radianach)

Kolejność obrotów dla wektorów Eulera

Z powyższych rozważań wynika jasno, żę kiedy obracamy obiekty wokół więcej niż jednej osi, kolejność tych obrotów ma zasadnicze znaczenie. Ten temat został ominięty przy traktowaniu wektora Eulerowskiego jako całkowitego obrotu, ale nasuwa się pytanie: W jakiej kolejności wykonywane są obroty wokół poszczególnych osi? Odpowiedzią jest: Z, Y, X wg współrzędnych świata. Jeżeli obracasz obiekt wokół więcej niż jednej osi na raz, używając reprezentacji Eulerowkiej, musisz ustalić wektor Eulera używając porządku obrotów Z, Y, X, a następnie funkcji llEuler2Rot, żeby uzyskać typ rotation, niezbędny do składania obrotów, lub zastosowania obrotu na obiekcie.

Obroty lokalne i globalne (wg współrzędnych świata)

Ważne jest, aby rozróżniać obroty w układzie współrzędnych świata (globalnych) od tych w układzie współrzędnych obiektu (lokalnych). W edytorze można przełączać z jednego ukłądu na drugi i odwrotnie. W skrypcie trzeba dokonywać przekształceń celem uzyskania pożądanych efektów.

Lokalne obroty są dokonywane wokół osi przypisanych do obiektu: przód/tył, lewo/prawo i góra/dół, bez uwzględniania jak obiekt jest obrócony względem współrzędnych globalnych. Globalne obroty są dokonywane wokół osi świata: Północ/Południe, Wschód/Zachód, Wyżej/Niżej. Różnicę najłatwiej obserwować obracając prim'a, a następnie edytując go i zmieniając układ współrzędnych pomiędzy lokalnym i globalnym. Należy zwrócić uwagę jak zmieniają kolorowe strzałki wskaźnika.

W LSL'u rodzaj obrotu (lokalny czy globalny) jest określony przez kolejność w jakiej obroty są ustawione w wyrażeniu.

Przykład poniżej pokazuje lokalny obrót o 30 stopni. Jest to spowodowane kolejnością - stał obrót o 30 stopni jest po lewej stronie operatora a obrót startowy obiektu (myRot) po prawej. Ten przykład ilustruje pierwsze przekształcenie przypadku I powyżej.

rotation localRot = rot30X * myRot; // wykonuje lokalny obrót przemnażając stały obrót przez obrót we współrzędnych świata

Żeby wykonać obrót globalny należy użyć tych samych wartości, ale w odwrotnej kolejności. Jest to ilustracja drugiego przekształcenia z przypadku II powyżej

rotation globalRot = myRot * rot30X; // wykonuje globalny obrót przemnażając obrót we współrzędnych świata przez stały obrót

Inny sposób spojrzenia na obroty

Może być łatwiej zrozumieć obroty lokalne i globalne zauważając, że operacje obrotu są wykonywane w kolejności przetwarzania - od lewej do prawej, z wyjątkiem wyrażeń w nawiasach.

W powyższym skrypcie ustawiającym zmienną localRot, zaczynając od <0, 0, 0>, najpierw wykonany został obrót rot30X, co spowodowało obrót prim'a wokół osi X świata, ale osie obiektu i świat pokrywały się, więc efekt jest identyczny z obrotem wokół osi obiektu. Nasepnie został wykonany obrót myRot, który przekształca obiekt do pozycji początkowej, ale z "wbudowanym" dodatkowym obrotem wokół osi X i niezmienionym położeniem osi Y i Z. W wyniku powstaje obrót lokalny

W skrypcie z globalRot, znów zaczynamy od <0,0,0>, ale najpierw obiekt obracany jest o myRot, co powoduje, że osie świata i obiektu nie są już tożsame. Tak więc następny obrót, rot30X (który wykonuje dokładnie to samo co poprzednio), działa na obiekt wokół osi X świata, czego efektem jest poza obróceniem również przemieszczenie obiektu. Efektem końcowym jest obrót globalny

Dzielenie obrotów daje efekt wykonania obrotów w przeciwną stronę. Pomnożenie przez obrót o 330 stopni jest równoznaczne z podzielniem przez obrót o 30 stopni.

Używanie obrotów

Można uzyskać dostęp do poszczególnych składowych obrotu R używając konstrukcji R.x, R.y, R.z, & R.s (nieR.w). Część skalarna R.s jest cosinusem połowy kąta obrotu. Część wektorowa (R.x,R.y,R.z) jest iloczynem znormalizowanego wektora osi obrotu i sinusa połowy kąta obrotu. Można stworzyć obrót przeciwny albo poprzez zanegownie wszystkich trzech składowych x,y i z, albo przez zanegowanie składowej s. Można też używać typu rotation do przechowywania po prostu czterech wartości typu float. Ma to znaczenie w przypadku korzystania z listlist. Lista zmiennych typu rotation jest bardziej wydajna pamięciowo niż lista złożona ze zmiennych typu float, ale oczywiście kosztuje więcej cykli procesora przy "rozpakowywaniu".

rotation rot30X = llEuler2Rot(<30, 0, 0> * DEG_TO_RAD ); // Tworzy stałą typu rotation
rotation rotCopy = rot30X; // Kopiuje ją do zmiennej rotCopy, kopiując wszystkie cztery składowe.
float X = rotCopy.x; // Wyciąga poszczególne składowe obrotu
float Y = rotCopy.y;
float Z = rotCopy.z;
float S = rotCopy.s;
rotation anotherCopy = <X, Y, Z, S>; // tworzy inny obrót z tych składowych


Istnieje wbudowana stała obrót zerowy ZERO_ROTATION, której można użyć bezpośrednio, lub jeżeli potrzbujesz odwrócić obrót R, podziel ZERO_ROTATION przez R. Przypominając rozważania z poprzednich akapitów, mechanizm jest tu następujący: Najpierw wykonywany jest obrót zerowy, potem dzielenie (które daje obrót przeciwny) przez obrót R

rotation rot330X = <-rot30X.x, -rot30X.y, -rot30X.z, rot30X.s>; // obrót przeciwny - UWAGA składowa s nie została zanegowana
rotation another330X = ZERO_ROTATION / rot30X; // obrót przeciwny wykonany dzieleniem, taki sam rezultat jak wyżej
rotation yetanother330X = <rot30X.x, rot30X.y, rot30X.z, -rot30X.s>; // Nie dokładnie to samo, ale taki sam efekt.

Pojedyncze lub główne primy a primy dołączone a dostawki (attachments)

Niektóre rzeczy, jak na przykład drzwi pojazdów, powinny obracać się względem pojazdu, niezależnie od tego, jak ustawiony jest sam pojazd. Można to zrobić obrotami globalnymi, ale jest to męczące i nudne. Z tego powodu istnieją trzy układy współrzędnych w których prim może być obracany: pojedynczy prim, dołączony do zestawu, lub będący dostawką . Prim będący głównym w zestawie zachowuje się jak pojedyńczy. Prim będący dostawką zachowuje się inaczej niż pozostałe i nie zawsze działa poprawnie


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.

Obracanie wektorów

Obracanie wektorów może być potrzebne w przypadku poruszania obiektu (używając LSL'a) po okręgu lub łuku, jeżeli oś obrotu nie jest osią tego obiektu.

Może to brzmieć skomplikowanie, ale tylko pozornie. Wystarczy rzutkę z przykładów wyżej zamienić na wektor, którego początkiem są pióra rzutki a współrzędne X,Y i Z to położenie jej szpica. Obracanie rzutki wokół końca przesuwa szpic w stożku, którego wierzchołkiem są pióra rzutki. W dokładnie ten sam sposób obracanie wektor'a, który reprezentuje przesunięcie względem środka obiektu (prim'a), obraca prim w takim samym stożku. Daje to taki efekt, że środek prim'a przesunięty o wektor staje się przecięciem osi obrotów.

rotation rot6X = llEuler2Rot(<30, 0, 0> * DEG_TO_RAD ); // Tworzy stałą typu obrót o wartości 30 stopni dookoła lokalnej osi X
vector offset = <0, 1, 0>; // Tworzy przesunięcie o jeden metr w kierunku dodatnim globalnej osi Y
vector rotatedOffset = offset * rot6X; // Obraca przesunięcie, żeby uzyskać ruch spowodowany przez obroty
vector newPos = llGetPos() + (offset - rotatedOffset) * llGetRot(); // przesuwa obiekt w położenie odpowiadające obróconemu przesunięciu
rotation newRot = rot6X * llGetRot(); // zmienia rot, tak żeby dalej był zwrócony w stronę punktu przesunięcia

<lsl> //-- Te same efekty daje: llSetPrimitiveParams( [PRIM_POSITION, llGetPos() + (gPosOffset - gPosOffset * gRotArc) * llGetRot(),

                      PRIM_ROTATION, gRotArc * llGetRot() );

</lsl> Nota Bene: Wykonanie takiego skryptu daje w efekcie ruch, więc należy rozważyć takie konsekwencje jak wyrzucenie obiektu poza świat, pod ziemię, lub dalej niż 10 metrów itd.

Żeby uzyskać przesunięcie względem aktualnego przodu obiektu (np. w rezzor'ach) można użyć następującej konstrukcji

rotation rotFacing = llGetRot(); // pobiera obecny obrót obiektu
vector offset = <0, 0, 1>; // tworzy przesunięcie o 1m w dodatnim kierunku globalnej osi Z
vector rotatedOffset = offset * rotFacing; // obraca przesunięcie tak, by było względem rotacji obiektu
vector correctOffset = llGetPos() + rotatedOffset; // odczytuje globalne położenie lokalnego przesunięcia

<lsl> //-- to samo co: vector correctOffset = llGetPos() + offset * llGetRot(); </lsl>

Stałe

ZERO_ROTATION

ZERO_ROTATION = <0.0, 0.0, 0.0, 1.0>;
Stała typu rotation reprezentująca kąt Euler'a <0.0, 0.0, 0.0>.

DEG_TO_RAD

DEG_TO_RAD = 0.01745329238f;
Stała typu float, która pomnożona przez kat w stopniach da kąt w radianach.

RAD_TO_DEG

RAD_TO_DEG = 57.29578f;
Stała typu float, która pomnożona przez kat w radianach da kąt w stopniach.