Differences

This shows you the differences between two versions of the page.

Link to this comparison view

egc:laboratoare:bonusrendertext [2019/11/25 16:42]
victor.asavei [Utilizare FreeType]
egc:laboratoare:bonusrendertext [2019/12/03 07:56] (current)
alexandru.gradinaru
Line 1: Line 1:
-===== Laborator ​bonus =====+===== Resurse ​bonus =====
  
 ==== Redare text în OpenGL ==== ==== Redare text în OpenGL ====
Line 18: Line 18:
 Cea de-a doua variantă (și cea care este folosită și pentru implementare în continuarea laboratorului) este ca pentru fiecare caracter/​simbol să se creeze câte o textură individuală ce va avea dimensiunea (lătime/​înălțime) caracterului/​simbolului. Această metodă permite o mai bună flexibilitate în manipularea fiecărui caracter/​simbol în parte pentru poziționarea/​scalarea acestuia. Cea de-a doua variantă (și cea care este folosită și pentru implementare în continuarea laboratorului) este ca pentru fiecare caracter/​simbol să se creeze câte o textură individuală ce va avea dimensiunea (lătime/​înălțime) caracterului/​simbolului. Această metodă permite o mai bună flexibilitate în manipularea fiecărui caracter/​simbol în parte pentru poziționarea/​scalarea acestuia.
  
-Pentru a obtine ​textura ​pentru fiecare caracter/​simbol necesar dintr-un font dat, a fost folosită biblioteca //​FreeType//​.+Pentru a obtine ​imaginea (bitmapul) ​pentru fiecare caracter/​simbol necesar dintr-un font dat, a fost folosită biblioteca //​FreeType//​.
  
 ==== Utilizare FreeType ==== ==== Utilizare FreeType ====
Line 46: Line 46:
   * Creare texturi pentru fiecare caracter/​simbol   * Creare texturi pentru fiecare caracter/​simbol
 <code cpp> <code cpp>
-// Then for the first 128 ASCII characters, ​+// for the first 128 ASCII characters, ​
 // pre-load/​compile their characters and store them // pre-load/​compile their characters and store them
 for (GLubyte c = 0; c < 128; c++)  ​ for (GLubyte c = 0; c < 128; c++)  ​
Line 78: Line 78:
 } }
 </​code>​ </​code>​
 +
 +Astfel pentru fiecare dintre primele 128 de caractere ASCII din font se crează câte o textură. Se folosește pentru textura creată doar primul canal de culoare (GL_RED) unde se va memora valoarea de culoare din bitmap-ul generat pentru fiecare caracter ca o imagine greyscale pe 8 biți.
 +
  
 ==== Shadere ==== ==== Shadere ====
  
