Plan
Plan
Det er slik at dersom vi kjenner to vektorer som danner en vinkel forskjellig fra 0 eller 180 grader med hverandre i et plan så er planet entydig bestemt. Det betyr at dersom vi kjenner tre punkter som ikke ligger på linje så er planet entydig bestemt. Og normalen til planet er bestemt av kryssproduktet til de to vektorene.
Den generelle formen for et plan er
Ax+By+Cz+D=0
der vektoren |A B C| er normalen til planet. Vi drar ikke bevis eller utledninger eller nærmere begrunnelse for dette. Merk at normalen beregnes etter høyrehåndsregelen. Dette er viktig når vi skal oppgi normaler i OpenGL. Siden OpenGL skiller mellom forside og bakside på flater, er det viktig at vi oppgir normaler på en systematisk måte. D kan finnes ved innsetting av et punkt i planet i den generelle planligningen.
Minner om definisjonen av kryssproduktet:
AXB=(a2b3-a3b2, a3b1-a1b3, a1b2-a2b1)
La oss eksemplifisere:
Eksempel 1.
Anta P1 =(0,0,0), P2=(2,0,0) og P3=(0,3,0)
N=P1P2 X P1P3= [2,0,0] X [0,3,0]
= [0·0-0·3 , 0·0-2·0 , 2·3-0·0]
= [0,0,6]Planet:
6z+D=0.Substituerer for P1, og får 0+D=0, som gir D=0.
Planligningen blir 6z=0, eller like godt z=0.
Eksempel 2.
Anta P1 =(0,1,0), P2=(1,0,0) og P3=(0,0,1)
N=P1P3 X P1P2= [0,-1,1] X [1,-1,0] = [-1·0-1·(-1),1·1-0·0 ,0·(-1)-(-1)·1]
= [1,1,1]Planet: x+y+z+D=0.
Setter inn for P1, og får 1+D=0, som gir D=-1.
Planligningen blir x+y+z-1=0
Plan og linje
Vi vil forsøke å løse det generelle problemet med å finne skjæring mellom en linje gjennom punktene O og Q og et plan som er beskrevet med punktene P1, P2 og P3. Vi tar for gitt at P1, P2 og P3 ikke ligger på linje, slik at vi kan være sikre på at de tre punktene bestemmer et plan.
Vi forutsetter i fortsetningen at vi har funnet planligninga slik som vist ovenfor:
Ax+By+Cz+D=0
Vi kan relatere problemet til den problemstillingen som melder seg dersom vi skal beregne slagskygge. Tilsvarende analyse er nyttig for å forstå raytracing. Vi tenker oss at O er posisjonen til en lyskilde og Q er hjørnet på en flate som skal kaste skygge på planet. For enkelthets skyld tenker vi oss at lyskilden er plassert i origo, dvs. O er origo. Vi taper ikke noe generalitet i dette siden vi vet at vi kan transformere til et vilkårlig origo.
Linja fra origo gjennom Q kan vi beskrive parametrisk slik:
P(t)=t·Q
eller for hver komponent:
x(t)=t·Qx y(t)=t·Qy z(t)=t·Qz
Problemet vårt reduseres til å finne ut for hvilken t-verdi linja skjærer planet. Vi setter inn i planligninga og får:
A·t·Qx+B·t·Qy+C·t·Qz+D=0
Løst med hensyn på t:
t=-D/(A·Qx+B·Qy+C·Qz)
Vi finner linjas skjæring med planet uttrykt med Q og plankoeffisientene.
x=-D·Qx/(A·Qx+B·Qy+C·Qz) y=-D·Qy/(A·Qx+B·Qy+C·Qz) z=-D·Qz/(A·Qx+B·Qy+C·Qz)
Merk at planligninga ikke sier oss noe om planets utstrekning. Vi har derfor ikke informasjon i uttrykket ovenfor som kan si oss om skjæringspunktet faller innenfor et avgrenset polygon i planet.
Vi har imidlertid informasjon om hvordan punktet Q ligger i forhold til planet. Planet ligger lenger fra origo en Q bare dersom t >1.
Vi ser litt nærmere på uttrykket ovenfor. Det hadde vært ønskelig å kunne uttrykke sammenhengen mellom skjæringspunktet og Q i matriseform. Dersom vi får til det, kan vi ha følgende tegnestrategi for uttegning av et polygon og dets slagskygge på et plan:
// tegn polygonet DrawPolygon(p) <sett opp en transformasjonsmatrise basert på ligninga for planet > // tegn slagskyggen DrawPolygon(p)
Spørsmålet blir da hvordan transformasjonsmatrisa skal se ut. Den skal realisere sammenhengen mellom Q og skjæringspunktet, S, mellom linja fra origo gjennom Q og planet.
Sammenhengen ovenfor kan uttrykkes slik i matriseform:
|-D 0 0 0| |Qx| |-DQx | S=M*Q= |0 -D 0 0|*|Qy|=|-DQy | |0 0 -D 0| |Qz| |-DQz | |A B C 0| |1 | |AQx+BQy+CQz |
For at dette skal bli riktig må vi forutsette at resultatvektoren homogeniseres, dvs. at de tre første koordinatene divideres med den siste. Se modulen Homogenisering. I OpenGL er det slik og vi kan realisere en tegnestrategi som skissert ovenfor.
DrawPolygon(p) float m[]={...} glPushMatrix() glMultMatrix(m) DrawPolygon(p) glPopMatrix()
Slagskygge er videre behandlet i modulen Slagskygge.
Klippeplan i OpenGL
OpenGL gir oss en mulighet for å sette opp (midlertidige) klippeplan under uttegning av en figur. Hvis vi f.eks. ønsker å tegne ut en halvkule, kan vi sette opp et klippeplan som deler en hel kule og tegne ut den hele kula.
Oppsetting av et klippeplan gjøres ved funksjonen:
glClipPlane(GL_CLIP_PLANEi,koeffisienter som beskriver planet);
Konstanten GL_CLIP_PLANEi sier oss at vi skal bruke klippeplan i. i er et tall i området [0..n] som holder styr på de i alt n+1 mulige klippeplanene. n skal være minst 5 i en OpenGL-implementasjon.
Koeffisientene som beskriver planet er A,B,C,D slik vi har beskrevet plan ovenfor.
Et eksempel på uttegning av en halvkule:
// set up clip plane double clip_plane1[]={0.0,0.0,-1.0,0.5}; gl.glClipPlane(GL_CLIP_PLANE1,clip_plane1); gl.glEnable(GL_CLIP_PLANE1); // draw sphere long qd=glu.gluNewQuadric(); glu.gluSphere(qd,3.0f,20,20); glu.gluDeleteQuadric(qd); gl.glDisable(GL_CLIP_PLANE1); |
Merk at de individuelle klippeplanene må/kan skrus av og på.