Actieve camouflage is een sci-fi-concept, meestal te zien in de vorm van een pak waarmee de drager bijna onzichtbaar kan worden. Het is te zien in films als Predator en Die Another Day, en games zoals Halo en Crysis.
In deze zelfstudie leert u hoe u een dergelijk effect in Flash kunt bereiken door een verplaatsingsfilter te animeren met behulp van een reeks bitmaps. Het effect is niet alleen cool, maar deze techniek komt zelden voor in online tutorials.
Laten we eens kijken naar het eindresultaat waar we naartoe zullen werken:
Verplaatsingstoewijzing is een structuurkaart die wordt gebruikt om de verplaatsingssterkte te moduleren. Verplaatsing betekent letterlijk de pixels van een oppervlak op zijn plaats verplaatsen. In de meeste 3D-toepassingen worden de pixels verplaatst langs de normaal van het oppervlak. In Adobe Flash vindt de verplaatsing plaats in 2D-ruimte, langs de X- en Y-coördinaten van een afbeelding.
Verplaatsingsfilters in Flash worden meestal geanimeerd door hun intensiteit (de scaleX- en scaleY-parameters) dynamisch te wijzigen, de positie van de verplaatsingbitmap (de mapPoint-parameter) te wijzigen of door de kleurkanalen te manipuleren. Deze tutorial zal deze technieken nader toelichten, maar we zullen ook een andere bestuderen, die een bitmapsequentie gebruikt om een nieuwe verplaatsingskaart op elk frame te tekenen.
Voorbeeld van verplaatsing langs de normaal van het oppervlak.
Voorbeeld van verplaatsingstoewijzing in flash langs de X- en Y-assen.
Open een nieuw document in Flash en stel het formaat in op 550x368 zodat het overeenkomt met onze achtergrondafbeelding. Stel de framesnelheid in op 48 fps. Het verplaatsingsfilter werkt eigenlijk met 12 fps, maar in het geval dat je later extra animatie wilt, ziet het er soepeler uit bij 48 fps.
Klik op Bestand> Publicatie-instellingen> ActionScript 3.0-instellingen en schakel "auto-declare stage instances" uit.
Importeer rainforest.jpg naar het podium.
Druk op Ctrl + K om de canvasgrootte uit te lijnen en te matchen. Dit wordt onze achtergrondafbeelding.
Nu met de afbeelding geselecteerd, drukt u op F8 om het naar een symbool te converteren. Selecteer "Movie Clip" in het type menu.
Als het eigenschappenvenster gesloten is, drukt u op Ctrl + F3 om het te openen. We gaan de filmclip een naam geven die zojuist is gemaakt. Typ "bkgd_mc" in het veld van de instantienaam.
Druk nu op Ctrl + F8 om een nieuwe filmclip helemaal te maken. We noemen dit nog niet. Eerst gaan we de bitmapsequentie in deze filmclip importeren. Ga naar Bestand> Importeren> Importeren naar werkgebied. Selecteer de eerste afbeelding van de reeks, die "pred0001.jpg" wordt genoemd. Flash vraagt of je alle afbeeldingen in deze volgorde wilt importeren. Klik op Ja.
U zult opmerken dat elke bitmap op een hoofdframe langs de tijdlijn van de filmclip wordt geplaatst. Begin met frame 1, selecteer de afbeelding en druk op F8 om deze naar filmclip te verbergen. Doe dit op elk frame tot het einde van de reeks. Doe het in volgorde, van het begin tot het einde en zorg ervoor dat je geen frames overslaat, anders zal het de animatie verpesten.
Als je klaar bent, moet elk sleutelframe één filmclip bevatten met een kader van het gezicht van het personage. Selecteer frame één opnieuw en druk op enter om de animatie te zien.
Selecteer de filmclip in frame 1. Klik met de rechtermuisknop en verdeel naar lagen. Nogmaals, doe het aan alle filmfragmenten op alle frames. Als je klaar bent, kun je de animatie niet meer zien, alleen de afbeelding op de bovenste laag.
Druk op Ctrl + L om de bibliotheek te openen en sleep "Symbool 2" naar het werkgebied. Op het tabblad Eigenschappen van dit exemplaar "displ_mc". Deze filmclip wordt gebruikt in ons verplaatsingsfilter.
We gaan de code voor ons verplaatsingkaartfilter in een documentklassebestand schrijven. Maak een nieuw Actionscript-bestand en noem dit "pred_as3". Plak nu deze code:
pakket import flash.display.MovieClip; import flash.display.BitmapData; import flash.display.IBitmapDrawable; import flash.display.BitmapDataChannel; import flash.filters.DisplacementMapFilter; import flash.filters.DisplacementMapFilterMode; import flash.geom.Point; import flash.events.Event; openbare klasse pred_as3 verlengt MovieClip
Ga terug naar het flash-document en noem de klasse pred_as3.
Zoals je ziet hebben we al de klassen die we nodig zullen hebben geïmporteerd in deze tutorial, laten we nu verder gaan met het schrijven van de documentklasse. Voeg deze code eraan toe:
private var clipcont = new Array (); // alle geanimeerde frames worden opgeslagen in deze array private var count: Number; // deel van de enterframe-lus; vertelt welk frame van animatie private var timer wordt getoond: uint = 0; // bepaalt de snelheid van de animatie openbaar var displ_mc: MovieClip; public var bkgd_mc: MovieClip;
We vermelden een aantal variabelen die later zullen worden gebruikt. Ze moeten voor de klasse-constructor worden gedeclareerd als ze door meer dan één functie in de documentklasse moeten worden gebruikt.
Direct onder de laatste regel beginnen we de parameters en de constructor van het verplaatsingskaartfilter te schrijven.
private var strength1: int = 120; // de waarde van scaleX en scaleY - stelt de intensiteit in van het verplaatsingsfilter private var mapBitmap: BitmapData = nieuwe BitmapData (320,240); // de grootte van de verplaatsingskaart in pixels private var mapPoint: Point = new Point (0,0 ); // de positie van de verplaatsingsbitmap private var componentX = BitmapDataChannel.GREEN; // welk kleurkanaal wordt gebruikt; maakt niet echt uit, omdat het in grijstinten is; private var componentY = BitmapDataChannel.GREEN; private var spe: int = 1; // wijzigt de sterkte van het verplaatsingsfilter // alle variabelen worden vervolgens toegepast op een nieuw filter prive-var-filter: DisplacementMapFilter = nieuw DisplacementMapFilter (mapBitmap, mapPoint, componentX, componentY, scaleX, scaleY); private var filterList = new Array (); // een filterlijstarray.
Daarom hebben we parameters ingesteld voor sterkte, grootte, positie en RBG-kanaal. Laten we elk van deze parameters eens nader bekijken ...
Zoals eerder vermeld, is verplaatsing in flits alleen mogelijk langs de X- en Y-assen. De parameters die de verplaatsingssterkte voor X en Y instellen, zijn scaleX
en scaleY
respectievelijk. In deze zelfstudie gebruiken we dezelfde sterkte op zowel X- als Y-assen, dus we gebruiken dezelfde variabele sterkte1 voor beide parameters. Hieronder ziet u een voorbeeld van verplaatsing langs de horizontale as, met schaal ingesteld op nul (linker afbeelding) en de verticale as, met scaleX ingesteld op nul (rechts).
Merk op hoe de grootte is ingesteld op 320x240. We weten al de grootte van de bitmaps in de animatie en de constructor moet dezelfde grootte hebben als deze. Als de waarde in de constructor groter is dan die van de bitmaps, zal er verplaatsing zijn in gebieden waar dit niet zou moeten gebeuren. De # 808080 grijs rond het hoofd van het personage is een neutrale kleur, aan de andere kant elk gebied dat leeg is, of een transparante bitmap zou de achtergrondafbeelding verdringen.
Voorbeeld van de waarde die in de constructor is ingesteld die groter is dan de werkelijke verplaatsingskaart: de lege gebieden verplaatsen de achtergrond.
Het verplaatsingsfilter gebruikt slechts één van de drie RGB-kanalen op een bitmap voor elke as. Wanneer een gekleurde bitmap als verplaatsingskaart wordt gebruikt, geeft elk kanaal zeer verschillende resultaten, zoals in het onderstaande voorbeeld. In deze zelfstudie gebruiken we een afbeelding in grijstinten, dus het kanaal is niet relevant. ComponentX en componentY zijn ingesteld op groen, maar hetzelfde effect zou worden verkregen met behulp van de rode of blauwe kanalen.
De verschillende resultaten verkregen met behulp van het groene kanaal, rode kanaal of het blauwe kanaal.
De parameter mapPoint bepaalt de positie van de verplaatsingskaart. De positie is relatief ten opzichte van het object waarop deze is toegepast en niet de fase. Door de positie in te stellen op (0,0), verschijnt de verplaatsingskaart in de linkerbovenhoek van onze achtergrondafbeelding, die niet altijd samenvalt met de linkerbovenhoek van de etappe, zoals hieronder weergegeven.
De mapPoint-parameter is relatief ten opzichte van het object, niet de stage.
Laten we nu het verplaatsingsfilter toepassen op onze achtergrondafbeelding "displ_mc". Het verplaatsingsfilter wordt in een reeks filters geschoven en we doen dit in de klasseconstructor. We voegen ook onze twee belangrijkste filmclips toe aan het podium met de addchild-methode. In AS3 is de klasse-constructor de eerste functie die moet worden uitgevoerd in een documentklasse en deze wordt automatisch aangeroepen, dus het is beter dat alle functies of methoden die tijdens het laden moeten worden uitgevoerd, worden aangeroepen vanuit een klasseconstructor.
openbare functie pred_as3 () addChild (displ_mc); addChild (bkgd_mc); // voeg beide filmclipinstanties toe aan de stage filterList.push (filter); // voeg het verplaatsingskaartfilter toe aan de array. bkgd_mc.filters = filterList; // past de reeks filters toe op de doelfilmclip. storeClips ();
De laatste regel code roept een functie op die nog niet is geschreven. Zoals de naam al doet vermoeden, zal deze functie alle geanimeerde filmclips in een array opslaan. Dus laten we doorgaan en dat nu schrijven.
Daarom hebben we een filter voor verplaatsingskaarten gemaakt en dit toegepast op de filmclip, maar we hebben nog geen bitmaps aan het filter toegevoegd. We gaan dit in twee stappen doen: eerst gaan we de animatie in een array opslaan, later zullen we deze animatie aan het filter toevoegen.
private function storeClips (): void // slaat de animatie op in een array count = displ_mc.numChildren; // het totale aantal filmclips in displ_mc voor (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
Deze functie gebruikt a voor
loop om alle filmclips in displ_mc te scannen. We willen de animatieframes die eerder in deze tutorial zijn geconverteerd naar filmclips. Weet je nog toen ik zei om ze beeld voor beeld te converteren? We hebben dat gedaan, zodat de frames correct konden worden gesorteerd en later konden worden benaderd met de methode getChildAt (). Omdat we geen van deze instanties hebben benoemd, sorteert Flash ze intern in volgorde van creatie. Als de bitmaps willekeurig in filmclips werden omgezet, zou de animatie nooit correct worden afgespeeld. De frames kunnen nu één voor één in de clipcont-array worden geschoven.
De code tot nu toe zou er als volgt uit moeten zien:
pakket import flash.display.MovieClip; import flash.display.BitmapData; import flash.display.IBitmapDrawable; import flash.display.BitmapDataChannel; import flash.filters.DisplacementMapFilter; import flash.filters.DisplacementMapFilterMode; import flash.geom.Point; import flash.events.Event; public class pred_as3 breidt MovieClip uit private var clipcont = new Array (); // alle geanimeerde frames worden opgeslagen in deze array private var count: Number; // deel van de enterframe-lus; vertelt welk frame van animatie wordt getoond private var timer: uint = 0; public var displ_mc: MovieClip; public var bkgd_mc: MovieClip; private var strength1: int = 120; // stelt de intensiteit in van het verplaatsingsfilter private var mapBitmap: BitmapData = nieuwe BitmapData (320,240); // de grootte van de verplaatsingskaart in pixels private var mapPoint: Point = new Point (0,0); // de positie van de verplaatsingbitmap private var componentX = BitmapDataChannel.GREEN; // welk kleurkanaal wordt gebruikt; maakt niet echt uit, omdat het in grijstinten is; private var componentY = BitmapDataChannel.GREEN; privé var spe: int = 1; // alle variabelen worden vervolgens toegepast op een nieuw filter voor privé-var: DisplacementMapFilter = new DisplacementMapFilter (mapBitmap, mapPoint, componentX, componentY, scaleX, scaleY); private var filterList = new Array (); // een filterlijstarray. // CLASS CONSTRUCTOR openbare functie pred_as3 () addChild (displ_mc); addChild (bkgd_mc); // voeg beide Movie Clip-instanties toe aan de stage storeClips (); filterList.push (filter); // voeg het verplaatsingsfilter toe aan de array. bkgd_mc.filters = filterList; // past de filterset toe op de doelfilmclip. private function storeClips (): void // slaat de animatie op in een array count = displ_mc.numChildren; // het totale aantal filmclips in displ_mc voor (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 we de animatie klaar voor gebruik hebben, laten we deze in het verplaatsingsfilter plaatsen. We gaan naar de clipcont array met een "time released" lus met behulp van de Event.ENTER_FRAME
klasse. Elke 4 frames wordt een nieuwe bitmap in de array geopend en vervolgens toegepast op het filter met behulp van de methode draw (). Nadat het laatste frame in clipcont is getekend, begint de lus opnieuw en wordt het eerste frame in clipcont getekend. Het is een eindeloze lus.
privé-functie animeren (e: Event) filter.scaleX = sterkte1; // stelt de waarde in van scaleY en scaleX filter.scaleY = strength1; if (timer> 3) // om de 4 frames wordt een nieuw frame getekend if (count <= 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
Kopieer de bovenstaande regels naar uw actionscript-bestand. Laten we dit nu uitvoeren door een gebeurtenislistener toe te voegen aan de klassenconstructor.
openbare functie pred_as3 () addChild (displ_mc); addChild (bkgd_mc); // voeg beide filmclipinstanties toe aan de stage filterList.push (filter); // voeg het verplaatsingskaartfilter toe aan de array. bkgd_mc.filters = filterList; // past de filterset toe op de doelfilmclip. storeClips (); addEventListener (Event.ENTER_FRAME, animeren); // roept de animatiefunctie op enter frame
Werk de klassenconstructor bij met de addEventListener
methode. Nu is de animatiefunctie aan het podium toegevoegd en wordt op elk frame opgeroepen. Test het effect door op Ctrl + Enter te drukken. Je zou het geanimeerde gezicht in de linkerbovenhoek van je film moeten zien.
We hebben een animatielus in de hoek van de film. Laten we de verplaatsingskaart volgen met de muis, op deze manier kunt u zien hoe het actieve camouflage-effect tegen verschillende delen van de achtergrond aankijkt. Plak deze regel in de animatiefunctie:
privéfunctie animeren (e: Event) filter.scaleY = sterkte1; // stelt de waarde in van scaleY en scaleX filter.scaleX = strength1; timer ++; if (timer> 3) // om de 4 frames wordt een nieuw frame getekend if (count <= 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;
Op deze manier werken we de positie van de verplaatsingskaart op basis van het enterframe bij met behulp van de eigenschappen mouseX en mouseY. Druk op Ctrl + Enter om het te testen. Het hoofd zou nu de muis moeten volgen.
In de laatste stap van deze tutorial gaan we een klein beetje spelen met de kracht van ons filter, waardoor de waarde van de scaleX- en scaleY-parameters in de loop van de tijd toeneemt, en dan terug naar de beginwaarde. Wat we hiermee proberen te bereiken, is om het effect er dynamischer en ... zichtbaarer te laten uitzien. Hoewel het de bedoeling van een echte camouflage in het echte leven is om dingen minder zichtbaar te maken, proberen we het er hier cool uit te laten zien. Laten we de animatie bevriezen zodat je kunt begrijpen waar ik het over heb. Vervang de regel in de animatiefunctie
filter.mapBitmap.draw (clipcont [count]);
met deze regel in plaats daarvan:
filter.mapBitmap.draw (clipcont [20]);
In plaats van het tekenen van de animatie, vertellen we flash om hetzelfde frame steeds opnieuw te tekenen. Druk op Ctrl + Enter om het te testen.
Het effect ziet er volkomen statisch en saai uit. Laten we het een beetje bewegen. Plak de onderstaande code in de animatiefunctie:
privéfunctie animeren (e: Event) filter.scaleY = sterkte1; // werkt de waarde van scaleY en scaleX filter bij. scaleX = strength1; timer ++; if (timer> 3) // om de 4 frames wordt een nieuw frame getekend if (count <= 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;
Test het nu met Ctrl + Enter.
Zie je hoe veel beter het eruit ziet? Oké, je kunt nu de animatie herstellen, de regel corrigeren die is gewijzigd:
filter.mapBitmap.draw (clipcont [count]);
Dit effect is ook handig als u later een statisch lichaam aan de gezichtsanimatie wilt hechten. Het zou er actiever uitzien naast de bitmap-animatie.
Het bestand kan een beetje zwaar zijn als je jpeg-kwaliteit 100 gebruikt, wat ik aanraad. In een lagere kwaliteit verliest het effect een beetje zijn charme. Als je een kleinere film wilt, kun je de afbeeldingen nog meer comprimeren in photoshop, maar zorg er wel voor dat je het kleurenschema goed houdt. De kleur rond het hoofd van het personage moet altijd # 808080 zijn, anders zie je een kader eromheen.
Dus dit is het. De eerste zelfstudie die ik ooit heb geschreven, het was leuk om het te doen en ik hoop dat je het leuk vond om te lezen en er goed gebruik van te maken. Ik zou uw feedback zeer op prijs stellen. Bedankt voor het lezen!