Android OpenGL Práce s texturami
Textura Obrázek, který jsme schopní nanášet na 3D objekty S použitím shaderů mnohem víc než to Může obsahovat jiné vlastnosti povrchu, než jen barvu (reliéf, lesklost, ) Může obsahovat libovolná data (tabulku hodnot funkce, atp.) Může obsahovat informace o vzdálenostech ve scéně (pro výpočet stínů)
Aplikace textury Abychom mohli texturu na povrch nanášet, potřebujeme znát její souřadnice Typicky uložené ve vrcholech Někdy je možné vypočíst souřadnice textury z pozice vrcholů v prostoru (např. mapování do plochy)
Aplikace textury Fragment shader provádí čtení textury Libovolný počet vzorků Z libovolných souřadnic Používají se tzv. samplery Udává v které texturovací jednotce je připojená textura, kterou má shader číst Většinou stačí přiřadit jednotky od nuly
Uložení textury v aplikaci Pokud se jedná o malou texturu, lze ji uložit jako statické pole přímo v kódu byte[] texture = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff} Většinou nepraktické
Uložení textury v aplikaci Je možné použít resource Identifikace podle cesty R.drawable.fitlogo
Načtení textury z resource Pomocí InputStream a BitmapFactory Bitmap bitmap; // načítaný obrázek InputStream is = mcontext.getresources getresources(). openrawresource(r.drawable.fitlogo); // identifikace resource try { bitmap = BitmapFactory.decodeStream decodestream(is); } finally { try { is.close close(); } catch (IOException e) { // chyba } }
Vytvoření textury v OpenGL int n_texture; int[] p_temp = new int[1]; glgentextures(1, p_temp, 0); n_texture = p_temp[0]; // vygeneruje texturu glbindtexture(gl_texture_2d, n_texture); gltexparameterf(gl_texture_2d, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); gltexparameterf(gl_texture_2d, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // nastaví texturu (lineární filtr, mip-mapping) GLUtils.texImage2D teximage2d(gl_texture_2d, 0, bitmap, 0); // glteximage2d glgeneratemipmap(gl_texture_2d); // specifikuje obrázek textury, vygeneruje mip-mapy bitmap.recycle recycle(); // úklid
Použití textury ve fragment shaderu Je třeba mít sampler Je třeba znát souřadnice precision highp float; // specifikace přesnosti varying vec2 v_texcoord; // souřadnice textury (z vertex shaderu) uniform sampler2d n_sampler; // nastaveni texturovaci jednotky void main() { gl_fragcolor = texture2d(n_sampler, v_texcoord); // přečte barvu z textury, pomocí sampleru z daných souřadnic }
Nastavení sampleru Zjistit adresu parametru sampleru int n_sampler_address = glgetuniformlocation(n_program_object, "n_sampler"); Nastavit jeho hodnotu gluseprogram(n_program_object); // aby šly nastavovat parametry gluniform1i(n_sampler_address, 0); Dát texturu do stejné texturovací jednotky glactivetexture(gl_texture0); // aktivuj texturovací jednotku 0 glbindtexture(gl_texture_2d, n_texture); // aktivuj texturu
Souřadnice textury Lze vygenerovat ve vertex shaderu precision highp float; // specifikace přesnosti attribute vec3 v_pos; // 3D pozice - vstup z dat vrcholu varying vec2 v_texcoord; // výstup 2D souřadnice textury uniform mat4 t_modelview_projection; // transformační matice void main() { gl_position = t_modelview_projection * vec4(v_pos, 1.0); // musíme zapsat pozici v_texcoord = vec2(v_pos.x, v_pos.z) * 0.5 + 0.5; // vymyslíme souřadnice textury pro fragment shader }
Souřadnice textury Generování souřadnic ve vertex shaderu však není vždy to pravéřešení (výstup z předchozích shaderů, použití souřadnic x a z jako souřadnic textury)
Souřadnice textury Pro správné mapování je třeba dodat souřadnice textury spolu s vrcholy final float[] p_box_vertices = { 1, 0, -1, 1, -1, 0, 0, 1, 1, -1, 1, 1, -1, -1, -1, 0, 1, 1, -1, -1, souřadnice v prostoru (offset v poli 2) souřadnice textury (offset v poli 0) /* a data pro další stěny... */};
Souřadnice textury Aby se souřadnice textury dostaly k shaderu, je třeba přidat druhý vertex atribut glvertexattribpointer(0, 3, // nultý atribut je 3D (pozice) GL_FLOAT, false, 5 * 4, // jeden vertex zabírá 5 * 4 byte // (5 = 3D pozice + 2D textura) p_box_vertices_buff.position position(2)); // k datům pozic je třeba // přeskočít dvě čísla glvertexattribpointer(1, 2, // první atribut je 2D (textura) GL_FLOAT, false, 5 * 4, p_box_vertices_buff.position position(0)); // data textury na začátku glenablevertexattribarray(0); glenablevertexattribarray(1); // je třeba povolit i první atribut
Souřadnice textury Je třeba upravit vertex shader precision highp float; // specifikace přesnosti attribute vec3 v_pos; attribute vec2 v_tex; // nový atribut 2D souřadnice textury varying vec2 v_texcoord; // výstup - souřadnice textury uniform mat4 t_modelview_projection; // transformační matice void main() { gl_position = t_modelview_projection * vec4(v_pos, 1.0); //.. } v_texcoord = v_tex; // zkopírujeme souřadnici textury pro fragment shader
Souřadnice textury Je třeba nastavit spojení prvního atributu s proměnnou v_tex v shaderu glbindattriblocation(n_program_object, 0, "v_pos"); // atribut pozice glbindattriblocation(n_program_object, 1, "v_tex"); // atribut souřadnice textury
Výsledek
Shrnutí Pro zobrazení textury Je třeba mít souřadnice Generování ve vertex shaderu Uložené v datech vrcholů, spolu se správným nastavením vertex atributů Je třeba mít sampler Nastavit číslo sampleru Dát texturu do stejné texturovací jednotky, nebo použít jednotku 0 (default)
Konec