Strona wykorzystuje ciasteczka by usprawnić komfort z jej korzystania. Korzystając ze strony akceptujesz naszą Politykę Ciasteczek. X

Podstawy Stage3D część III: korzystanie z rotacji [ekspert]

Kontynuując z poprzedniej części tutaj tym razem chce poruszyć temat łączenia rotacji. Każdy kto bez wcześniejszego kontaktu z 3D spróbował obrócić bryłę we Flash'owym Stage3D korzystając z funkcji appendRotation() na pewno prędzej czy później otrzymał wynik, którego się nie spodziewał. Do tego by jeszcze bardziej zniechęcić początkujących, w Internecie główną odpowiedział na owe zagadnienie jest "będziesz musiał skorzystać z liczb zespolonych (kwaternionów dokładnie)". Hmm? Dobra, nie wiem jak bardzo liczby zespolone przydają się do wyliczania obrotu, ale jeśli do rotacji 2D nie potrzebne są obliczenia 3D, to i zapewne w obrocie 3D da się przeżyć bez operacji 4D, a już szczególnie jeśli dopiero zaczynamy poruszać ten temat.
W każdy bądź razie, przejdźmy do sedna sprawy zaczynając od kodu z poprzedniego artykułu: Tutorial3D-2.zip, najpierw usuńmy wszystkie sześciany zostawiając tylko jedno pudełko, reszta nie będzie nam potrzebna. Przy okazji dodać można jeszcze zmienne do przechowywania jednego Vector3D i jednej Matrix3D - przydadzą się później.
Generalnie rotacje można dodać na dwa sposoby: lokalnie i globalnie - innymi słowy biorąc pod uwagę już istniejący obrót lub nie. Jakikolwiek sposób wybierzemy należy pamiętać, że na transformacje ma jeszcze wpływ istniejące przesunięcie, dlatego by ułatwić sobie pracę dobrze jest trzymać samą rotację w osobnej macierzy, a potem ją dodawać do transformacji naszego pudełka 3D. Tak więc zacznijmy od rotacji globalnej oraz utworzenia dodatkowej matrycy (jeśli jeszcze tego nie zrobiłeś):
private var rotMat:Matrix3D = new Matrix3D();
Następnie zmodyfikujemy kod odpowiedzialny za obsługę strzałek klawiatury tak by teraz dodawał obrót do matrycy rotMat:
switch(key&0x0000ff) {
	case 0x00000f: // forward
		rotMat.appendRotation(SPEED, Vector3D.X_AXIS);
		break;
	case 0x0000f0: // backward
		rotMat.appendRotation(-SPEED, Vector3D.X_AXIS);
		break;
}
switch(key&0x00ff00) {
	case 0x000f00: // left
		rotMat.appendRotation(SPEED, Vector3D.Y_AXIS);
		break;
	case 0x00f000: // right
		rotMat.appendRotation(-SPEED, Vector3D.Y_AXIS);
		break;
}
W tym momencie pozostaje nam już tylko dodać rotacje do obiektu sześcianu box3D zanim zostanie utworzona ostateczna transformacja w matrycy finalTransform:
var boxMat:Matrix3D = box3D.getMatrix3D();
boxMat.identity();
boxMat.append(rotMat);
W efekcie dostając:
Żeby uczynić ten przykład nieco ciekawszym i przy okazji sprawdzić, że faktycznie rotacja będzie niezależna od pozycji, możemy wykorzystać wcześniej wspomniany Vector3D. Nazwijmy go:
private var posVec:Vector3D = new Vector3D();
Jego manipulacja nie powinna być problemem na tym poziomie, dlatego wspomnę tylko aby dodać jego wartości w odpowiednim miejscu - zaraz po linijce boxMat.append(rotMat); należy dopisać:
boxMat.appendTranslation(posVec.x, posVec.y, posVec.z);
Otrzymując:
Tak więc globalna rotacja nie była szczególnie skomplikowanym zagadnieniem, ale pozostaje jeszcze kwestia lokalnej transformacji. Na szczęście i tutaj rozwiązanie jest trywialne i sprowadza się tylko do znalezienia prawidłowych osi w obiekcie:
switch(key&0x0000ff) {
	case 0x00000f: // forward
		rotMat.appendRotation(SPEED, rotMat.transformVector(Vector3D.X_AXIS));
		posVec.y += SPEED/50;
		break;
	case 0x0000f0: // backward
		rotMat.appendRotation(-SPEED, rotMat.transformVector(Vector3D.X_AXIS));
		posVec.y -= SPEED/50;
		break;
}
switch(key&0x00ff00) {
	case 0x000f00: // left
		rotMat.appendRotation(SPEED, rotMat.transformVector(Vector3D.Y_AXIS));
		posVec.x -= SPEED/50;
		break;
	case 0x00f000: // right
		rotMat.appendRotation(-SPEED, rotMat.transformVector(Vector3D.Y_AXIS));
		posVec.x += SPEED/50;
		break;
}
Wektor X_AXIS zostanie przekształcony do lokalnego systemu obiektu, dzięki czemu będziemy wiedzieli gdzie ma oś X w około której następnie dokonamy obrotu. W rezultacie jedna z krawędzi obracanego sześcianu będzie pozostawać nieruchomo, zależnie od wybranej osi:
Kod źródłowy: Tutorial3D_rot.zip