Grafika 3D - rzutowanie przestrzenne.


Przykładowy program używa jedynie klas Graphics2D i Line2D do wyświetlania grafiki. Widoczna na obrazku grafika rysowana jest w instancji klasy PanelRysunku dziedziczącej po klasie JPanel. Zatem problem polega na wizualizacji obiektu 3D na rysunek 2D.
Poniżej przedstawiony jest kod odpowiedzialny za obliczenie współrzędnych z układu 3D na układ 2D. 


 double x2D = (x3D * wielkosc) / (z3D - 600) + srodekX2D;
 double y2D = (y3D * wielkosc) / (z3D - 600) + srodekY2D;


w celu zdefiniowania dowolnej bryły w przestrzeni 3D najlepiej podawać punkty tak aby punkt 0 (X=0, Y=0, Z=0) znajdował się w jej środku. Zapewni to obrót bryły wokół jej osi.
Przykład dla figury sześcian - punkty:
P1: X=-20 Y=-20 Z=-20
P2: X=20 Y=-20 Z=-20
P3: X=20 Y=20 Z=-20
P4: X=-20 Y=20 Z=-20
P5: X=-20 Y=-20 Z=20
P6: X=20 Y=-20 Z=20
P7: X=20 Y=20 Z=20
P8: X=-20 Y=20 Z=20

Środek bryły jak i punkt obserwatora znajdują się w punkcie zerowym i dlatego przeliczając punkty na układ 2D należy odjąć od współrzędnej "Z" jakąś wartość, nie mniejszą niż odległość krawędzi bryły do jej środka. Zmienne: "srodekX2D" i "srodekY2D" przechowują wartości, które są współrzędnymi środka panelu, odpowiadają za przesunięcie rysunku na środek panelu. Zmienna "wielkosc" odpowiedzialna jest za skalowanie rysunku 2D, im większa jej wartość tym większy jest rysunek. Wartość zmiennej "wielkosc" może być zależna od wielkości okna programu - zapewni to zmianę rozmiaru rysunku w zależności od rozmiaru okna.



Łączenie punktów linią.

Jedno z prostych rozwiązań, jakie umożliwia programowanie obiektowe jest: utworzenie klasy "Punkt3D". Obiekt klasy "Punkt3D" zawiera referencję do innego obiektu tej samej klasy np. pod nazwą zmiennej: poprzedni. W Klasie "Punkt3D" znajduje się metoda:

public void rysujLinie2D() {
 if(prior != null) {
  double x1 = (-prior.px * wielkosc) / (prior.pz - 600) + srodekX2D;
  double y1 = (prior.py * wielkosc) / (prior.pz - 600) + srodekY2D;
  double x2 = (-this.px * wielkosc) / (this.pz - 600) + srodekX2D;
  double y2 = (this.py * wielkosc) / (this.pz - 600) + srodekY2D;
  linia.setLine(x1, y1, x2, y2);
  g2.draw(linia);
 }
}

Metoda odpowiada za narysowanie linii między dwoma punktami. 

Obrót wokół osi X, Y, Z o zadany kąt

Za przesunięcie punktu względem osi X, Y, Z o zadany kąt odpowiadają trzy metody znajdujące się w klasie "Punkt3D". Metody:

 public void ObrotX(double kat) {
   double katX = degToRad(kat);
   double pomX, pomY, pomZ;
   pomX = px;
   pomY = py * Math.cos(katX) - pz * Math.sin(katX);
   pomZ = pz * Math.cos(katX) + py * Math.sin(katX);
   px = pomX; py = pomY; pz = pomZ;
 }

 public void ObrotY(double kat) {
   double katY = degToRad(kat);
   double pomX, pomY, pomZ;
   pomX = px * Math.cos(katY) + pz * Math.sin(katY);
   pomY = py;
   pomZ = pz * Math.cos(katY) - px * Math.sin(katY);
   px = pomX; py = pomY; pz = pomZ;
 }

 public void ObrotZ(double kat) {
   double katZ = degToRad(kat);
   double pomX, pomY, pomZ;
   pomX = px * Math.cos(katZ) - py * Math.sin(katZ);
   pomY = py * Math.cos(katZ) + px * Math.sin(katZ);
   pomZ = pz;
   px = pomX; py = pomY; pz = pomZ;
 }

Funkcje trygonometryczne z pakietu "Math" przyjmują radiany, zatem potrzebna jest metoda przeliczająca ze stopni na radiany:

 private double degToRad(double deg)
 {
   return deg * ((2 * Math.PI) / 360);
 }