[OpenGL] Animacja ruchu belki lokomotywy

0

Witam !
Na wszelki wypadek, chciałbym przeprosić, jeśli temat umieściłem w nie tym dziale co trzeba, ale nie znalazłem kategorii odnośnie grafiki komputerowej.
Przedstawiając mój problem, to mam zrobić animację w OpenGl przedstawiającą podwozie lokomotywy, które z geometrycznej perspektywy, składa się 1 głównego prostopadłościanu, 4 walców reprezentujących koła oraz 2 poruszających się belek w postaci prostopadłościanów. Generalnie największy problem mam właśnie z ruchem belki, która ma wykonywać charakterystyczną "ósemkę" (proszę nie patrzeć na sens fizyczny tego ruchu ;) ) - tzn. że gdy belka na jednym kole jest "na dole", to na drugim jest "na górze" i dwa końce belki zataczają kółka w dwie różne strony. Do rozwiązania swojego problemu postanowiłem po prostu zrobić przede wszystkim na belce transformacje przesunięcia, aby belka przesuwała się, robiąc końcami kółka, a za odpowiednie pochylenie belki miała posłużyć rotacja wokół osi naszej belki. I tutaj mam problem, że środek ciężkości mojej belki też się przesuwa i wektor określający oś wokół, której kręci się belka także się zmienia.

Jeszcze co do szczegółów - środek ciężkości znajduje się w punkcie (1.0f, 0.2f, 0.0f) po przesunięciu belki w odpowiednie miejsce. W ogóle to mam powoli dylemat, czy na początku powinienem dokonać translacji, czy rotacji (jakby co wiem, że to co wstawie w kodzie później, zrobi się szybciej, bo...macierze :) ).

Więc podsumowując uważam, że ruch "ósemkowy" powinien zostać osiągnięty poprzez prawidłowe złożenie dwóch ruchów:

  1. Ruch postępujący belki
 // Belka porusza się w płaszczyźnie określonej przez współrzędne y i z.
 GLfloat y = -0.2f + 0.15f * glm::cos((GLfloat)glfwGetTime() * glm::radians(-60.0f)); // -0.2f żeby krążyło wokół środka koła, 0.15f - promień
 GLfloat z = 0.15f * glm::sin((GLfloat)glfwGetTime() * glm::radians(-60.0f));
 model = glm::translate(model, glm::vec3(0.0f, y, z));
  1. Ruch powodujący odpowiednie nachylenie belki (rotacja):
 angle = 0.1f * glm::asin(sin((GLfloat)glfwGetTime() * glm::radians(-60.0f))); // ograniczony kąt obrotu
 model = glm::rotate(model, angle, glm::vec3(1.0f, 0.2f, 0.0f)); // bez ruchu postępującego to powoduje takie "wahanie" belki

Próbowałem już wiele kombinacji złożenia tego ruchu, ale nadal mam problem jak uwzględnić, że współrzędne y i z naszego środka ciężkości belki się zmieniają. Z góry dziękuje za wszelkie podpowiedzi.

1

Animacja ruchu belki lokomotywy

Ta „belka” nazywa się wiązar (łącząca koła ze sobą) i korbowód (łącząca tłok z wiązarem).

gdy belka na jednym kole jest "na dole", to na drugim jest "na górze"

Nie ma czegoś takiego. Jak by to miało jeździć? ;-)

0

Znaczy... Takie samo pytanie zadałem prowadzącemu projekt... A on odparł, że tu nie liczy się fizyka, tylko sobie taki ruch wymyślił, żeby utrudnić zadanie :)

1

Najprościej to

  1. Wyznaczyć punkt A i B, gdzie A to początek belki B jej koniec. Czyli dwa niezależne ruchy po okręgu.
  2. Wyznaczyć belkę na wektorze A i B, potrzebny do tego będzie wektor prostopadły do wektora AB.
    Jeżeli dobrze rozumiem założenia to belka powinna zmieniać swoją długość?
0

Znaczy nie zakładałem wstępnie, aby zmieniać długość belki, nawet o tym nie pomyślałem, ale po licznych próbach wydaje mi się że chyba to nieuniknione. A mógłbyś bardziej wyjaśnić swój pomysł ?

