Oświetlenie graniastosłupa

Myślę, że najpierw musisz przeczytać artykuł o rysowaniu bryły w rzucie aksonometrycznym np aksonometria prostopadła oraz artykuł omawiający jak roztrzygnąć widoczność ściany w wielościanie.

Uzyskamy dynamiczne oświetlenie liczone dla całej ściany (naszą sceną 3D jest tylko graniastosłup).
Natężenie oświetlenia wyrazimy przy pomocy gradientu kolorów długości 90 np:
void paleta_zl() 
{ 
  float r,g,b; 
  float pr=154f/255f,dr=(254f-154f)/255f; 
  float pg=122f/255f,dg=(252f-122f)/255f; 
  float pb=40f/255f,db=40f/255f;

  for(int i=0;i<91;i++) 
   { 
    r=pr+i*dr/91f; 
    g=pg+i*dg/91f; 
    b=pb+i*db/91f; 
    pal[i]=new Color(r,g,b); 
   } 
}


Prezentowane podejście jest bardzo proste i potraktuj je jako początek swojej przygody z tym tematem.
Zdefiniowana w sugerowanych na początku artykułach funkacja widoczna posłuży nam do oświetlenia naszego graniastosłupa.
Oprócz oceny widoczności, będzie miała zadanie ustalić numer koloru w gradiencie, którym wyrazimy natężenie oświetlenia wg zasady:
<(kierunek rzutu , wektor normalny ściany) = nr koloru -> im większy kąt tym oświetlenie jest jaśniejsze
Algorytm oceniający ścianę :
if(widoczna) zamaluj(pal[kolor])
boolean widoczna(int i,int j,int m) 
{ 
  pkt3d p,q,N,K; 
  double a,b,c,iloczyn,i_dl; 
  p=new pkt3d(0,0,0);q=new pkt3d(0,0,0); 
  N=new pkt3d(0,0,0); 
  K=new pkt3d(pkt3d.obs.x,pkt3d.obs.y,pkt3d.obs.z); 

  p.x=w[i].x-w[j].x; q.x=w[m].x-w[j].x; 
  p.y=w[i].y-w[j].y; q.y=w[m].y-w[j].y; 
  p.z=w[i].z-w[j].z; q.z=w[m].z-w[j].z; 

  N.x=p.y*q.z-p.z*q.y; 
  N.y=p.x*q.z-p.z*q.x; 
  N.z=p.x*q.y-p.y*q.x; 
  iloczyn=N.x*K.x+N.y*K.y+N.z*K.z; 
  i_dl=mat.dl3(N)*mat.dl3(pkt3d.obs); 
  kolor=(int)(90d*Math.abs(iloczyn)/i_dl); 
  return(iloczyn<0); 
}
Obok wersja funkcji dla Javy. Zobacz wersję C++Builder.

W Javie nie ma wskaźników, funkcje zwracają tylko jedną wartość - na swoją nazwę. C++/C jest tu oczywiście bardziej elastyczne. Zmienna kolor musi być zmienną globalną (z tym ostrożnie).
Dla każdego kąta <(wektor Normalny, wektor Rzutu) otrzymujemy liczbę całkowitą z przedziału <0,90>
Można więc porównać, że oświetlenie ściany wyrażamy w mierze "kątowej" dla kątów ostrych, liczonej w stopniach. Teraz zajmiemy się procedurą zamaluj(). Mamy dwa przypadki :
  1. zamaluj czworokąt tzn ścianę boczną
  2. zamaluj wielokąt o n-bokach tzn podstawę bryły
W Javie zamalowanie np trójkata (wsp. całk) wygląda tak:
int[] fx={x1,x2,x3,}, fy={y1,y2,y3}; 
g.setColor(pal[kolor]); 
g.fillPolygon(fx,fy,3);

Teraz trzeba to wszystko zorganizować.
1. Zgromadzimy współrzędne wierzchołków w tablicy pkt3d[] w=new pkt3d[30];. Zobacz przykład .
2. Zdefiniujemy funkcję R3 -> C2 oraz procedury "oświetlające" : ściany boczne i podstawy
Point w_sc(int nr) 
{ 
  Point p=new Point(0,0); 
  lo28.pkt rz=new lo28.pkt(0,0); 

  rz=pkt3d.rzut(w[nr]); 
  p.x=lo28.cal_x(rz.x); 
  p.y=lo28.cal_y(rz.y); 
  return(p); 
} 
void Filuj4(Graphics g,int w1,int w2,int w3,int w4) 
{ 
  Point[] u={w_sci(w1),w_sc(w2),w_sc(w3),w_sc(w4)}; 
  int[] fx={u[0].x,u[1].x,u[2].x,u[3].x}, 
            fy={u[0].y,u[1].y,u[2].y,u[3].y}; 

  g.setColor(pal[kolor]); 
  g.fillPolygon(fx,fy,4); 
}
Zdefiniuj funkcję rzut. Jeśli zdecydujesz się na aksonometrię prostopadłą z zadanym kierunkiem rzutu ciało funkcji może wyglądać:

pkt2d rzut(pkt3d p) 
{ 
 return(new pkt2d(p.y*sa+p.x*ca,(p.y*ca-p.x*sa)*sf+p.z*cf)); 
}
Dla podstaw procedura "oświetlająca" może wyglądać np tak :
void FilujP(Graphics g,int kt) 
{ 
  Point fig []=new Point[15]; 
  int[] fx=new int[15]; 
  int[] fy=new int[15]; 

  int j=-1; 
  for(int i=kt;i<kt+ile;i++) 
   { 
    j++; 
    fig[j]=w_sciany(i); 
    fx[j]=fig[j].x; 
    fy[j]=fig[j].y; 
   } 
  g.setColor(pal[kolor]); 
  g.fillPolygon(fx,fy,ile); 
}

3. Zorganizujemy proces oświetlania ścian.
Fragment kodu dotyczący oświetlania podstaw może wyglądać tak:
void podstawy(Graphics g) 
{ 
 if(widoczna(2,1,0)) FilujP(g,0); 
  else 
    FilujP(g,ile) ; 
}

Zobacz jeszcze wersję C++Builder