Anaglyphe 3D in Javascript, of een van mijn slechtere ideeën.

Deze heb je nodig voor het resultaat van dit artikel
3D is hip. Films, televisie en games moeten allemaal in 3D. Simpel omdat het kan. Daarom wilde ik kijken of dat ook in javascript kan, en snel. Moeilijke klus? Ja. Onmogelijk? Nee. Aan de slag dus maar.

Het idee

Om simpel te beginnen, wilde ik kijken of het mogelijk was een kubus die bestaat uit bolletjes in 3D te laten zien, met een wisselend camerapunt. In principe is mijn programma dan in pseudocode:
Loop for ieder frame {
  Verzin voor beide ogen een camera punt
  Bepaal de kijkrichting
  Projecteer alle punten van de kubus op het scherm volgens beide camerapunten
}

Simpel genoeg om te werken, nu de uitvoering nog.

De camera

Een willekeurig punt kiezen lijkt makkelijk. Helaas krijg je als je gewoon iedere keer met Math.random() willekeurige coordinaten kiest, niet een heel mooie beweging, maar spring je houterig van punt naar punt.

Een oplossing vond ik dit artikel. Kies voor een paar frames een doelwit waar de camera naar toe moet verplaatsen, neem een intermediair en neem de camerapositie. Wat je hierna doet is interpoleren. Eerst het intermediair naar het doelwit en daarna de camerapositie naar het intermediair. Code is makkelijker dan taal.
function interpoleer(begin, doel) {
  return begin + (doel - begin) * (een getal < 1);
}

intermediair = interpoleer(intermediair, doelwit);
camerapositie = interpolair(camerapositie, intermediair);

if(framenummer%7 == 0)
  kies een nieuw doelwit;

Natuurlijk zou je ook nog meer intermediairs kunnen toevoegen voor een nog voor een vloeiendere verschuiving, maar dit volstaat. Het effect van deze methode zie je hieronder. De hoekige zwarte lijn is een coördinaat van de doelwitpositie, de groene lijn is het intermediair en de blauwe lijn (die inmiddels vloeiend is) is de camerapositie.


Twee ogen

Nu heb ik 1 camerapunt, ik had er twee nodig. Om te beginnen moet ik reken ik dan yaw en pitch uit. (Geen idee hoe die in het Nederlands zouden moeten heten) Deze kan je makkelijk aflezen uit de camerapositie, aangenomen dat je naar het middelpunt van de scene kijkt. Hierna kan je met de yaw de geroteerde x-as uitrekenen.
yaw  = atan2(X, -Z);
pitch = atan2(Y , sqrt(X * X + Z * Z));

xAs = new Vector(cos(yaw), 0, sin(yaw));

Met die x-as is het vervolgens heel makkelijk om links en rechts van het oorspronkelijke punt twee cameraposities te kiezen. Het mag ook wel eens simpel zijn.

Projecties

Projecties zijn na het uitrekenen van de yaw en de pitch vrij makkelijk. Je transleert ieder punt naar de camera toe, past de twee rotaties toe, et voila. Dit moet voor beide camerapunten uiteraard.
for ieder punt van de kubus
  X = punt.x - cameraX;
  Y = punt.y - cameraY;
  Z = punt.z - cameraZ;

  // Yaw rotatie
  X2 = X * cos(yaw) + Z * sin(yaw);
  Y2 = Y;
  Z2 = Z * cos(yaw) - X * sin(yaw);

  // Pitch rotatie
  X3 = X2;
  Y3 = Y2 * cos(pitch) + Z2 * sin(pitch)
  Z3 = Z2 * cos(pitch) - Y2 * sin(pitch);

  if(Z3 > 0)
    Zorg dat deze pixel getekend wordt.
}

Helaas wordt je altijd door schade en schande wijs in dit vak. Het blijkt namelijk dat als je twee kleuren hebt, het opvalt als een achtergelegen bol over een bol in de voorgrond heen getekend wordt. Hiervoor moesten alle puntjes dus nog ge-Z-buffert worden. Maar met dit alles klopte het eindelijk.

Compatibiliteit

De demo werkt in Chrome, Opera, Firefox, IE9. Safari geeft echter vreemde resultaten, want die wist het canvas niet, wat wel zou moeten gebeuren bij het resetten van de hoogte danwel breedte. Je hebt een Rood / magenta 3D bril nodig als je de demo wil bekijken.

En dit is dan het eindresultaat.
Bert Peters | 18:46:00 22/05/2011 | Link | 0 reactie(s) | Tags: 3D HTML5 
tweet


Reacties


Laat zelf een bericht achter

Naam (verplicht)
E-mail (verplicht, nooit publiek)
Typ deze tekst over: captcha
Link
Opmerking