Shape blending
Teori
Shape blending er en teknikk for å kombinere flere former til en ny form.
En form fungerer som en slags standardflate, mens de andre formene "påvirker" standardflaten.
Man bruker en faktor mellom 0 og 1 for å fortelle hvor stor "påvirkningen" skal være.
Dersom flere former har påvirkningsfaktor 1, vil resultatet bli et gjennomsnitt av formene.
For at algoritmen skal fungere må det være like mange punkter i alle formene.
Alle punkter i flater man skal blande mellom beskrives i forhold til standardflaten.
Hvis x er en blandingsfaktor, og y er verdien man vil blande mellom, så kan man bruke følgende funksjon (laget av Sven Nilsen):
Ut = (x1*y1+x2*y2+x3*y3+...xn*yn)/(x1+x2+x3+...xn)
For å bruke funksjonen på punkter må man først trekke ifra koordinatet til
det tilsvarende punktet i standardflaten. Når det nye relative punktet er beregnet, må man
legge til punktet i standardflaten, og dermed får vi ut det blandede punktet.
Dersom summen av blandingsfaktorene er lik 0, vil algoritmen kræsje. En måte å løse dette på, er å bruke origo dersom summen av blandingsfaktorene er mindre enn f.eks. 0.01. Dette kan forårsake at punktene "hopper" litt.
I klassen Blending, som følger med kildekoden til dette prosjektet, er problemet med deling på 0 løst ved å bruke forholdet mellom ny sum og gammel sum av vekter, der summen av vektene alltid er 1 eller større. Dette sikrer at blendingen alltid er jevn.
float oldSumFactors = 1; float newSumFactors = 0; float blendFactor = 0; float[][] sh = null; for (int i = 0; i < numShapes; i++) { sh = stateVertices[i]; blendFactor = blendFactors[i]; newSumFactors = Math.Max(1, sumFactors + blendFactor); // Blend points. for (int j = 0; j < numVertices; j++ ) ps[j] = new float[]{ (ps[j][0] * (oldSumFactors / newSumFactors)) + (sh[j][0] - baseVertices[j][0]) * blendFactor, (ps[j][1] * (oldSumFactors / newSumFactors)) + (sh[j][1] - baseVertices[j][1]) * blendFactor, (ps[j][2] * (oldSumFactors / newSumFactors)) + (sh[j][2] - baseVertices[j][2]) * blendFactor }; sumFactors += blendFactor; oldSumFactors = Math.Max(1, sumFactors); } for (int j = 0; j < numVertices; j++) ps[j] = new float[]{ baseVertices[j][0] + ps[j][0], baseVertices[j][1] + ps[j][1], baseVertices[j][2] + ps[j][2]};
Om eksempelprosjektet
Eksempelkoden er skrevet i C#, og som OpenGL wrapper har jeg brukt Tao.
For å demonstrere Shape Blending, har jeg modellert et ansikt i 3D-programmet Maya.
Så brukte jeg skjeletter i Maya til å lage forskjellige uttrykk.
Etterpå eksporterte jeg uttrykkene til OBJ-format.
Det finnes ikke noen standard OBJ-leser for Tao OpenGL, så jeg lagde min egen.
I eksempelkoden heter klassen ObjReader, som leser et Mesh objekt fra en fil.
Normalene blir ikke blandet i programeksempelet for å gi en slag "rynkeeffekt".
For å kunne stille på blandingsfaktorene, lagde jeg et eget lite oppsett for 2D kontroller i OpenGL.
Kontrollene tegnes med GDI+ på Bitmap-objekter, og gjøres deretter om til teksturer i OpenGL.
Jeg har valgt å lage et eget oppsett for kontroll-grensesnitt, slik at jeg kan bestemme design, farger og
virkemåte i størst mulig grad.
Med klassene for kontroll-grensesnittet, er det enkelt å legge til
fancy 2D-grafikk oppå 3D-grafikken. F.eks. når brukeren holder musen over en knapp eller slidebar, endres fargen til en gjennomsiktig blå farge.
For mer informasjon se GDI+ i OpenGL