1

Ja bym zrobił tak:

  1. 2 belki A i B,
  2. Ustawiam punkt ciężkości(pivot) belek na jeden z końców,
  3. Rotuje każdą z belek tak by była pochylona o kąt między nią a punktem na drugim kole
  4. Przesuwam każdą z belek na odpowiednie koło,

po takim czymś belki powinny nachodzić na siebie równolegle i wyglądać to powinno jak tłok.

1

Problem sprowadza się do 2D więc, powiedzmy że masz koło o środku S(y, z) i promieniu R, oraz kąt obrotu T(w radianach). Wartość T posłuży do wyznaczenia punktu zaczepienia belki.
A.y = S.y + R * sin(T);
A.z = S.z + R * cos(T);
Zwiększanie T spowoduje przemieszczanie się punktu A po okręgu.
Analogicznie postępujemy z punktem B, różnica jest taka że T będziesz zmniejszać zamiast zwiększać (zmieni się kierunek obrotu).

Mamy już początek i koniec belki, potrzebujemy teraz nadać "grubość" belce czyli rozciągnąć ją w dwóch kierunkach prostopadłych do wektora AB. Wektor AB nazwijmy V, wektor prostopadły VP.
V normalizujemy (obliczamy jego długość i dzielimy każdą współrzędną przez tę wartość).
VP można wyznaczyć za pomocą iloczynu wektorowego. Ponieważ interesuje nas płaszczyzna YZ, użyjemy do tego wektora X(1,0,0)

Po przekształceniu VP:
VP.x = 0;
VP.y = V.z;
VP.z = -V.y;

Teraz chcemy żeby belka miała grubość L. Wyznaczamy 4 punkty (narożniki belki)

P0 = A + 0.5 * VP * L;
P1 = B + 0.5 * VP * L;
P2 = B - 0.5 * VP * L;
P3 = A - 0.5 * VP * L;

Teraz rysujesz prostokąt (P0, P1, P2, P3), lub dwa trójkąty : (P0, P1, P2), (P0, P2, P3)

0

Właśnie robiłem z dwoma belkami, ale mam nałożoną teksturę na belkę i słabo to wygląda...Wykombinowałem jednak coś innego, ale idealnie nie jest. Generalnie wykombinowałem sobie po prostu, że nachylenie belki będę osiągać poprzez obrót wokół jednego końca belki w płaszczyźnie określonej przez współrzędne x i y. Ruch "postępujący: dający nam okrążanie środka kół zachowany. Asin do ograniczenia kąta nachylenia. I było w miarę git, ale niestety po stronie drugiego końca belki, jej ruch jest za bardzo "skokowy", nie tak płynny jak przy końcu belki, wokół którego następował obrót. Czym to może być spowodowane ?
Kod:

glm::mat4 model4;
GLfloat angle = (GLfloat)glfwGetTime() * glm::radians(-45.0f); // kat do obrysowania kola
GLfloat deltaY = 0.15f * glm::cos(angle); // przemieszczenie
GLfloat y = -0.2f + deltaY;
GLfloat z = 0.15f * glm::sin(angle);
GLfloat angle2 = 0.05f * glm::asin(sin(angle)); // kat nachylenia
model4 = glm::translate(model4, glm::vec3(i * (-2.0f), 0.2f, 0.0f));
model4 = glm::translate(model4, glm::vec3(0.0f, y, z));
model4 = glm::translate(model4, glm::vec3(0.0f, 1.5f, 0.0f));
model4 = glm::rotate(model4, angle2, glm::vec3(1.0f, 0.0f, 0.0f));
model4 = glm::translate(model4, glm::vec3(0.0f, -1.5f, 0.0f)); 

EDIT:

Nie zauwazyłem rozwiązania @xxx_xx_x, którym postaram się zainspirować (i oczywiście bardzo za nie dziękuje), ale jakby ktoś wiedział co jest nie tak z kodem powyżej, to bym prosił o uwagi.

1 użytkowników online, w tym zalogowanych: 0, gości: 1