zoukankan      html  css  js  c++  java
  • C#+OpenGL+FreeType显示3D文字(2)

    C#+OpenGL+FreeType显示3D文字(2) - 用GLSL+VBO绘制文字

    +BIT祝威+悄悄在此留下版了个权的信息说:

    上一篇得到了字形贴图及其位置字典(可导出为XML)。本篇就利用此贴图和位置字典,把文字绘制到OpenGL窗口。

    基本流程

    +BIT祝威+悄悄在此留下版了个权的信息说:

    有了贴图,绘制文字和绘制普通纹理的过程是一样的。我们需要用glTexImage2D设定纹理,然后用GLSL+VBO设置一个长方形,把纹理的某个字形所占据的位置贴到长方形上,就可以绘制一个字符。连续设置多个长方形,就可以显示字符串了。

    当然,用legacy opengl里的glVertex和glTexCoord来设置长方形和贴图也可以,不过本文推荐用modern opengl的GLSL+VBO的方式来实现。

    您可以在此下载查看上图所示的demo。为节省空间,此demo只能显示ASCII范围内的字符。实际上它具有显示所有Unicode字符的能力。

    编辑GLSL

    我们只需vertex shader和fragment shader。

    Vertex shader只是进行最基本的变换操作,并负责传递纹理坐标。

     1 #version 120
     2 
     3 attribute vec3 in_Position;
     4 attribute vec2 in_TexCoord;
     5 varying vec2 texcoord;
     6 uniform mat4 projectionMatrix;
     7 uniform mat4 viewMatrix;
     8 uniform mat4 modelMatrix;
     9 
    10 void main(void) {
    11   gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(in_Position, 1);
    12   texcoord = in_TexCoord;
    13 }

    Fragment shader根据纹理坐标所在位置的纹理颜色决定此位置是否显示(透明与否)。这就绘制出了一个字形。 

    1 #version 120
    2 
    3 varying vec2 texcoord;
    4 uniform sampler2D tex;
    5 uniform vec4 color;
    6 
    7 void main(void) {
    8   gl_FragColor = vec4(1, 1, 1, texture2D(tex, texcoord).r) * color;
    9 }

    设定VAO

    每个字符的宽度是不同的,所以每个长方形都要据此调整宽度。下面是根据字符串生成VAO/VBO的片段。

     1         private void InitVAO(string value)
     2         {
     3             if (value == null) { value = string.Empty; }
     4 
     5             this.mode = PrimitiveModes.Quads;
     6             this.vertexCount = 4 * value.Length;
     7 
     8             //  Create a vertex buffer for the vertex data.
     9             UnmanagedArray<vec3> in_Position = new UnmanagedArray<vec3>(this.vertexCount);
    10             UnmanagedArray<vec2> in_TexCoord = new UnmanagedArray<vec2>(this.vertexCount);
    11             Bitmap bigBitmap = this.ttfTexture.BigBitmap;
    12             vec3[] tmpPositions = new vec3[this.vertexCount];
    13             float totalLength = 0;
    14             for (int i = 0; i < value.Length; i++)
    15             {
    16                 char c = value[i];
    17                 CharacterInfo cInfo;
    18                 if (this.ttfTexture.CharInfoDict.TryGetValue(c, out cInfo))
    19                 {
    20                     float glyphWidth = (float)cInfo.width / (float)this.ttfTexture.FontHeight;
    21                     if (i == 0)
    22                     {
    23                         tmpPositions[i * 4 + 0] = new vec3(0, 0, 0);
    24                         tmpPositions[i * 4 + 1] = new vec3(glyphWidth, 0, 0);
    25                         tmpPositions[i * 4 + 2] = new vec3(glyphWidth, 1, 0);
    26                         tmpPositions[i * 4 + 3] = new vec3(0, 1, 0);
    27                     }
    28                     else
    29                     {
    30                         tmpPositions[i * 4 + 0] = tmpPositions[i * 4 + 0 - 4 + 1];
    31                         tmpPositions[i * 4 + 1] = tmpPositions[i * 4 + 0] + new vec3(glyphWidth, 0, 0);
    32                         tmpPositions[i * 4 + 3] = tmpPositions[i * 4 + 3 - 4 - 1];
    33                         tmpPositions[i * 4 + 2] = tmpPositions[i * 4 + 3] + new vec3(glyphWidth, 0, 0);
    34                     }
    35                     totalLength += glyphWidth;
    36                 }
    37 
    38             }
    39             for (int i = 0; i < value.Length; i++)
    40             {
    41                 char c = value[i];
    42                 CharacterInfo cInfo;
    43                 float x1 = 0;
    44                 float x2 = 1;
    45                 float y1 = 0;
    46                 float y2 = 1;
    47                 if (this.ttfTexture.CharInfoDict.TryGetValue(c, out cInfo))
    48                 {
    49                     x1 = (float)cInfo.xoffset / (float)bigBitmap.Width;
    50                     x2 = (float)(cInfo.xoffset + cInfo.width) / (float)bigBitmap.Width;
    51                     y1 = (float)cInfo.yoffset / (float)bigBitmap.Height;
    52                     y2 = (float)(cInfo.yoffset + this.ttfTexture.FontHeight) / (float)bigBitmap.Height;
    53                 }
    54 
    55                 in_Position[i * 4 + 0] = tmpPositions[i * 4 + 0] - new vec3(totalLength / 2, 0, 0);
    56                 in_Position[i * 4 + 1] = tmpPositions[i * 4 + 1] - new vec3(totalLength / 2, 0, 0);
    57                 in_Position[i * 4 + 2] = tmpPositions[i * 4 + 2] - new vec3(totalLength / 2, 0, 0);
    58                 in_Position[i * 4 + 3] = tmpPositions[i * 4 + 3] - new vec3(totalLength / 2, 0, 0);
    59 
    60                 in_TexCoord[i * 4 + 0] = new vec2(x1, y2);
    61                 in_TexCoord[i * 4 + 1] = new vec2(x2, y2);
    62                 in_TexCoord[i * 4 + 2] = new vec2(x2, y1);
    63                 in_TexCoord[i * 4 + 3] = new vec2(x1, y1);
    64             }
    65 
    66             GL.GenVertexArrays(1, vao);
    67             GL.BindVertexArray(vao[0]);
    68 
    69             GL.GenBuffers(2, vbo);
    70 
    71             uint in_PositionLocation = shaderProgram.GetAttributeLocation(strin_Position);
    72             GL.BindBuffer(BufferTarget.ArrayBuffer, vbo[0]);
    73             GL.BufferData(BufferTarget.ArrayBuffer, in_Position, BufferUsage.StaticDraw);
    74             GL.VertexAttribPointer(in_PositionLocation, 3, GL.GL_FLOAT, false, 0, IntPtr.Zero);
    75             GL.EnableVertexAttribArray(in_PositionLocation);
    76 
    77             uint in_TexCoordLocation = shaderProgram.GetAttributeLocation(strin_TexCoord);
    78             GL.BindBuffer(BufferTarget.ArrayBuffer, vbo[1]);
    79             GL.BufferData(BufferTarget.ArrayBuffer, in_TexCoord, BufferUsage.StaticDraw);
    80             GL.VertexAttribPointer(in_TexCoordLocation, 2, GL.GL_FLOAT, false, 0, IntPtr.Zero);
    81             GL.EnableVertexAttribArray(in_TexCoordLocation);
    82 
    83             GL.BindVertexArray(0);
    84 
    85             in_Position.Dispose();
    86             in_TexCoord.Dispose();
    87         }
    根据字符串生成VAO/VBO

    其它 

    在上一篇,我们通过TTF文件得到了贴图文件及其位置信息(XML文件)。此时其实不再需要借助freetype就可以直接使用这些贴图了。

    另外,本文所给的demo已经包含了perspective和ortho两种透视的camera功能,固定在窗口左下角显示坐标系的功能,感兴趣的话通过反编译即可得到。

    总结

    现在能够绘制文字了,但是换行之类的高级功能还没有实现。这已经不熟悉opengl的研究范围,而是更高层的功能了,所以暂时不再深入考虑。

    +BIT祝威+悄悄在此留下版了个权的信息说:
  • 相关阅读:
    PAT (Advanced Level) Practice 1054 The Dominant Color (20 分)
    PAT (Advanced Level) Practice 1005 Spell It Right (20 分) (switch)
    PAT (Advanced Level) Practice 1006 Sign In and Sign Out (25 分) (排序)
    hdu 5114 Collision
    hdu4365 Palindrome graph
    单链表查找最大值、两个递增的链表合并并且去重
    蓝桥杯-最短路 (SPFA算法学习)
    蓝桥杯-最大最小公倍数
    Codeforces-470 div2 C题
    蓝桥杯-地宫取宝
  • 原文地址:https://www.cnblogs.com/bitzhuwei/p/display-text-using-glsl-and-vbo.html
Copyright © 2011-2022 走看看