Fortsetter fra del 1 hvor vi grep Papervision3D, del 2 tar scenen litt lenger. I denne avsluttende delen lærer du hvordan du får dine roterende terninger å hoppe ut på betrakteren med 3D-briller.
Jeg vet det står der oppe at denne opplæringen handler om Papervision3D i Flash, men faktisk handler det om å lure hjernen din. Vi skal gjøre hjernen din tanke om at den ser på et faktisk 3D-objekt, når det faktisk bare ser et 2D-bilde.
Hvis du er kjent med Papervision3D, kan du følge dette ved å bruke et prosjekt som har en scene, et kamera og et visningsport. Hvis ikke, sjekk ut del 1 av denne veiledningen først, siden jeg skal fortsette fra hvor vi sluttet. Her er den typen ting vi skal jobbe for:
Pek fingeren i luften og hold den opp foran nesen din.
Se på det med bare ditt høyre øye åpent, så med bare venstre. Se hvordan det ser ut til å hoppe fra venstre til høyre, mens det som i bakgrunnen nesten ikke ser ut til å bevege seg i det hele tatt?
Hjernen din merker disse forskjellene mellom hva hver av dine øyne ser og bruker dem til å generere en full 3D-simulering av verden rundt deg. I hodet ditt. Øyeblikkelig. Ganske imponerende!
Hvis vi skal lure hjernen din, må vi gjøre hvert av øynene dine se et annet bilde. Så for å starte, la oss legge til et annet "øye" (et annet kamera) til scenen. Dette vil bli brukt til å lage bildet til høyre øye, mens det eksisterende kameraets bilde vil bli matet til venstre øye.
Opprett en ny offentlig variabel som heter camera2...
offentlig var kamera2: Camera3D;
... og initialiser den i Main () constructor-funksjonen:
kamera = nytt kamera3D ();
Vi trenger en annen visningsport for å ta kameraets utgang, så legg til følgende:
offentlig var viewport2: Viewport3D;
viewport2 = nytt Viewport3D (); viewport2.autoScaleToStage = true; // dette vil gjøre visningsporten så stor som scenen addChild (viewport2);
(Jeg rushing gjennom dette, siden vi dekket det hele sist gang.)
Huske, viewport2 vil være tomt til vi gjør noe for det. Vi trenger ikke å opprette en ny renderer for dette; bare bruk den eksisterende en to ganger. Så, i Main (), ta denne koden:
renderer = ny BasicRenderEngine (); renderer.renderScene (scene, kamera, visningsport);
... og legg til en ny linje for å gjøre det andre kameraet til den andre visningsporten, slik som:
renderer = ny BasicRenderEngine (); renderer.renderScene (scene, kamera, visningsport); renderer.renderScene (scene, kamera2, viewport2);
Gjør det samme i onEnterFrame () -funksjonen din også:
renderer.renderScene (scene, kamera, visningsport); renderer.renderScene (scene, kamera2, viewport2);
Hvis du tester dette ut nå, vel, det vil se ut som det gjorde før:
Men det er ingen overraskelse: For det første er de to kameraene på nøyaktig samme sted!
Som standard plasseres kameraer på (x = 0, y = 0, z = -1000) - du kan sjekke ved å gjøre det spor (kamera.x, kamera.y, kamera.z).
Så sett ovenfra ser scenen slik ut:
Sett fra siden, er det slik:
For å etterligne våre egne øyne, bør vi plassere vårt andre kamera litt til høyre for vår første:
La oss prøve å flytte det 50 piksler til høyre, og se hva som skjer. Sett dette i Main (), et sted etter at du har laget det andre kameraet:
camera2.x = camera.x + 50;
Test det nå, og se hva du får:
Det ser merkelig ut, men det virker tydelig! Området rundt kubene er gjennomsiktig i hver visning, så det første kan ses bakom det andre.
Det vil være nyttig å se på hva hvert kamera ser individuelt, så la oss ta øye analogi videre ved å gjøre dem "blanke" når vi klikker. Først legger du til en hendelseslytter til hvert visningsport, for å oppdage museklikkene:
viewport.addEventListener (MouseEvent.CLICK, onClickViewport); viewport2.addEventListener (MouseEvent.CLICK, onClickViewport2);
Sett det på slutten av Main () -funksjonen. Ikke glem å importere MouseEvent:
importer flash.events.MouseEvent;
Legg til disse nye funksjonene i koden din, utenfor hovedfunksjonen (), men i hovedklassen:
offentlig funksjon onClickViewport (mouseEvt: MouseEvent): void offentlig funksjon onClickViewport2 (mouseEvt: MouseEvent): void
Når vi klikker på den første visningsporten, trenger vi den til å bli usynlig mens den andre blir synlig (og omvendt for når vi klikker på det andre). Så endre hendelsesbehandlerne dine slik:
offentlig funksjon onClickViewport (mouseEvt: MouseEvent): void viewport.visible = false; viewport2.visible = true; offentlig funksjon onClickViewport2 (mouseEvt: MouseEvent): void viewport.visible = true; viewport2.visible = false;
Prøv det:
Legg merke til at du må klikke på en av kuber; De gjennomsiktige områdene brenner ikke av en CLICK MouseEvent.
Du kommer til å trenge et par 3D "anaglyph" briller; typen der hvert objektiv er en annen farge. Paret jeg bruker har en gul linse i venstre øye og en blå linse i høyre øye (kalt ColorCode3D-systemet), men andre fargekombinasjoner er også populære, som rød og cyan.
Du kan finne disse brillene på eBay for et par dollar: bare søk etter 3d briller
Alternativt kan du selv lage din egen! André skrev en kommentar på den første delen av denne opplæringen som forklarer at han bruker Tic-Tac-bokser med forskjellige farger for å lage hans. Geni!
Selv om eksemplene mine vil bli laget for gule og blå briller, vil jeg prøve å forklare prinsippene slik at du kan få din til å fungere med alle farger du har. Det er litt vanskelig, så vær så snill å legge inn en kommentar nedenfor hvis dette blir forvirrende!
Hver piksel på datamaskinen din er som en gruppe med tre lyspærer: en rød, en grønn og en blå.
Ved å justere lysstyrken til hver "pære" kan vi endre fargen på den piksel:
Linsene i 3D-briller stopper lyset fra noen av disse pærene fra å komme seg gjennom. For eksempel blokkerer den blå linse i brillene mitt det røde og grønne lyset fra å nå øynene mine.
Så hvis jeg ser på dette bildet gjennom min blå linse, vil jeg ikke kunne lese den:
Intet lys når øynene fra det svarte området fordi alle tre pærer er slått av. Og det kommer ikke noe lys fra øynene fra det grønne området, fordi bare den grønne pæren er slått på, og det blå objektivet filtrerer det ut. Så alt jeg ser er et svart rektangel.
Nå, OK, hvis du prøver dette selv, kan du oppleve at dette ikke er helt sant. Linsen din er sannsynligvis ikke 100% ren blå, så det vil gi litt grønt og rødt lys gjennom. Eller kanskje skjermens farger er kalibrert annerledes enn min, så den grønne teksten har en liten mengde rød og blå i den. For å være ærlig, det samme er sant for meg - men det spiller ingen rolle, så lenge teksten er hard å lese.
Vårt mål er å gjøre det vanskelig for ditt høyre øye for å se bildet fra det venstre kameraet, og også for venstre øye og høyre kamera.
Den blå linse er over mitt høyre øye, så i teorien hvis jeg fjerner alt det blå fra det venstre kameraets bilde, vil jeg ikke kunne se det med høyre øye.
I dette trinnet, la oss få det venstre visningsportens bilde bare å gi rødt og grønt lys; ikke noe blått lys i det hele tatt. Vi kan gjøre dette ved å bruke en ColorTransform. Disse er enkle å sette opp; Først importerer du klassen:
importer flash.geom.ColorTransform;
Deretter oppretter du en ny offentlig variabel for å holde en forekomst av klassen:
offentlig var leftViewportColorTransform: ColorTransform;
Nå opprett faktisk denne nye forekomsten inne Main ():
leftViewportColorTransform = ny ColorTransform ();
Til slutt, fortell Flash å bruke denne ColorTransform til venstre kameraets visningsport:
viewport.transform.colorTransform = leftViewportColorTransform;
(Den siste linjen må være etter at du har opprettet visningsporten og fargetransformasjonen. Det er sannsynligvis enklest å bare si det riktig på slutten av Main ().)
SWF vil ikke se noe annerledes ennå, fordi ColorTransform ikke endrer bildet som standard som standard.
Vi kan velge hvilken brøkdel av hver pære lys vi ønsker å gi gjennom ved å endre blueMultiplier, greenMultiplier og redMultiplier egenskapene til vår ColorTransform.
Setter noen av disse til 1 forteller at Flash skal la det være alene, mens du setter det på 0 forteller Flash for å slå den av helt. Og, selvfølgelig, 0.5 vil få det til å utgjøre halvparten av det normale beløpet, 2.0 vil gjøre det doble det, og så videre.
Så å tømme alt det blå ut av venstre visningsport, kan vi gjøre dette:
leftViewportColorTransform.blueMultiplier = 0;
Du må sette det før linjen som gjelder forvandlingen til visningsporten, slik:
leftViewportColorTransform.blueMultiplier = 0; viewport.transform.colorTransform = leftViewportColorTransform;
Hvis brillene har et rødt eller grønt objektiv over høyre øye, bør du stille inn redMultiplier eller greenMultiplier til 0, heller enn det blå. For andre farger må du bruke en blanding av rød, grønn og blå - mer på det i trinn 15.
Test SWF:
Det er vanskelig å få frem «a» av logoen gjennom det blå objektivet, men det er ikke vanskelig å få ut kubernes form mot den hvite bakgrunnen!
Hvis du endrer bakgrunnen til SWF, ser du problemet. Fordi det "hvite" området rundt kubene ikke er egentlig hvitt, men ganske gjennomsiktig og la den hvite bakgrunnen til SWF vise seg, er den ikke påvirket av ColorTransform.
For å fikse dette må vi gi visningsporten en solid hvit bakgrunn som kuber vil bli gjengitt på toppen av. Det er lett nok; bare gå tilbake til der du opprettet visningsporten:
viewport = nytt Viewport3D (); viewport.autoScaleToStage = true; // dette vil gjøre visningsporten så stor som scenen
... og legg til et par linjer for å tegne et hvitt rektangel som er like stort som scenen:
viewport = nytt Viewport3D (); viewport.autoScaleToStage = true; // dette vil gjøre visningsporten så stor som scenen viewport.graphics.beginFill (0xffffff); // 0xffffff er hvit viewport.graphics.drawRect (0, 0, stage.stageWidth, stage.stageHeight);
Test det ut igjen:
Bildet skal være veldig svakt, kjedelig og vanskelig å se gjennom den riktige linse, men like enkelt som det vanlige bildet å se gjennom venstre linse.
Vi må gjøre det samme for riktig visningsport nå. Så lager din nye ColorTransform:
offentlig var rightViewportColorTransform: ColorTransform;
rightViewportColorTransform = ny ColorTransform ();
Bruk nå denne nye transformasjonen til høyre visningsport:
viewport2.transform.colorTransform = rightViewportColorTransform;
Siden mitt venstre linse er gult, må jeg tømme alt det gule ut av denne visningsporten.
(Hvis venstre linse er rød, så er dette trinnet enkelt - bare sett redMultiplier av din nye ColorTransform til 0.)
Men hvordan blir vi gule ut av rødt, grønt og blått?
Hvis vi brukte maling, kunne vi ikke; gul er en primær farge i det tilfellet. Men når det gjelder lys, er det forskjellige. Se på dette:
Bilde fra Wikimedia Commons. Takk, Mike Horvath og jacobolus!
Som du kan se, blandes rød og grønn sammen for å bli gul (som forklarer hvorfor bakgrunnen til venstre visningsport ble gul da vi fjernet alt det blå). For å fjerne alle de gule fra bildet vårt, må vi fjerne alle de røde og alle de grønne!
Vi kan gjøre dette slik:
rightViewportColorTransform = ny ColorTransform (); rightViewportColorTransform.redMultiplier = 0; rightViewportColorTransform.greenMultiplier = 0; viewport2.transform.colorTransform = rightViewportColorTransform;
Ja, vi må også fylle ut bakgrunnen til denne visningsporten.
Gjør dette på samme måte som før:
viewport2 = nytt Viewport3D (); viewport2.autoScaleToStage = true; // dette vil gjøre visningsporten så stor som scenen viewport2.graphics.beginFill (0xffffff); // 0xffffff er hvit viewport2.graphics.drawRect (0, 0, stage.stageWidth, stage.stageHeight);
Test det ut:
Den gule linse på brillene mine lar faktisk en hel del blått lys gjennom, men det er fortsatt mye mørkere når det ses gjennom linsen enn når man ser på den blå linse, og det er det som betyr noe.
Så vi har våre to bilder satt opp og fargetransformert. Feil er, for øyeblikket kan vi bare se en av dem om gangen.
Den mest åpenbare måten å la oss se begge på en gang, er å redusere alfaenheten (gjennomsiktigheten) til visningsporten på forsiden, slik som:
viewport2.alpha = 0.5;
Test dette ut:
Ah. OK, ikke en vekslende suksess. Alpha er klart ikke det riktige verktøyet for jobben; hva har vi igjen?
Flash gir oss valget mellom flere forskjellige blandingsmodus, metoder for å blande to skjermobjekter sammen. Det er en fullstendig liste over dem her, men jeg skal bare fokusere på den som heter Legg til.
De Legg til blandingsmodus går gjennom hver piksel av de to bildene, og legger sammen lysstyrken til hver av de tre pærene.
Så hvis en bestemt piksel i det første bildet har den grønne pæren helt på og de andre to helt av, og samme piksel i det andre bildet har den blå pæren helt på og de to andre helt av, da når de blandes sammen, blir den grønne og blåpærer vil være helt på, og den røde pæren vil være helt av.
Hvis de første og andre bildene begge har den røde pæren halvveis og de andre to helt av, vil det blandede bildet ha den røde pæren helt på, mens de andre to holder seg av.
Få bildet? Flott, la oss bruke den. Slett linjen vi nettopp skrev som justerte alfaen, og erstatt den med dette:
viewport2.blendMode = "add";
(Vi trenger ikke å bruke blandemodus til begge visningsportene, bare den øverst på visningslisten.)
Test det ut:
Det er bedre!
Hvis du ser på det gjennom ett øye av gangen, bør du legge merke til at hvert øye ser en annen visningsport mer fremtredende. Du vil sikkert også kunne se et svakt spøkelse i den andre viewporten, men det er ikke noe problem; Hjernen din kan ignorere det.
Imidlertid ser bildet ikke helt 3D ut ennå. La oss sortere det ut.
Selv om øynene dine ser forskjellige bilder, er dette ikke nok til å lure hjernen din. Hjernen din er ganske smart, du ser; noen vil til og med si at det er det smarteste organet i kroppen din. Det vet at det skal bruke andre ledetråder til å finne ut om et objekt er 3D. Perspektiv, for eksempel: hvor lite en gjenstand skal se ut fra hvor langt det er.
Hovedproblemet her er at våre to kameraer er plassert langt lenger bortsett fra hverandre enn våre egne øyne er. Det er ikke overraskende, siden jeg plukket nummer 50 tilfeldig.
Den faktiske separasjonsavstanden vi skal bruke, kommer til å stole på en rekke ting, for eksempel hvor langt du er fra skjermen og hvor stor skjermen din er, så jeg kan ikke bare gi deg et magisk nummer å bruke. Vi må finne ut det manuelt.
Vi kan gjøre dette ved å prøve mange forskjellige tall en etter en, men dette er kjedelig og vil ta for alltid. Jeg har en bedre ide.
Legg denne linjen til funksjonen onEnterFrame ():
camera2.x = camera.x + (mouseX * 0,1);
Endre nå onClickViewport og onClickViewport2-funksjonene til følgende:
offentlig funksjon onClickViewport (mouseEvt: MouseEvent): void trace (camera2.x - camera.x); offentlig funksjon onClickViewport2 (mouseEvt: MouseEvent): void trace (camera2.x - camera.x);
Kjør SWF, og flytt musen til venstre og høyre. Det ser slik ut:
Sett brillene på, skru av lysene, og hold musen til du finner den "søte flekken" der bildet ser ut til å bli solid. Klikk musen på dette punktet, og det vil spore ut et nummer. Legg merke til det!
Når du har funnet den optimale separasjonen, slett du linjen vi nettopp la til funksjonen onEnterFrame ():
camera2.x = camera.x + (mouseX * 0,1);
Finn nå linjen i Main () hvor du angir avstanden mellom kameraene:
camera2.x = camera.x + 50;
... og erstatt 50 med uansett antall du noterte ned. Jeg fant at 18 var et godt nummer å bruke til oppsettet mitt.
Endelig teste SWF:
Ta-da!
Godt gjort - du har opprettet en 3D-scene i Flash og brukt litt sinnssykdom til å overføre den til en 3D-scene inne i hodet ditt;)
Hvis du har forstått alt du gikk gjennom, bør du kunne bruke samme teknikk for å lage 3D-anaglyph-bilder ved hjelp av andre 3D-motorer.
Jeg nevnte i første del at du kanskje vil prøve å gjøre det mulig for brukeren å flytte kameraet med musen. Nå har du lagt til anaglyph-effekten, og kameraene fremover og bakover vil se veldig imponerende ut.
Takk for at du har lest denne opplæringen, håper du du har funnet det nyttig. Som alltid, hvis du har noen spørsmål, vennligst spør dem i kommentarene nedenfor.