Aktiv kamouflage är ett sci-fi-koncept, vanligtvis sett i form av en kostym som gör att bäraren blir nästan osynlig. Det kan ses i filmer som Predator och Die Another Day, och spel som Halo och Crysis.
Denna handledning visar hur du uppnår en sådan effekt i Flash genom att animera ett förskjutningsfilter med hjälp av en sekvens bitmaps. Inte bara är effekten cool, men den här tekniken ses sällan i online-handledning.
Låt oss ta en titt på det slutliga resultatet vi ska arbeta för:
Förskjutningskartläggning är en texturkarta som används för att modulera förskjutningsstyrkan. Förskjutning betyder att bokstavligen flyttar pixlarna av en yta ur sin plats. I de flesta 3D-applikationer förskjuts pixlarna längs ytan. I Adobe Flash händer förskjutningen i 2D-utrymme, längs X och Y-koordinaterna för en bild.
Förskjutningsfilter i Flash animeras vanligtvis genom att dynamisk ändra intensiteten (skalaX och scaleY parametrar), ändra positionen för förskjutningsbitmappen (mapPoint-parametern) eller genom att manipulera färgkanalerna. Denna handledning kommer att förklara dessa tekniker vidare, men vi studerar också en annan, som använder en bitmap-sekvens för att rita en ny förskjutningskarta på varje ram.
Exempel på förskjutning längs ytan normal.
Exempel på förskjutningskartläggning i blixt, längs X- och Y-axlarna.
Öppna ett nytt dokument i Flash och ställa in storleken till 550x368 så det matchar vår bakgrundsbild. Ställ in bildfrekvensen till 48fps. Förskjutningsfiltret kommer faktiskt att köras vid 12fps, men om du vill ha ytterligare animering senare skulle det se bättre ut vid 48fps.
Klicka på Arkiv> Publicera inställningar> ActionScript 3.0-inställningar och stäng av "auto-declare stage instances".
Importera rainforest.jpg till scenen.
Tryck Ctrl + K för att anpassa och matcha dukstorleken. Detta kommer att bli vår bakgrundsbild.
Nu med den valda bilden trycker du på F8 för att konvertera den till ett Symbol. Välj "Filmklipp" i typmenyn.
Om egenskapsfönstret är stängt trycker du på Ctrl + F3 för att öppna det. Vi kommer att namnge filmklippet som just skapades. I fältet Instansnamn anger du "bkgd_mc".
Tryck nu Ctrl + F8 för att skapa ett nytt filmklipp helt och hållet. Vi nämner inte detta just ännu. Först ska vi importera bitmappsekvensen i detta filmklipp. Gå till Arkiv> Importera> Importera till steg. Välj den första bilden av sekvensen, som kallas "pred0001.jpg". Flash kommer att fråga om du vill importera alla bilder i den här sekvensen. Klicka ja.
Du kommer att märka att varje bitmapp placeras på en nyckelram längs filmklippstidslinjen. Börja med ram 1, välj bilden och tryck på F8 för att dölja den till filmklippet. Gör detta på varje ram tills slutet av sekvensen. Gör det i ordning, från första till sista och se till att du inte hoppa över några ramar, annars kommer det att röra upp animeringen.
När du är klar ska varje nyckelram ha ett filmklipp som innehåller en ram av teckens ansikte. Välj ram en igen och tryck på enter för att se animationen.
Välj filmklippet på ram 1. Högerklicka och fördela till lager. Återigen gör det till alla filmklipp på alla ramar. När du är klar kommer du inte längre kunna se animationen, bara bilden på det översta lagret.
Tryck Ctrl + L för att öppna biblioteket och dra "Symbol 2" till scenen. I fliken Egenskaper namnge denna instans "displ_mc". Detta filmklipp kommer att användas i vårt förskjutningsfilter.
Vi ska skriva koden för vårt förskjutningskartfilter i en dokumentklassfil. Skapa en ny Actionscript-fil och namnge den "pred_as3". Nu klistra in den här koden:
paket import flash.display.MovieClip; importera flash.display.BitmapData; importera flash.display.IBitmapDrawable; importera flash.display.BitmapDataChannel; importera flash.filters.DisplacementMapFilter; importera flash.filters.DisplacementMapFilterMode; importera flash.geom.Point; importera flash.events.Event; offentlig klass pred_as3 utökar MovieClip
Gå tillbaka till flashdokumentet och namnge klassen pred_as3.
Som du kan se har vi redan importerat alla de klasser som vi behöver i den här handledningen, nu ska vi fortsätta skriva dokumentklassen. Lägg till den här koden:
private var clipcont = ny Array (); // Alla animerade ramar kommer att lagras i denna array Private Var Count: Number; // del av enterframe loop berättar vilken animationsram som ska visas privat var timer: uint = 0; // anger hastigheten på animationen allmän var displ_mc: MovieClip; public var bkgd_mc: MovieClip;
Vi anger några variabler som kommer att användas senare. De måste deklareras före klasskonstruktören om de ska användas av mer än en funktion i dokumentklassen.
Längre än sista raden börjar vi skriva parametrarna och konstruktören för förskjutningskartfiltret.
privat var styrka1: int = 120; // värdet av skalaX och skalaY - ställer in intensiteten för förskjutningsfiltret privat var mapBitmap: BitmapData = ny BitmapData (320,240); // storleken på förskjutningskartan i pixlar privat var mapPoint: Punkt = ny Punkt (0,0 ); // positionen för förskjutning bitmapp privat var komponentX = BitmapDataChannel.GREEN; // vilken färgkanal används spelar ingen roll eftersom det är i gråtoner; private var componentY = BitmapDataChannel.GREEN; privat var spe: int = 1; // ändrar styrkan på förskjutningsfiltret // alla variabler appliceras sedan på ett nytt filter privatvarfilter: DisplacementMapFilter = ny DisplacementMapFilter (mapBitmap, mapPoint, componentX, componentY, scaleX, scaleY); private var filterList = new Array (); // en filterlista array.
Så vi har satt parametrar för styrka, storlek, position och RBG-kanal. Låt oss titta närmare på var och en av dessa parametrar ...
Som tidigare nämnts är förskjutningen i blixt endast möjlig längs X- och Y-axlarna. Parametrarna som ställer förskjutningsstyrkan för X och Y är scaleX
och scaleY
respektive. I denna handledning kommer vi att använda samma styrka på både X- och Y-axlarna, så vi använder samma variabla styrka1 för båda parametrarna. Nedan visas ett exempel på förskjutning längs den horisontella axeln, med scaleY inställd på noll (vänster bild) och den vertikala axeln, med skalaX inställd på noll (höger).
Lägg märke till hur storleken är inställd på 320x240. Vi vet redan storleken på bitmapparna i animationen och konstruktören måste ha samma storlek som dem. Om värdet i konstruktören är större än bitmappens storlek, kommer det att bli förskjutning i områden där det inte ska ske. # 808080 grå runt karaktärens huvud är en neutral färg, å andra sidan något område som är tomt, eller en transparent bitmapp skulle faktiskt förskjuta bakgrundsbilden.
Exempel på det värde som anges i konstruktören är större än den faktiska förskjutningskartan: De tomma områdena förskjuter bakgrunden.
Förskjutningsfiltret använder endast en av de 3 RGB-kanalerna på en bitmapp för varje axel. När du använder en färgad bitmapp som en förskjutningskarta kommer varje kanal att ge mycket olika resultat som visas i exemplet nedan. I den här handledningen använder vi en bild i gråtoner, så kanalen är irrelevant. KomponentX och komponentY är inställda på grön, men samma effekt skulle erhållas med hjälp av de röda eller blåa kanalerna.
De olika resultaten som erhållits med den gröna kanalen, den röda kanalen eller den blå kanalen.
Parameter mapPoint anger positionen för förskjutningskartan. Positionen är i förhållande till objektet som det tillämpas på, och inte scenen. Genom att ställa in positionen till (0,0) visas förskjutningskartan i det övre vänstra hörnet av vår bakgrundsbild, som inte alltid sammanfaller med scenens övre vänstra hörn, som visas nedan.
MapPoint-parametern är relativt objektet, inte scenen.
Låt oss nu tillämpa förskjutningsfiltret till vår bakgrundsbild "displ_mc". Förskjutningsfiltret skjuts in i en uppsättning filter, och vi gör det inom klasskonstruktorn. Vi lägger också till våra två huvudfilmer till scenen med addchild-metoden. I AS3 är klasskonstruktorn den första funktionen som ska utföras i en dokumentklass och den heter automatiskt, så det är bättre att alla funktioner eller metoder som måste köras vid laddning kallas inifrån en klasskonstruktor.
offentlig funktion pred_as3 () addChild (displ_mc); addChild (bkgd_mc); // lägg till båda filmklippsinstanserna till scenfiltretList.push (filter); // lägg till förskjutningskartfiltret i arrayen. bkgd_mc.filters = filterList; // tillämpar arrayen av filter till målfilmklippet. storeClips ();
Den sista raden av kod ringer en funktion som ännu inte har skrivits. Som namnet antyder kommer denna funktion att lagra alla animerade filmklipp i en array. Så låt oss gå vidare och skriva det nu.
Så vi skapade ett förskjutningskartfilter och applicerade det på filmklippet, men vi har inte lagt till några bitmappar till filtret ännu. Vi ska göra detta i två steg: Först ska vi lagra animationen i en array, sen kommer vi att lägga till denna animering till filtret.
Private Function StoreClips (): void // lagrar animeringen i en array count = displ_mc.numChildren; // det totala antalet filmklipp inom displ_mc för (var i: int = 0; i < displ_mc.numChildren; i++)//finds all movieclips inside displ_mc clipcont.push(displ_mc.getChildAt(i));// frames are pushed inside the clipcont array
Denna funktion använder a för
loop för att skanna alla filmklipp i displ_mc. Vi vill ha animeringsramarna som konverterades till filmklipp tidigare i denna handledning. Kom ihåg när jag sa att de skulle konvertera ram för ram? Vi gjorde det så att ramarna kunde sorteras ordentligt och senare nås med metoden getChildAt (). Eftersom vi inte namngav några av dessa fall, sorterar Flash dem internt på beställningsordning. Om bitmaparna slumpmässigt konverterades till filmklipp, skulle animationen aldrig spela korrekt. Så ramarna kan nu skjutas in i clipcont array, en efter en.
Koden hittills skulle se ut så här:
paket import flash.display.MovieClip; importera flash.display.BitmapData; importera flash.display.IBitmapDrawable; importera flash.display.BitmapDataChannel; importera flash.filters.DisplacementMapFilter; importera flash.filters.DisplacementMapFilterMode; importera flash.geom.Point; importera flash.events.Event; public class pred_as3 utökar MovieClip private var clipcont = new Array (); // alla animerade ramar lagras i denna array privat var count: Number; // del av enterframe loop berättar vilken animationsram som visas privat var timer: uint = 0; public var displ_mc: MovieClip; public var bkgd_mc: MovieClip; privat var styrka1: int = 120; // anger intensiteten för förskjutningsfiltret privat var mapBitmap: BitmapData = ny BitmapData (320,240); // storleken på förskjutningskartan i pixlar privat var mapPoint: Punkt = ny punkt (0,0); // positionen för Förskjutning bitmapp privat var componentX = BitmapDataChannel.GREEN; // vilken färgkanal används; spelar ingen roll eftersom det är i gråtoner; private var componentY = BitmapDataChannel.GREEN; privat var spe: int = 1; // alla variabler appliceras sedan på ett nytt filter privat varfilter: DisplacementMapFilter = ny DisplacementMapFilter (mapBitmap, mapPoint, componentX, componentY, scaleX, scaleY); private var filterList = new Array (); // en filterlista array. // KLASS CONSTRUCTOR public function pred_as3 () addChild (displ_mc); addChild (bkgd_mc); // lägg till båda Movie Clip-instanser till scenaffärClips (); filterList.push (filter); // lägg till förskjutningsfiltret i arrayen. bkgd_mc.filters = filterList; // applicerar uppsättningen filter till målfilmklippet. Private Function StoreClips (): void // lagrar animeringen i en array count = displ_mc.numChildren; // det totala antalet filmklipp inom displ_mc för (var i: int = 0; i < displ_mc.numChildren; i++)//finds all movieclips inside displ_mc clipcont.push(displ_mc.getChildAt(i));// frames are pushed inside the clipcont array
Nu när vi har animationen klar att använda, låt oss sätta den i förskjutningsfiltret. Vi kommer att komma åt clipcont array med en "time released" loop med hjälp av Event.ENTER_FRAME
klass. Varje 4 ramar öppnas en ny bitmapp i matrisen och appliceras sedan på filtret med hjälp av draw () -metoden. När den sista bilden i clipcont är ritad börjar slingan över och den första bilden i clipcont är ritad. Det är en oändlig loop.
privat funktion animera (e: Event) filter.scaleX = strength1; // anger värdet av skalaY och skalaX filter.scaleY = strength1; om (timer> 3) // en ny ram dras varje 4 ramar om (räkna <= 0) count = clipcont.length;// setting an infinite loop count--; timer = 0; if (clipcont[count]) filter.mapBitmap.draw(clipcont[count]);// a new frame of animation is drawn bkgd_mc.filters = filterList;//updates the filter
Kopiera ovanstående rader till din actionscript-fil. Låt oss nu göra det här genom att lägga till en händelseloggare till klasskonstruktören.
offentlig funktion pred_as3 () addChild (displ_mc); addChild (bkgd_mc); // lägg till båda filmklippsinstanserna till scenfiltretList.push (filter); // lägg till förskjutningskartfiltret i arrayen. bkgd_mc.filters = filterList; // applicerar uppsättningen filter till målfilmklippet. storeClips (); addEventListener (Event.ENTER_FRAME, animera); // kallar animeringsfunktionen på inramningsramen
Uppdatera klasskonstruktorn med addeventlistener
metod. Nu har animationsfunktionen lagts till scenen och kallas på varje ram. Testa effekten genom att trycka på Ctrl + Enter. Du ska se det animerade ansiktet längst upp till vänster på din film.
Vi har en animationsslinga som körs i hörnet av filmen. Låt oss göra förskjutningskartan följ musen så att du kan se hur den aktiva kamouflageffekten ser ut mot olika delar av bakgrunden. Klistra in den här raden inuti animeringsfunktionen:
privat funktion animera (e: Event) filter.scaleY = strength1; // anger värdet av skalaY och skalaX filter.scaleX = strength1; timer ++; om (timer> 3) // en ny ram dras varje 4 ramar om (räkna <= 0) count = clipcont.length;// setting an infinite loop count--; timer = 0; if (clipcont[count]) filter.mapBitmap.draw(clipcont[count]);// a new frame of animation is drawn filter.mapPoint = new Point(mouseX-160, mouseY-240); // displacement map follows the mouse bkgd_mc.filters = filterList;
På det här sättet uppdaterar vi positionen för förskjutningskartan på en frame-basis med hjälp av mouseX- och mouseY-egenskaperna. Tryck Ctrl + Enter för att testa den. Huvudet ska nu följa musen.
I det sista steget i denna handledning kommer vi att spela lite med styrkan i vårt filter, vilket ökar värdet för scaleX och scaleY parametrar över en tidsperiod och minskar sedan tillbaka till det ursprungliga värdet. Det vi försöker uppnå med detta är att få effekten att se mer dynamisk och ... synlig. Medan hela kamouflagepunkten i det verkliga livet borde vara att göra saker mindre synliga, är det vi försöker göra här att få det att se coolt ut. Låt oss frysa animationen så att du kan förstå vad jag pratar om. I animeringsfunktionen, byt ut linjen
filter.mapBitmap.draw (clipcont [count]);
med den här raden istället:
filter.mapBitmap.draw (clipcont [20]);
I stället för att skriva animationen berättar vi om att vi ska dra samma ram om och om igen. Tryck Ctrl + Enter för att testa den.
Effekten ser helt statisk ut och tråkig. Låt oss ge det lite rörelse. Klistra in koden nedan inuti animeringsfunktionen:
privat funktion animera (e: Event) filter.scaleY = strength1; // uppdaterar värdet av skalaY och scaleX filter.scaleX = strength1; timer ++; om (timer> 3) // en ny ram dras varje 4 ramar om (räkna <= 0) count = clipcont.length;// setting an infinite loop count--; timer = 0; if (clipcont[count]) filter.mapBitmap.draw(clipcont[20]);// a new frame of animation is drawn filter.mapPoint = new Point(mouseX-160, mouseY-240); // displacement map follows the mouse if (filter.scaleX > 220 || filter.scaleX < 120) // filter keeps changing it's intensity, making the effect more dynamic spe *= -1; strength1 += spe; bkgd_mc.filters = filterList;
Testa det med Ctrl + Enter.
Se hur mycket bättre ser det ut? Okej så att du nu kan återställa animeringen, fixa raden som har ändrats:
filter.mapBitmap.draw (clipcont [count]);
Denna effekt är också till hjälp om du vill fästa en statisk kropp på ansiktsanimationen senare. Det skulle se mer aktivt ut bredvid bitmap-animationen.
Filen kan vara lite tung om du använder jpeg-kvalitet 100, vilket är vad jag rekommenderar. I en lägre kvalitet förlorar effekten en bit av sin charm. Om du vill ha en mindre film kan du komprimera bilderna ännu mer i Photoshop, men se till att du håller färgschemat rätt. Färgen runt karaktärens huvud ska alltid vara # 808080 eller så får du se en låda runt den.
Så det här är det. Den första handledningen jag någonsin har skrivit, det var roligt att göra det och jag hoppas att du hade kul att läsa och använda det bra. Jag skulle verkligen uppskatta din feedback. Tack för att du läser!