• 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祝威+悄悄在此留下版了个权的信息说:
  • 相关阅读:
    第一阶段冲刺09
    英文单词统计
    第一阶段冲刺08
    暑假生活第二周
    暑假生活第一周
    大道至简读书笔记03
    个人总结15
    大道至简读书笔记02
    计算最长英语单词链
    个人总结14
  • 原文地址:https://www.cnblogs.com/bitzhuwei/p/display-text-using-glsl-and-vbo.html
Copyright © 2020-2023  润新知