{"id":1155,"date":"2017-07-23T17:29:16","date_gmt":"2017-07-23T17:29:16","guid":{"rendered":"http:\/\/demensdeum.com\/blog\/?p=1155"},"modified":"2024-12-16T22:32:46","modified_gmt":"2024-12-16T19:32:46","slug":"opengles-miku","status":"publish","type":"post","link":"https:\/\/demensdeum.com\/blog\/pt\/2017\/07\/23\/opengles-miku\/","title":{"rendered":"S\u00f3 existe Miku"},"content":{"rendered":"<p>O resultado de trabalhar na biblioteca FSGL com OpenGL ES e c\u00f3digo:<\/p>\n<p><iframe loading=\"lazy\" src=\"https:\/\/www.youtube.com\/embed\/9L11ezDGRB8\" width=\"560\" height=\"315\" frameborder=\"0\" allowfullscreen=\"allowfullscreen\"><\/iframe><\/p>\n<p>A seguir descreverei como tudo foi programado, v\u00e1rios problemas <em>interessantes<\/em> foram resolvidos.<\/p>\n<p>Primeiro, inicializaremos o contexto OpenGL ES, conforme escrevi no post anterior. Al\u00e9m disso, consideraremos apenas a renderiza\u00e7\u00e3o e uma breve descri\u00e7\u00e3o do c\u00f3digo.<\/p>\n<h3>A Matrix est\u00e1 observando voc\u00ea<\/h3>\n<p>Esta figura de Miku no v\u00eddeo consiste em tri\u00e2ngulos. Para desenhar um tri\u00e2ngulo no OpenGL, voc\u00ea precisa especificar tr\u00eas pontos com coordenadas x, y, z. em coordenadas 2D do contexto OpenGL.<br \/>Como precisamos desenhar uma figura contendo coordenadas 3D, precisamos usar uma <strong>matriz de proje\u00e7\u00e3o<\/strong>. Tamb\u00e9m precisamos girar, ampliar ou o que quisermos fazer com o modelo. Para tanto, \u00e9 utilizada a <strong>matriz modelo<\/strong>. N\u00e3o existe o conceito de c\u00e2mera no OpenGL; na verdade, os objetos giram em torno de uma c\u00e2mera est\u00e1tica; Para isso, \u00e9 utilizada uma <strong>matriz de visualiza\u00e7\u00e3o<\/strong>.<\/p>\n<p>Para simplificar a implementa\u00e7\u00e3o do OpenGL ES &#8211; n\u00e3o cont\u00e9m dados de matriz. Voc\u00ea pode usar bibliotecas que adicionam funcionalidades ausentes, por exemplo, <a href=\"http:\/\/glm.g-truc.net\" target=\"_blank\" rel=\"noopener\">GLM<\/a>.<\/p>\n<h3><strong>Sombreadores<\/strong><\/h3>\n<p>Para permitir que o desenvolvedor desenhe qualquer coisa, e de qualquer forma, o OpenGL ES deve implementar shaders de v\u00e9rtices e fragmentos. O vertex shader deve receber coordenadas de renderiza\u00e7\u00e3o como entrada, realizar transforma\u00e7\u00f5es usando matrizes e passar as coordenadas para gl_Position. Fragmento ou pixel shader &#8211; j\u00e1 desenha cor\/textura, aplica sobreposi\u00e7\u00e3o, etc.<\/p>\n<p>Eu escrevi shaders em GLSL. Na minha implementa\u00e7\u00e3o atual, os shaders s\u00e3o integrados diretamente no c\u00f3digo principal do aplicativo como strings <strong>C<\/strong>.<\/p>\n<h3>Buffers<\/h3>\n<p>O buffer de v\u00e9rtices cont\u00e9m as coordenadas dos v\u00e9rtices (v\u00e9rtices); este buffer tamb\u00e9m cont\u00e9m coordenadas para texturiza\u00e7\u00e3o e outros dados necess\u00e1rios para shaders. Depois de gerar o buffer de v\u00e9rtice, voc\u00ea precisa vincular o ponteiro aos dados do sombreador de v\u00e9rtice. Isso \u00e9 feito com o comando glVertexAttribPointer, onde voc\u00ea precisa especificar o n\u00famero de elementos, um ponteiro para o in\u00edcio dos dados e o tamanho do passo que ser\u00e1 usado para percorrer o buffer. Na minha implementa\u00e7\u00e3o, \u00e9 feita a liga\u00e7\u00e3o de coordenadas de v\u00e9rtice e coordenadas de textura para o pixel shader. Por\u00e9m, vale ressaltar que a transfer\u00eancia dos dados (coordenadas de textura) para o fragment shader \u00e9 realizada atrav\u00e9s do vertex shader. Para conseguir isso, as coordenadas s\u00e3o declaradas usando <strong>variando<\/strong>.<\/p>\n<p>Para que o OpenGL saiba em que ordem desenhar pontos para tri\u00e2ngulos &#8211; voc\u00ea precisar\u00e1 de um buffer de \u00edndice (\u00edndice). O buffer de \u00edndice cont\u00e9m o n\u00famero do v\u00e9rtice na matriz. Usando tr\u00eas desses \u00edndices, um tri\u00e2ngulo \u00e9 obtido.<\/p>\n<h3>Texturas<\/h3>\n<p>Primeiro voc\u00ea precisa carregar\/gerar uma textura para OpenGL. Para isso utilizei SDL_LoadBMP, a textura \u00e9 carregada a partir de um arquivo bmp. No entanto, \u00e9 importante notar que apenas BMPs de 24 bits s\u00e3o adequados e as cores neles s\u00e3o armazenadas n\u00e3o na ordem RGB usual, mas em BGR. Ou seja, ap\u00f3s o carregamento, \u00e9 necess\u00e1rio substituir o canal vermelho por um azul.<br \/>As coordenadas de textura s\u00e3o especificadas no formato <a href=\"http:\/\/www.opengl-tutorial.org\/beginners-tutorials\/tutorial-5-a-textured-cube\/\" target=\"_blank\" rel=\"noopener\"> UV< \/a>, ou seja, voc\u00ea s\u00f3 precisa transferir duas coordenadas. A sa\u00edda da textura \u00e9 feita no fragment shader. Para fazer isso, voc\u00ea precisa vincular a textura em um fragment shader.<\/p>\n<h3>Nada extra<\/h3>\n<p>Como, de acordo com nossas instru\u00e7\u00f5es, o OpenGL desenha de 3D a 2D &#8211; em seguida, implemente a profundidade e selecione tri\u00e2ngulos invis\u00edveis &#8211; voc\u00ea precisa usar sele\u00e7\u00e3o e um buffer de profundidade (Z-Buffer). Na minha implementa\u00e7\u00e3o, consegui evitar a gera\u00e7\u00e3o manual do buffer de profundidade usando dois comandos: glEnable(GL_DEPTH_TEST); e sele\u00e7\u00f5es glEnable(GL_CULL_FACE);<br \/>Certifique-se tamb\u00e9m de verificar se o plano pr\u00f3ximo da matriz de proje\u00e7\u00e3o \u00e9 maior que zero, porque verificar a profundidade com um plano pr\u00f3ximo nulo n\u00e3o funcionar\u00e1.<\/p>\n<h3><strong>Renderiza\u00e7\u00e3o<\/strong><\/h3>\n<p>Para preencher o buffer de v\u00e9rtice, buffer de \u00edndice com algo consciente, por exemplo o modelo Miku, voc\u00ea precisa carregar este modelo. Para isso usei a biblioteca <a href=\"https:\/\/github.com\/assimp\/assimp\" target=\"_blank\" rel=\"noopener\">assimp<\/a>. Miku foi colocado em um arquivo no formato Wavefront OBJ, carregado usando assimp, e a convers\u00e3o de dados de assimp para v\u00e9rtice e buffers de \u00edndice foi implementada.<\/p>\n<p>A renderiza\u00e7\u00e3o ocorre em v\u00e1rios est\u00e1gios:<\/p>\n<ol>\n<li>Gire Miku usando a rota\u00e7\u00e3o da matriz do modelo<\/li>\n<li>Limpando a tela e o buffer de profundidade<\/li>\n<li>Desenhar tri\u00e2ngulos usando o comando glDrawElements.<\/li>\n<\/ol>\n<p>Pr\u00f3xima etapa &#8211; Implementa\u00e7\u00e3o de renderiza\u00e7\u00e3o em WebGL usando Emscripten.<\/p>\n<p>C\u00f3digo fonte:<br \/><a href=\"https:\/\/github.com\/demensdeum\/OpenGLES3-Experiments\/tree\/master\/8-sdl-gles-obj-textured-assimp-miku\" target=\"_blank\" rel=\"noopener\">https:\/\/github.com\/demensdeum\/OpenGLES3-Experiments\/tree\/master\/8-sdl-gles-obj-textured-assimp-miku<br \/>\n<\/a>Modelo:<br \/><a href=\"https:\/\/sketchfab.com\/models\/7310aaeb8370428e966bdcff414273e7\" target=\"_blank\" rel=\"noopener\">https:\/\/sketchfab.com\/models\/7310aaeb8370428e966bdcff414273e7<\/a><\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>O resultado de trabalhar na biblioteca FSGL com OpenGL ES e c\u00f3digo: A seguir descreverei como tudo foi programado, v\u00e1rios problemas interessantes foram resolvidos. Primeiro, inicializaremos o contexto OpenGL ES, conforme escrevi no post anterior. Al\u00e9m disso, consideraremos apenas a renderiza\u00e7\u00e3o e uma breve descri\u00e7\u00e3o do c\u00f3digo. A Matrix est\u00e1 observando voc\u00ea Esta figura de<a class=\"more-link\" href=\"https:\/\/demensdeum.com\/blog\/pt\/2017\/07\/23\/opengles-miku\/\">Continue reading <span class=\"screen-reader-text\">&#8220;S\u00f3 existe Miku&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[61,52],"tags":[76],"class_list":["post-1155","post","type-post","status-publish","format-standard","hentry","category-techie","category-tutorials","tag-opengl","entry"],"translation":{"provider":"WPGlobus","version":"3.0.2","language":"pt","enabled_languages":["en","ru","zh","de","fr","ja","pt"],"languages":{"en":{"title":true,"content":true,"excerpt":false},"ru":{"title":true,"content":true,"excerpt":false},"zh":{"title":true,"content":true,"excerpt":false},"de":{"title":true,"content":true,"excerpt":false},"fr":{"title":true,"content":true,"excerpt":false},"ja":{"title":true,"content":true,"excerpt":false},"pt":{"title":true,"content":true,"excerpt":false}}},"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/demensdeum.com\/blog\/pt\/wp-json\/wp\/v2\/posts\/1155","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/demensdeum.com\/blog\/pt\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/demensdeum.com\/blog\/pt\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/demensdeum.com\/blog\/pt\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/demensdeum.com\/blog\/pt\/wp-json\/wp\/v2\/comments?post=1155"}],"version-history":[{"count":26,"href":"https:\/\/demensdeum.com\/blog\/pt\/wp-json\/wp\/v2\/posts\/1155\/revisions"}],"predecessor-version":[{"id":3996,"href":"https:\/\/demensdeum.com\/blog\/pt\/wp-json\/wp\/v2\/posts\/1155\/revisions\/3996"}],"wp:attachment":[{"href":"https:\/\/demensdeum.com\/blog\/pt\/wp-json\/wp\/v2\/media?parent=1155"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/demensdeum.com\/blog\/pt\/wp-json\/wp\/v2\/categories?post=1155"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/demensdeum.com\/blog\/pt\/wp-json\/wp\/v2\/tags?post=1155"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}