Hvordan bruke Android Media effekter med OpenGL ES

How å bruke Android Media effekter med OpenGL ES
24
Del
to
Del

Denne Cyber ​​Monday Envato Tuts + kurs vil bli redusert til bare $ 3. Ikke gå glipp av.

Android Media Effects rammeverket tillater utviklere å enkelt bruke masse imponerende visuelle effekter på bilder og videoer. Som ramme bruker GPU til å utføre alle sine bildebehandling operasjoner, kan det bare akseptere OpenGL teksturer som sin inngang. I denne opplæringen, skal du lære å bruke OpenGL ES 2.0 for å konvertere en teikne ressurs inn i en tekstur og deretter bruke rammeverket til å bruke ulike effekter for det.

Forutsetninger

For å følge denne opplæringen, må du ha:

en IDE som støtter Android programutvikling. Hvis du ikke har en, få den nyeste versjonen av Android Studio fra Android Developer nettstedet.

  • en enhet som kjører Android 4.0 + og har en GPU som støtter OpenGL ES 2.0. Anmeldelser

    en grunnleggende forståelse av OpenGL.

    1. Sette opp OpenGL ES Miljø

    Trinn 1: Lag en GLSurfaceView

    For å vise OpenGL-grafikk i programmet ditt, må du bruke en GLSurfaceView objekt. Som alle andre View, kan du legge det til en aktivitet eller Fragment ved å definere det i en layout XML fil eller ved å opprette en forekomst av det i kode.

    I denne opplæringen, du kommer til å ha en GLSurfaceView objekt som den eneste visningen i din aktivitet. Derfor skaper det i kode er enklere. Når den er laget, gi det til setContentView metode slik at det fyller hele skjermen. Din aktivitet er onCreate metode skal se slik ut:
    beskyttet void onCreate (Bundle savedInstanceState) {super.onCreate (savedInstanceState); GLSurfaceView view = new GLSurfaceView (denne); setContentView (vis);}

    Fordi Media Effects rammeverket bare støtter OpenGL ES 2.0 eller høyere, passerer verdien 2 til setEGLContextClientVersion metoden
    view.setEGLContextClientVersion (2);.

    For å være sikker at GLSurfaceView gjengir innholdet bare når det er nødvendig, passerer verdien RENDERMODE_WHEN_DIRTY til setRenderMode metoden
    view.setRenderMode (GLSurfaceView.RENDERMODE_WHEN_DIRTY);
    Trinn 2:. Lag en Renderer

    En GLSurfaceView.Renderer er ansvarlig for å tegne innholdet i GLSurfaceView.

    Opprett en ny klasse som implementerer GLSurfaceView.Renderer grensesnittet. Jeg kommer til å kalle denne klassen EffectsRenderer. Etter å legge en konstruktør og overstyrer alle metoder for grensesnittet, bør klassen se slik ut:
    public class EffectsRenderer implementerer GLSurfaceView.Renderer {public EffectsRenderer (Context kontekst) {super (); }Override Public void onSurfaceCreated (GL10 gl, EGLConfig config) {}Override public void onSurfaceChanged (GL10 gl, int bredde, int høyde) {}Override public void onDrawFrame (GL10 gl) {}}

    Gå tilbake til aktivitets og ringe setRenderer metode, slik at GLSurfaceView bruker tilpassede renderer
    view.setRenderer (ny EffectsRenderer (denne));
    Trinn 3:. Rediger Manifest

    Hvis du planlegger å publisere app på Google Play, legg følgende til AndroidManifest.xml:
    < bruker-feature android: glEsVersion = "0x00020000" android: påbudt = "true" />

    Dette gjør at din app kan bare installeres på enheter som støtter OpenGL ES 2.0. OpenGL miljø er nå klar.

    2. Opprette en OpenGL Plane

    Trinn 1: Definer Toppunkter

    GLSurfaceView kan ikke vise et bilde direkte. Bildet må konverteres til en tekstur og brukes på en OpenGL form først. I denne opplæringen vil vi skape et 2D-plan som har fire hjørner. For enkelhets skyld, la oss gjøre det til en firkant. Opprett en ny klasse, Kvadrat, for å representere torget.
    Public class Square {}

    Standard OpenGL koordinatsystem har sin opprinnelse i midten. Som et resultat av koordinatene til de fire hjørner av vår kvadrat, som har sider er to enheter lenge, vil være:

    nederst i venstre hjørne på (-1, -1)

    nederst i høyre hjørne på (1, -1)

    øverst i høyre hjørne på (1, 1)

    øverst i venstre hjørne på (-1, 1)

    Alle de objektene vi tegner ved hjelp av OpenGL bør bestå av trekanter. Å tegne kvadrat, trenger vi to trekanter med en felles kant. Dette betyr at koordinatene av trekantene vil være:

    trekanten 1: (-1, -1), (1, -1) og (-1, 1)
    trekant to: (1 , -1), (-1, 1) og (1, 1)

    Opprett en dupp array å representere disse knutepunktene
    privat float ekser [] = {-1f,. - 1f, 1f, -1f, -1f, 1f, 1f, 1f,};

    For å kartlegge strukturen på torget, må du angi koordinatene til hjørnene i tekstur. Tekstur følge et koordinatsystem hvor verdien av y-koordinaten øker når man går høyere. Lag en matrise for å representere punktene av tekstur
    private float textureVertices [] = {0f, 1f, 1f, 1f, 0f, 0f, 1f, 0f};
    Trinn 2:. Lag Buffer Objects Anmeldelser

    De matriser av koordinater må konverteres til byte buffere før OpenGL kan bruke dem. La oss erklære disse buffere første
    privat FloatBuffer verticesBuffer;. Privat FloatBuffer textureBuffer;

    Skriv inn koden for å initialisere disse buffere i en ny metode som kalles initializeBuffers. Bruk ByteBuffer.allocateDirect metode for å lage bufferen. Fordi en dupp bruker 4 bytes, må du multiplisere størrelsen på arrays med verdien 4.

    Deretter bruker ByteBuffer.nativeOrder å bestemme byte rekkefølge av det underliggende innfødte plattform, og angi rekkefølgen på buffere til denne verdien. Bruk asFloatBuffer metode for å konvertere ByteBuffer eksempel i en FloatBuffer. Etter FloatBuffer er opprettet, kan du bruke put metoden å laste matrisen inn i buffer. Til slutt bruker posisjonen metoden for å sørge for at bufferen leses fra begynnelsen

    Innholdet i initializeBuffers metoden bør se slik ut:.
    Private void initializeBuffers () {ByteBuffer buff = ByteBuffer.allocateDirect (vertices.length * 4); buff.order (ByteOrder.nativeOrder ()); verticesBuffer = buff.asFloatBuffer (); verticesBuffer.put (hjørner); verticesBuffer.position (0); buff = ByteBuffer.allocateDirect (textureVertices.length * 4); buff.order (ByteOrder.nativeOrder ()); textureBuffer = buff.asFloatBuffer (); textureBuffer.put (textureVertices); textureBuffer.position (0);}
    Trinn 3: Lag Shaders

    Det er på tide å skrive dine egne shaders. Shaders er ikke annet enn enkle C-programmer som kjøres av GPU til å behandle hver enkelt toppunktet. For denne opplæringen, må du lage to shaders, et toppunkt shader og et fragment shader

    C-kode for toppunktet shader er:.
    Attributtet vec4 aPosition; tilskriver vec2 aTexPosition; varierende vec2 vTexPosition; void main () {gl_Position = aPosition; vTexPosition = aTexPosition; };

    C-kode for fragment shader er:
    presisjon mediump flyte; uniform sampler2D uTexture; varierende vec2 vTexPosition; void main () {gl_FragColor = texture2D (uTexture, vTexPosition); };

    Hvis du allerede vet OpenGL, bør denne koden være kjent for deg, fordi det er vanlig på tvers av alle plattformer. Hvis du ikke gjør det, for å forstå disse programmene må du se dokumentasjonen OpenGL. Her er en kort forklaring å komme i gang:

    vertex shader er ansvarlig for å tegne de enkelte hjørner. aPosition er en variabel som vil bli bundet til FloatBuffer som inneholder koordinatene til hjørnene. Tilsvarende er aTexPosition en variabel som skal bli bundet til FloatBuffer som inneholder koordinatene til tekstur. gl_Position er en innebygd OpenGL variabel og representerer posisjonen til hver toppunktet. Den vTexPosition er en varierende variabel, der verdien er rett og slett overlevert til fragment shader.

  • I denne opplæringen, er det fragment shader ansvarlig for farging torget. Den plukker opp fargene fra teksturen ved hjelp av texture2D metode og tildeler dem til fragmentet ved hjelp av en innebygd variabel kalt gl_FragColor.

    shader kode må være representert som String objekter i .
    klasse privat endelige String vertexShaderCode = "attributt vec4 aPosition;" + "Attributt vec2 aTexPosition;" + "Varierende vec2 vTexPosition;" + "Void main () {" + "gl_Position = aPosition;" + "VTexPosition = aTexPosition;" + "}"; Privat endelige String fragmentShaderCode = "presisjon mediump flyte;" + "Uniform sampler2D uTexture;" + "Varierende vec2 vTexPosition;" + "Void main () {" + "gl_FragColor = texture2D (uTexture, vTexPosition);" + "}";
    Trinn 4:. Lag et program

    Opprett en ny metode som kalles initializeProgram å skape et OpenGL-program etter å kompilere og linke de shaders

    Bruk glCreateShader å skape en skyggelegger objekt og returnere en referanse til den i form av en int. For å opprette en vertex shader, passerer verdien GL_VERTEX_SHADER til det. Tilsvarende, for å skape et fragment shader, passerer verdien GL_FRAGMENT_SHADER til det. Neste bruker glShaderSource å assosiere riktig shader kode med shader. Bruk glCompileShader å kompilere shader kode.

    Etter kompilering begge shaders, opprette et nytt program ved hjelp glCreateProgram. Akkurat som glCreateShader, også returnerer dette til en int som en referanse til programmet. Ring glAttachShader å feste shaders til programmet. Til slutt, ring glLinkProgram å knytte programmet

    Din metode og tilhørende variabler bør se slik ut:.
    Private int vertexShader; private int fragmentShader; private int program; private void initializeProgram () { vertexShader = GLES20.glCreateShader (GLES20.GL_VERTEX_SHADER); GLES20.glShaderSource (vertexShader, vertexShaderCode); GLES20.glCompileShader (vertexShader); fragmentShader = GLES20.glCreateShader (GLES20.GL_FRAGMENT_SHADER); GLES20.glShaderSource (fragmentShader, fragmentShaderCode); GLES20.glCompileShader (fragmentShader); Program = GLES20.glCreateProgram (); GLES20.glAttachShader (program, vertexShader); GLES20.glAttachShader (program, fragmentShader); GLES20.glLinkProgram (program);}

    Du har kanskje lagt merke til at OpenGL metoder (de metoder innledes med gl) tilhører klassen GLES20. Dette er fordi vi bruker OpenGL ES 2.0. Hvis du ønsker å bruke en nyere versjon, så må du bruke klassene GLES30 eller GLES31

    Trinn 5:. Tegn Square

    Opprett en ny metode som kalles uavgjort til faktisk tegne plassen ved hjelp av hjørner og shaders vi definerte tidligere

    Her er hva du trenger å gjøre i denne metoden.


      Bruk glBindFramebuffer å opprette en navngitt ramme buffer objekt (ofte kalt FBO).

      Bruk glUseProgram å begynne å bruke programmet vi bare sammen.

      Pass verdien GL_BLEND å glDisable å deaktivere blanding av farger mens gjengivelse. < .no>
      Bruk glGetAttribLocation å få en hånd til de variablene aPosition og aTexPosition nevnt i toppunktet shader kode.

      Bruk glGetUniformLocation å få en hånd til den konstante uTexture nevnt i fragment shader kode.

      Bruk glVertexAttribPointer å knytte aPosition og aTexPosition håndterer med verticesBuffer og textureBuffer hhv.

      Bruk glBindTexture å binde teksturen (vedtatt som et argument til trekningen metoden) til fragment shader.

      Slett innholdet i GLSurfaceView bruker glClear.

      Til slutt bruker glDrawArrays metoden å faktisk trekke de to trekanter ( og dermed torget)

      Koden for trekningen metoden bør se slik ut:.
      public void uavgjort (int tekstur) {GLES20.glBindFramebuffer (GLES20.GL_FRAMEBUFFER , 0); GLES20.glUseProgram (program); GLES20.glDisable (GLES20.GL_BLEND); int positionHandle = GLES20.glGetAttribLocation (program, "aPosition"); int textureHandle = GLES20.glGetUniformLocation (program, "uTexture"); int texturePositionHandle = GLES20.glGetAttribLocation (program, "aTexPosition"); GLES20.glVertexAttribPointer (texturePositionHandle, 2, GLES20.GL_FLOAT, falsk, 0, textureBuffer); GLES20.glEnableVertexAttribArray (texturePositionHandle); GLES20.glActiveTexture (GLES20.GL_TEXTURE0); GLES20.glBindTexture (GLES20.GL_TEXTURE_2D, tekstur); GLES20.glUniform1i (textureHandle, 0); GLES20.glVertexAttribPointer (positionHandle, 2, GLES20.GL_FLOAT, falsk, 0, verticesBuffer); GLES20.glEnableVertexAttribArray (positionHandle); GLES20.glClear (GLES20.GL_COLOR_BUFFER_BIT); GLES20.glDrawArrays (GLES20.GL_TRIANGLE_STRIP, 0, 4);
      offentlig Square () {initializeBuffers}

      Legg til en konstruktør til klassen å initial bufferne og programmet på tidspunktet for objektoppretting (.); initializeProgram ();}
      3. Rendering OpenGL Plane og Texture

      Foreløpig gjør vår renderer ingenting. Vi trenger å endre det slik at det kan gjengi flyet vi opprettet i forrige trinn.

      Men først, la oss lage en Bitmap. Legg et bilde til prosjektets res /teikne mappe. Filen jeg bruker heter forest.jpg. Bruk BitmapFactory å konvertere bilder til en Bitmap objekt. Også lagre dimensjonene av Bitmap objektet i separate variabler

      Endre konstruktøren av EffectsRenderer klassen slik at den har følgende innhold:.
      Privat Bitmap bilder; private int photoWidth , photoHeight, offentlig EffectsRenderer (Context kontekst) {super (); foto = BitmapFactory.decodeResource (context.getResources (), R.drawable.forest); photoWidth = photo.getWidth (); photoHeight = photo.getHeight ();}

      Opprett en ny metode som kalles generateSquare å konvertere punktgrafikk til en tekstur og klargjøre en Square objekt. Du vil også trenge en rekke heltall å holde referanser til OpenGL teksturer. Bruk glGenTextures å initialisere array og glBindTexture å aktivere tekstur ved indeks 0.

      Deretter bruker glTexParameteri å sette opp ulike egenskaper som avgjør hvordan teksturen er gjengitt:

      Still GL_TEXTURE_MIN_FILTER (den forminsker funksjon) og GL_TEXTURE_MAG_FILTER (forstørrelsesfunksjon) til GL_LINEAR å sørge for at teksturen ser glatt, selv når den er strukket eller krympet.

      Set GL_TEXTURE_WRAP_S og GL_TEXTURE_WRAP_T å GL_CLAMP_TO_EDGE slik at teksturen er aldri gjentas.

      Til slutt bruker texImage2D metode for å kartlegge Bitmap til teksturen. Gjennomføringen av generateSquare metoden skal se slik ut:
      private int teksturer [] = new int [2]; privat Square square; private void generateSquare () {GLES20.glGenTextures (2, teksturer, 0); GLES20.glBindTexture (GLES20.GL_TEXTURE_2D, teksturer [0]); GLES20.glTexParameteri (GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR); GLES20.glTexParameteri (GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR); GLES20.glTexParameteri (GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE); GLES20.glTexParameteri (GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE); GLUtils.texImage2D (GLES20.GL_TEXTURE_2D, 0, foto, 0); square = new Square ();}

      Når dimensjonene på GLSurfaceView endringen er onSurfaceChanged metoden i Renderer kalles. Her er der du må ringe glViewPort å spesifisere nye dimensjoner av synsfeltet. Også kaller glClearColor å male GLSurfaceView svart. Deretter kaller generateSquare å initial teksturer og flyet
      Overridepublic void onSurfaceChanged (GL10 gl, int bredde, int høyde) {GLES20.glViewport (0,0, bredde, høyde).; GLES20.glClearColor (0,0,0,1); generateSquare ();}

      Til slutt ringe Square objektets uavgjort metode inne i onDrawFrame metoden i Renderer
      Overridepublic void onDrawFrame (GL10 gl) {square.draw (teksturer [0]);}.

      Nå kan du kjøre programmet ditt og se på bildet du hadde valgt å bli gjengitt som en OpenGL tekstur på et fly.

      4. Bruke Media Effects Framework

      Komplekset kode skrev vi til nå bare var en forutsetning for å bruke Media Effects rammeverket. Det er nå på tide å begynne å bruke rammeverket selv. Legg følgende felt til din Renderer klasse
      privat EffectContext effectContext;. Privat Effect effekt;

      Initial effectContext feltet ved hjelp av EffectContext.createWithCurrentGlContext. Det er ansvarlig for å administrere informasjon om de visuelle effektene inni en OpenGL kontekst. For optimal ytelse, bør dette bli kalt bare én gang. Legg til følgende kode i begynnelsen av din onDrawFrame metode
      if (effectContext == null) {effectContext = EffectContext.createWithCurrentGlContext ();}.

      Opprette en effekt er svært enkel. Bruk effectContext å skape en EffectFactory og bruk EffectFactory å skape en effekt objekt. Når en effekt objekt er tilgjengelig, kan du ringe søke og bestå en referanse til den opprinnelige strukturen til det, i vårt tilfelle er det teksturer [0], sammen med en referanse til en blank tekstur objekt, i vårt tilfelle er det teksturer [1 ]. Etter gjelder metoden kalles, teksturer [1] vil inneholde resultatet av Effect

      For eksempel, for å skape og bruke gråtoner effekt, her er koden du må skrive.
      private void grayScaleEffect () {EffectFactory fabrikken = effectContext.getFactory (); effekt = factory.createEffect (EffectFactory.EFFECT_GRAYSCALE); effect.apply (teksturer [0], photoWidth, photoHeight, teksturer [1]);}

      Ring denne metoden i onDrawFrame og passere teksturer [1] til torget objektets uavgjort metode. Din onDrawFrame metoden bør ha følgende kode:
      Overridepublic void onDrawFrame (GL10 gl) {if (effectContext == null) {effectContext = EffectContext.createWithCurrentGlContext (); } If (effekt = null) {effect.release (); } GrayScaleEffect (); square.draw (teksturer [1]);}

      Utgivelsen metoden brukes til å frigjøre alle ressurser som eies av en effekt. Når du kjører programmet, bør du se følgende resultat:

      Du kan bruke den samme koden for å bruke andre effekter. For eksempel, her er koden for å bruke dokumentaren effekt:
      private void documentaryEffect () {EffectFactory fabrikken = effectContext.getFactory (); effekt = factory.createEffect (EffectFactory.EFFECT_DOCUMENTARY); effect.apply (teksturer [0], photoWidth, photoHeight, teksturer [1]);}

      Resultatet ser slik ut:

      Noen effekter ta parametere. For eksempel, har justeringen lysstyrke virkning en lysstyrke parameter som tar en flyteverdi. Du kan bruke setParameter å endre verdien av alle parameter. Følgende kode viser deg hvordan du bruker det:
      private void brightnessEffect () {EffectFactory fabrikken = effectContext.getFactory (); effekt = factory.createEffect (EffectFactory.EFFECT_BRIGHTNESS); effect.setParameter ("lysstyrke", 2f); effect.apply (teksturer [0], photoWidth, photoHeight, teksturer [1]);}

      Den effekten vil gjøre din app gjengi følgende resultat:

      Konklusjon

      I denne opplæringen, har du lært hvordan du bruker Media Effects Framework for å bruke ulike effekter på bildene dine. Mens du gjør det, også lærte du hvordan du kan tegne et fly ved hjelp av OpenGL ES 2.0 og anvende ulike teksturer til det.

      Rammen kan brukes på både bilder og videoer. I tilfelle av videoer, du bare nødt til å bruke effekten til de enkelte rammene av video i onDrawFrame metoden.

      Du har allerede sett tre effekter i denne opplæringen og rammene har mange flere for deg å eksperimentere med . For å vite mer om dem, henvis til Android Developer hjemmeside.