opengl繪制球體,C#+OpenGL+FreeType顯示3D文字(3) - 用PointSprite繪制文字

 2023-11-22 阅读 23 评论 0

摘要:C#+OpenGL+FreeType顯示3D文字(3) - 用PointSprite繪制文字 上一篇實現了把文字繪制到OpenGL窗口,但實質上只是把含有文字的貼圖貼到矩形模型上。本篇我們介紹用PointSprite繪制文字,這可以只用1個點繪制文字,并確保文字始終面相窗口。用PointSp

C#+OpenGL+FreeType顯示3D文字(3) - 用PointSprite繪制文字

上一篇實現了把文字繪制到OpenGL窗口,但實質上只是把含有文字的貼圖貼到矩形模型上。本篇我們介紹用PointSprite繪制文字,這可以只用1個點繪制文字,并確保文字始終面相窗口。用PointSprite繪制的文字,其大小范圍有限,本篇提供的Demo中,Max Row Width最大只有256。現在能夠繪制少量的文字,為其指定的位置的過程與為一個點指定位置的過程是相同的,所以此方式的應用范圍還是比較廣的。

?

基本流程

與前文相同的是仍然用GLSL+VBO+貼圖來繪制。PointSprite只是Enable了一些OpenGL開關,然后把貼圖貼到一個Point圖元上。

opengl繪制球體。您可以在此下載查看上圖所示的demo。為節省空間,此demo只能顯示ASCII范圍內的字符。實際上它具有顯示所有Unicode字符的能力。

?

編輯GLSL

我們只需vertex shader和fragment shader。

Vertex shader只是進行最基本的變換操作,并負責傳遞紋理大小。

 1 #version 150 core
 2 
 3 in vec3 in_Position;
 4 
 5 uniform mat4 MVP;
 6 uniform float pointSize;
 7 
 8 void main(void) {
 9     gl_Position = MVP * vec4(in_Position, 1.0);
10     gl_PointSize = pointSize;
11 }

3d文字怎么寫。?

Fragment shader根據紋理坐標所在位置的紋理顏色決定此位置是否顯示(透明與否)。這就繪制出了一個字形。還可以順便用一個uniform vec3 textColor指定文字顏色。

 1 #version 150 core
 2 
 3 out vec4 out_Color;
 4 
 5 uniform sampler2D tex;
 6 uniform vec3 textColor;
 7 
 8 void main(void) {
 9     float transparency = texture2D(tex, gl_PointCoord).r;
10     if (transparency == 0.0f)
11     {
12         discard;
13     }
14     else
15     {
16         out_Color = vec4(1, 1, 1, transparency) * vec4(textColor, 1.0f);
17     }
18 }

?

設定VAO

模型只需一個Point。

 1         private void InitVAO()
 2         {
 3             GL.GenVertexArrays(1, vao);
 4             GL.BindVertexArray(vao[0]);
 5 
 6             //  Create a vertex buffer for the vertex data.
 7             {
 8                 UnmanagedArray<vec3> in_Position = new UnmanagedArray<vec3>(1);
 9                 in_Position[0] = this.position;
10 
11                 uint[] ids = new uint[1];
12                 GL.GenBuffers(1, ids);
13                 GL.BindBuffer(BufferTarget.ArrayBuffer, ids[0]);
14                 GL.BufferData(BufferTarget.ArrayBuffer, in_Position, BufferUsage.StaticDraw);
15                 GL.VertexAttribPointer(attributeIndexPosition, 3, GL.GL_FLOAT, false, 0, IntPtr.Zero);
16                 GL.EnableVertexAttribArray(attributeIndexPosition);
17             }
18 
19             //  Unbind the vertex array, we've finished specifying data for it.
20             GL.BindVertexArray(0);
21         }

3D??

程序生成文字貼圖

要想顯示任意的字符串,必須借助前文的貼圖來一個字符一個字符地拼接出需要的字符串貼圖并用之生成Texture。

這是從上面的圖片中計算出的"bithuwei.cnblogs.com"的貼圖。

opengl畫點、

