Obliczanie współrzędnych kliknięcia (2D) w przestrzeni (3D)

December 10th, 2009 by Piotr Wierzgała Leave a reply »

Wpis pokazuje w jaki sposób przenieść punkt kliknięcia o jeden wymiar dalej czyli jak na podstawie współrzędnych ekranowych (2D) obliczyć współrzędne odpowiadającego im punktu w przestrzeni (3D).

FLEX: 3.0, Papervision3D: 2.0.883

Pobierz źródła przykładu

Poniższy kod napisałem w oparciu o tekst Andy’ego Zupko Dragging in 3D – The Right Way.

Zadanie przeniesienia współrzędnych kliknięcia do przestrzeni, w skrócie, będzie polegało na znalezieniu punktu przecięcia prostej z płaszczyzną. Prostą zdefiniujemy na podstawie współrzędnych położenia kamery oraz punktu kliknięcia. Płaszczyznę natomiast określimy jednoznacznie za pomocą wektora normalnego tożsamego z wektorem wyznaczającym kierunek spoglądania kamery oraz dowolnego punktu leżącego na tej płaszczyźnie.

Tym wszystkim zajmie się funkcja convert2Dto3D, której kod zamieszczam poniżej wraz z objaśnieniem:

Funkcja convert2Dto3D przyjmuje dwa parametry:
distance typu Number – Odległość od kamery w jakiej będzie znajdować się punkt w przestrzeni.
viewportClickPoint typu Number2D – Współrzędne kliknięcia w viewport (viewport.containerSprite.mouseX, viewport.containerSprite.mouseY).

private function convert2Dto3D(distance:Number,viewportClickPoint:Number2D):Number3D {         
    var unprojectedPoint:Number3D;
    var intersectPoint:Number3D;
    var plane3d:Plane3D = new Plane3D();
           
    var planeNormal: Number3D = forward.clone();
    Matrix3D.multiplyVector(camera.transform,planeNormal);
    planeNormal.normalize();
           
    var planeVertex:Number3D = planeNormal.clone();

    plane3d.setNormalAndPoint(planeNormal, planeVertex);
           
    unprojectedPoint= camera.unproject(viewportClickPoint.x,viewportClickPoint.y);
    unprojectedPoint= Number3D.add(unprojectedPoint, camera.position);
           
    intersectPoint= plane3d.getIntersectionLineNumbers(camera.position, unprojectedPoint);
    intersectPoint.normalize();
    intersectPoint.multiplyEq(distance);
       
    return intersectPoint;
}

Zdefiniowanie płaszczyzny
Zmienna planeNormal początkowo jest kopią wektora forward wyznaczającego kierunek “do przodu” czyli ten, w którym przez cały czas spogląda kamera:

private const forward: Number3D = new Number3D(0,0,-1);

Ponieważ możemy obracać kamerą wektor ten ulega zmianie zgodnie ze zmianą wartości kątów obrotu kamery. Żeby znać aktualny wektor wyznaczający kierunek w jakim spogląda kamera musimy pomnożyć wektor forward przez macierz transformacji kamery. Po wykonaniu operacji mnożenia normalizujemy otrzymany wektor.
Żeby jednoznacznie określić płaszczyznę w przestrzeni musimy jeszcze znać współrzędne dowolnego punktu leżącego na tej płaszczyźnie. W tym celu użyjemy współrzędnych obliczonego przed chwilą wektora, który możemy potraktować jako punkt leżący w satysfakcjonującym nas miejscu. Nie musimy przejmować się odległością w jakiej znajdzie się punkt przecięcia prostej z płaszczyzną ponieważ pod koniec skorygujemy ją sobie zgodnie z parametrem distance.

Zdefiniowanie prostej
Jednym z punktów, który posłuży do zdefiniowania prostej w przestrzeni będzie punkt położenia kamery. Drugim zaś punkt powstały przez zastosowanie metody unproject obiektu kamery na współrzędnych kliknięcia. Funkcja unproject wykonuje operację odwrotną do rzutowania (projekcji współrzędnych 3D na 2D) w wyniku, której otrzymujemy punkt 3D leżący na przedniej płaszczyźnie odcinania. Na koniec dodajemy do drugiego punktu współrzędne położenia kamery w celu uzyskania jego rzeczywistego położenia w przestrzeni.

Punkt przecięcia prostej i płaszczyzny
Punkt przecięcia prostej i płaszczyzny oblicza metoda getIntersectionLineNumbers obiektu Plane3D, która jako parametry przyjmuje dwa punkty definiujące prostą.

Korekcja współrzędnych punktu przecięcia
Założeniem naszej funkcji jest obliczanie współrzędnych 3D klikniętego punktu w odległości od kamery określonej przez parametr distance. W tym celu wystarczy znormalizować otrzymany punkt przecięcia i pomnożyć przez parametr distance.

Advertisement

Leave a Reply

Flexmaniaks on Facebook