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 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 eksempelprosjekter
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