Differences

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

Link to this comparison view

egc:laboratoare:bonusrendertext [2019/11/25 16:50]
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 84: Line 84:
 ==== 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.1574693459.txt.gz · Last modified: 2019/11/25 16:50 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