-==== Redare ​text ====+Pentru redarea fiecărui caracter se folosesc următoarele shadere: 
 +  * Vertex shader 
 +<code glsl> 
 +layout(location ​0) in vec4 vertex; // <​x,​y,​u,​v>​ 
 +out vec2 TexCoords;​ 
 + 
 +uniform mat4 projection;​ 
 + 
 +void main() 
 +
 + gl_Position ​projection * vec4(vertex.xy,​ 0.0, 1.0); 
 + TexCoords ​vertex.zw;​ 
 +
 +</​code>​ 
 +Pe coordonatele .xy se transmit coordonatele x,y din cadrul ferestrei de afișare care reprezintă poziția unde va fi afișat caracterul. 
 + 
 +Coordonata z va fi zero deoarece afișarea se va face direct pe fața cubului corespunzător volumului vizual canonic în planul Z 0. 
 +  
 +Astfel acestea vor fi transformate in vertex shader doar cu matricea de proiecție. 
 + 
 +Se va folosi o proiecție ortografică ce va avea //near// = //far// = 0 și pentru a considera colțul stânga sus ca fiind 0,0 va avea //bottom// inversat cu //top// astfel: 
 +<code glsl> 
 +glm::​value_ptr(glm::​ortho(0.0f,​ static_cast<​GLfloat>​(width),​ static_cast<​GLfloat>​(height),​ 0.0f)) 
 +</​code>​ 
 +unde **width** și **height** sunt rezoluția ferestrei de afișare 
 + 
 +Pe coordonatele .zw vor veni coordonatele de textură care vor fi trimise mai departe în //​TexCoords//​ 
 + 
 +  * Fragment shader 
 +<code glsl> 
 +in vec2 TexCoords;​ 
 +out vec4 color; 
 + 
 +uniform sampler2D ​text
 +uniform vec3 textColor;​ 
 + 
 +void main() 
 +
 + vec4 sampled = vec4(1.0, 1.0, 1.0, texture(text,​ TexCoords).r);​ 
 + color = vec4(textColor,​ 1.0) * sampled; 
 +
 +</​code>​ 
 + 
 +Fragment shader-ul primește ca uniforme id-ul texturii unde a fost încărcat bitmap-ul monocolor al caracterului și culoarea cu care se dorește a fi afișat textul. 
 +Astfel, deoarece am folosit doar canalul roșu pentru textură (GL_RED) se face eșantionarea din textură doar de pe acesta (//​texture(text,​ TexCoords).r//​) și se stochează în culoarea finală pe canalul de alpha (componenta a 4-a). În acest fel, considerând quad-ul pe care se afisează ca fiind transparent (in bitmap acolo unde nu există pixeli pentru caracter, va fi intors 0 iar un alpha de 0 înseamnă perfect transparent) textul va fi afișat iar restul conținutului quad-ului pe care a fost mapată textură va fi ignorat permițând astfel combinarea naturală cu ce deja a fost afișat anterior în frame buffer.  
 +Ca ultim pas, se înmulțește culoarea obținută cu culoarea //​textColor//​ pentru a desena textul cu o culoare dorită. 
 + 
 +Pentru a putea fi folosit acest mecanism de transparență trebuie activat și folosit mecanismul de blending din OpenGL astfel: 
 +<code glsl> 
 +glEnable(GL_BLEND);​ 
 +glBlendFunc(GL_SRC_ALPHA,​ GL_ONE_MINUS_SRC_ALPHA);​ 
 +</​code>​ 
 + 
 +==== Redarea textului ==== 
 + 
 +Pentru redarea unei linii de text se va folosi functia 
 +<code glsl> 
 +void RenderText(std::​string text, GLfloat x, GLfloat y, GLfloat scale, glm::vec3 color) 
 +</​code>​ 
 +unde: 
 +  * x,y: coordonatele (x,y) din fereastra de afișare de unde va fi afișată linia de text ( 0,0 corespunde colțului stânga sus al ecranului) 
 +  * scale: factor de scalare pentru text (dimensiunea font-ului ales la încărcare va fi înmulțită cu acest factor) 
 +  * color: culoarea textului 
 + 
 +Întreaga funcție: 
 + 
 +<code glsl> 
 +void TextRenderer::​RenderText(std::​string text, GLfloat x, GLfloat y, GLfloat scale, glm::vec3 color) 
 +
 + // Activate corresponding render state  
 + //​this->​TextShader.Use();​ 
 + if (this->​TextShader) 
 +
 + glUseProgram(this->​TextShader->​program);​ 
 + CheckOpenGLError();​ 
 +
 + 
 + int loc_text_color = glGetUniformLocation(this->​TextShader->​program,​ "​textColor"​);​ 
 + glUniform3f(loc_text_color,​ color.r, color.g, color.b); 
 + //​this->​TextShader.SetVector3f("​textColor",​ color); 
 + glActiveTexture(GL_TEXTURE0);​ 
 + glBindVertexArray(this->​VAO);​ 
 + 
 + // Iterate through all characters 
 + std::​string::​const_iterator c; 
 + for (c = text.begin();​ c != text.end(); c++) 
 +
 + Character ch = Characters[*c];​ 
 + 
 + GLfloat xpos = x + ch.Bearing.x * scale; 
 + GLfloat ypos = y + (this->​Characters['​H'​].Bearing.y - ch.Bearing.y) * scale; 
 + 
 + GLfloat w = ch.Size.x * scale; 
 + GLfloat h = ch.Size.y * scale; 
 + // Update VBO for each character 
 + GLfloat vertices[6][4] ​
 + { xpos,     ypos + h,   0.0, 1.0 }, 
 + { xpos + w, ypos,       1.0, 0.0 }, 
 + { xpos,     ​ypos, ​      0.0, 0.0 }, 
 + 
 + { xpos,     ypos + h,   0.0, 1.0 }, 
 + { xpos + w, ypos + h,   1.0, 1.0 }, 
 + { xpos + w, ypos,       1.0, 0.0 } 
 + }; 
 + // Render glyph texture over quad 
 + glBindTexture(GL_TEXTURE_2D,​ ch.TextureID);​ 
 + // Update content of VBO memory 
 + glBindBuffer(GL_ARRAY_BUFFER,​ this->​VBO);​ 
 + glBufferSubData(GL_ARRAY_BUFFER,​ 0, sizeof(vertices),​ vertices); // Be sure to use glBufferSubData and not glBufferData 
 + 
 + glBindBuffer(GL_ARRAY_BUFFER,​ 0); 
 + // Render quad 
 + glPolygonMode(GL_FRONT_AND_BACK,​ GL_FILL); 
 + glEnable(GL_BLEND);​ 
 + glBlendFunc(GL_SRC_ALPHA,​ GL_ONE_MINUS_SRC_ALPHA);​ 
 + glDrawArrays(GL_TRIANGLES,​ 0, 6); 
 + glDisable(GL_BLEND);​ 
 + // Now advance cursors for next glyph 
 + x +(ch.Advance >> 6) * scale; // Bitshift by 6 to get value in pixels (1/64th times 2^6 64) 
 +
 + glBindVertexArray(0);​ 
 + glBindTexture(GL_TEXTURE_2D,​ 0); 
 +
 +</​code>​ 
 +Astfel se procesează fiecare caracter din care este alcătuit quad-ul după cum urmează: 
 +  * Pentru fiecare caracter se avansează pe ecran pe linia orizontală (variabila //x//) la poziția de început de unde urmează a fi desenat (//xpos, ypos//) 
 +  * Se crează quad-ul de dimensiunea lățimea și înălțimea texturii asociate caracterului 
 +  * Quad-ul va fi desenat folosind două triunghiuri:​ 6 vertecși (câte 3 pentru fiecare triunghi) fiecare cu 4 valori: 
 +          * x,y: coodonatele vârfului (după cum s-a explicat mai sus z va fi zero deoarece se desenează folosind o proiecție ortografică în planul Z 0 al volumului vizual canonic) 
 +          * z,w: coordonatele de textură asociate vârfului 
 +  * Se desenează quad-ul format din cele două triunghiuri cu textura corespunzătoare caracterului (//​glBindTexture(GL_TEXTURE_2D,​ ch.TextureID)//​) și cu mecanismul de blending activat pentru a nu desena decât pixelii caracterului și a ignora restul quad-ului care este transparent
  
 +==== Utilizare ====
  
 +  - Descărcați [[https://​github.com/​UPB-Graphics/​Framework-EGC/​archive/​withrendertext.zip|framework-ul de laborator]] ce are implementat redarea textului
 +  - Rulați exemplul de redare a textului: clasa ''​Laborator_BonusTextRenderer'' ​
 +  - Dacă doriți să vedeți în detaliu implementarea redării textului examinați:
 +    * Clasa ''​TextRenderer''​ din /​TextRenderer
 +    * Shaderele ''​VertexShaderText.glsl''​ și ''​FragmentShaderText.glsl''​ din /​TextRenderer/​Shaders
  
egc/laboratoare/bonusrendertext.1574692946.txt.gz · Last modified: 2019/11/25 16:42 by victor.asavei
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0