由于PointSprite支持的貼圖大小有限(最大256),所以計算字符串貼圖的程序有點繁瑣。

  1         /// <summary>
  2         /// 為指定的字符串生成貼圖。
  3         /// </summary>
  4         /// <param name="fontResource"></param>
  5         /// <param name="content"></param>
  6         /// <param name="fontSize"></param>
  7         /// <param name="maxRowWidth"></param>
  8         /// <returns></returns>
  9         public static System.Drawing.Bitmap GenerateBitmapForString(this FontResource fontResource,
 10             string content, int fontSize, int maxRowWidth)
 11         {
 12             // step 1: get totalLength
 13             int totalLength = 0;
 14             {
 15                 int glyphsLength = 0;
 16                 for (int i = 0; i < content.Length; i++)
 17                 {
 18                     char c = content[i];
 19                     CharacterInfo cInfo;
 20                     if (fontResource.CharInfoDict.TryGetValue(c, out cInfo))
 21                     {
 22                         int glyphWidth = cInfo.width;
 23                         glyphsLength += glyphWidth;
 24                     }
 25                     //else
 26                     //{ throw new Exception(string.Format("Not support for display the char [{0}]", c)); }
 27                 }
 28 
 29                 //glyphsLength = (glyphsLength * this.fontSize / FontResource.Instance.FontHeight);
 30                 int interval = fontResource.FontHeight / 10; if (interval < 1) { interval = 1; }
 31                 totalLength = glyphsLength + interval * (content.Length - 1);
 32             }
 33 
 34             // step 2: setup contentBitmap
 35             System.Drawing.Bitmap contentBitmap = null;
 36             {
 37                 int interval = fontResource.FontHeight / 10; if (interval < 1) { interval = 1; }
 38                 //int totalLength = glyphsLength + interval * (content.Length - 1);
 39                 int currentTextureWidth = 0;
 40                 int currentWidthPos = 0;
 41                 int currentHeightPos = 0;
 42                 if (totalLength * fontSize > maxRowWidth * fontResource.FontHeight)// 超過1行能顯示的內容
 43                 {
 44                     currentTextureWidth = maxRowWidth * fontResource.FontHeight / fontSize;
 45 
 46                     int lineCount = (totalLength - 1) / currentTextureWidth + 1;
 47                     // 確保整篇文字的高度在貼圖中間。
 48                     currentHeightPos = (currentTextureWidth - fontResource.FontHeight * lineCount) / 2;
 49                     //- FontResource.Instance.FontHeight / 2;
 50                 }
 51                 else//只在一行內即可顯示所有字符
 52                 {
 53                     if (totalLength >= fontResource.FontHeight)
 54                     {
 55                         currentTextureWidth = totalLength;
 56 
 57                         // 確保整篇文字的高度在貼圖中間。
 58                         currentHeightPos = (currentTextureWidth - fontResource.FontHeight) / 2;
 59                         //- FontResource.Instance.FontHeight / 2;
 60                     }
 61                     else
 62                     {
 63                         currentTextureWidth = fontResource.FontHeight;
 64 
 65                         currentWidthPos = (currentTextureWidth - totalLength) / 2;
 66                         //glyphsLength = fontResource.FontHeight;
 67                     }
 68                 }
 69 
 70                 //this.textureWidth = textureWidth * this.fontSize / FontResource.Instance.FontHeight;
 71                 //currentWidthPosition = currentWidthPosition * this.fontSize / FontResource.Instance.FontHeight;
 72                 //currentHeightPosition = currentHeightPosition * this.fontSize / FontResource.Instance.FontHeight;
 73 
 74                 contentBitmap = new Bitmap(currentTextureWidth, currentTextureWidth);
 75                 Graphics gContentBitmap = Graphics.FromImage(contentBitmap);
 76                 Bitmap bigBitmap = fontResource.FontBitmap;
 77                 for (int i = 0; i < content.Length; i++)
 78                 {
 79                     char c = content[i];
 80                     CharacterInfo cInfo;
 81                     if (fontResource.CharInfoDict.TryGetValue(c, out cInfo))
 82                     {
 83                         if (currentWidthPos + cInfo.width > contentBitmap.Width)
 84                         {
 85                             currentWidthPos = 0;
 86                             currentHeightPos += fontResource.FontHeight;
 87                         }
 88 
 89                         gContentBitmap.DrawImage(bigBitmap,
 90                             new Rectangle(currentWidthPos, currentHeightPos, cInfo.width, fontResource.FontHeight),
 91                             new Rectangle(cInfo.xoffset, cInfo.yoffset, cInfo.width, fontResource.FontHeight),
 92                             GraphicsUnit.Pixel);
 93 
 94                         currentWidthPos += cInfo.width + interval;
 95                     }
 96                 }
 97                 gContentBitmap.Dispose();
 98                 //contentBitmap.Save("PointSpriteStringElement-contentBitmap.png");
 99                 System.Drawing.Bitmap bmp = null;
100                 if (totalLength * fontSize > maxRowWidth * fontResource.FontHeight)// 超過1行能顯示的內容
101                 {
102                     bmp = (System.Drawing.Bitmap)contentBitmap.GetThumbnailImage(
103                         maxRowWidth, maxRowWidth, null, IntPtr.Zero);
104                 }
105                 else//只在一行內即可顯示所有字符
106                 {
107                     if (totalLength >= fontResource.FontHeight)
108                     {
109                         bmp = (System.Drawing.Bitmap)contentBitmap.GetThumbnailImage(
110                             totalLength * fontSize / fontResource.FontHeight,
111                             totalLength * fontSize / fontResource.FontHeight,
112                             null, IntPtr.Zero);
113 
114                     }
115                     else
116                     {
117                         bmp = (System.Drawing.Bitmap)contentBitmap.GetThumbnailImage(
118                             fontSize, fontSize, null, IntPtr.Zero);
119                     }
120                 }
121                 contentBitmap.Dispose();
122                 contentBitmap = bmp;
123                 //contentBitmap.Save("PointSpriteStringElement-contentBitmap-scaled.png");
124             }
125 
126             return contentBitmap;
127 
128         }
計算字符串貼圖?

缺陷

用PointSprite繪制的文字,其大小范圍有限,本篇提供的Demo中,Max Row Width最大只有256。

總結

現在能夠繪制少量的文字,為其指定的位置的過程與為一個點指定位置的過程是相同的,所以此方式的應用范圍還是比較廣的。

版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。

原文链接:https://hbdhgg.com/5/184749.html

发表评论:

本站为非赢利网站,部分文章来源或改编自互联网及其他公众平台,主要目的在于分享信息,版权归原作者所有,内容仅供读者参考,如有侵权请联系我们删除!

Copyright © 2022 匯編語言學習筆記 Inc. 保留所有权利。

底部版权信息