Autor Wątek: Rzutowanie wektora na płaszczyznę  (Przeczytany 1997 razy)

Offline hashedone

  • Użytkownik

# Sierpień 09, 2010, 14:00:35
Witam,

mam problem natury matematycznej. Potrzebuję napisać funkcję rzutującą mi dany wektor na płaszczyznę, dla której mam wektor normalny (i później normalizującą ten wektor). Potrzebne mi to do wyznaczania wektora "w górę" przy definiowaniu obrotów. Wziąłem więc kartkę z długopisem, i zastanawiam się. Oznaczam: V - mój wektor, N - normalna płaszczyzny na którą rzutuję. Jeśli policzę sobie R = V x N, to będę miał już wektor prostopadły do N, a więc znajdujący się na mojej płaszczyźnie. Wektor którego szukam jest na pewno do wektora R prostopadły (wystarczy sobie to narysować i to widać), jest też prostopadły do wektora N (bo leży na mojej płaszczyźnie). Konkluzja prosta - szukany wektor T = R x N, lub wektor T = N x R. Teraz tylko wydedukować który z tych dwóch. Wiem że iloczyn wektorowy jest antysymetryczny, jeśli więc R = V x N, to żeby "zachować kierunek" wektora V, muszę mieć T = N x R (liczne testy dla różnych dziwnych przypadków potwierdziły moje przypuszczenia). Mamy więc T = N x (V x N) (bo iloczyn wektorowy nie jest łączny). Zabieram się za implementację. Mam klasę Vector3 o publicznych składowych:
Kod: (cpp) [Zaznacz]
float x, y, z;
I funkcję składową "robiącą" z wektora wektor "w górę" dla innego wektora (czyli rzutuje ten wektor prostokątnie na płaszczyznę, dla której mam daną normalną):
Kod: (cpp) [Zaznacz]
Vector3 MakeTop(const Vector3 & dir) const { return dir.Cross(Cross(dir)).Normalize(); }
Funkcja jest wywoływana na rzecz wektora który ma być rzutowany. Jeszcze funkcja Cross:
Kod: (cpp) [Zaznacz]
Vector3 Cross(const Vector3 & r) const
{
  return Vector3
  (
    y * r.z - z * r.y,
    z * r.x - x * r.z,
    x * r.y - y * r.z
  );
}
I żeby nie było że coś ukrywam - konstruktor używany w funkcji Cross:
Kod: (cpp) [Zaznacz]
Vector3(float _x, float _y, float _z): x(_x), y(_y), z(_z){ }

Funkcja nie działa. Wyciąg z mojego maina:
Kod: (cpp) [Zaznacz]
Vector3 dir(-1.f, 1.f, 1.f);
Vector3 top(0.f, 0.f, 1.f);
top = top.MakeTop(dir);
std::cout << top.x << ' ' << top.y << ' ' << top.z << '\n';
Wynik:
Kod: (dos) [Zaznacz]
0.57735 -0.57735 0.57735
Wg. mojego liczenia to jest wynik zły, poprawny brzmi: (sqrt(6) / 2; -sqrt(6) / 2; sqrt(6)). I to nie tylko moje zdanie (również kalkulatora). Gdzie jest błąd? W rozumowaniu matematycznym czy gdzieś w programie?

Offline Mr. Spam

  • Miłośnik przetworów mięsnych

Offline Kuba D.

  • Użytkownik

# Sierpień 09, 2010, 14:19:32
Vector3 Cross(const Vector3 & r) const
{
 return Vector3
 (
   y * r.z - z * r.y,
   z * r.x - x * r.z,
   x * r.y - y * r.z
 );
}
Nie przeglądałem dokładnie całości ale tu jest bug w ostatniej linijce ;) Zamiast y*r.z powinno być y*r.x.
« Ostatnia zmiana: Sierpień 09, 2010, 14:21:25 wysłana przez Kuba D. »

Offline hashedone

  • Użytkownik

# Sierpień 09, 2010, 14:26:46
Bóg Ci zapłać! Bug głupi a jak bardzo zmienia wyniki:D I właśnie w takich chwilach wychodzą konsekwencje podejścia: "Co? Błąd w wektorze? Że testy jednostkowe? A co to ja mam czasu za dużo?". Okazuje się że nawet w głupim Crossie można błąd zrobić.... :D

Offline Avaj

  • Użytkownik

# Sierpień 09, 2010, 23:19:36
Bóg Ci zapłać! Bug głupi a jak bardzo zmienia wyniki:D I właśnie w takich chwilach wychodzą konsekwencje podejścia: "Co? Błąd w wektorze? Że testy jednostkowe? A co to ja mam czasu za dużo?". Okazuje się że nawet w głupim Crossie można błąd zrobić.... :D
Dlatego się używa gotowych bibliotek, np GLM albo CML. Ja też kiedyś miałem po swojemu, ale po dwóch dniach straconych na zamianę - na + w mnożeniu macierzy się przerzuciłem ;]