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

上一篇实现了把文字绘制到OpenGL窗口,但实质上只是把含有文字的贴图贴到矩形模型上。本篇我们介绍用PointSprite绘制文字,这可以只用1个点绘制文字,并确保文字始终面相窗口。用PointSprite绘制的文字,其大小范围有限,本篇提供的Demo中,Max Row Width最大只有256。现在能够绘制少量的文字,为其指定的位置的过程与为一个点指定位置的过程是相同的,所以此方式的应用范围还是比较广的。

基本流程

与前文相同的是仍然用GLSL+VBO+贴图来绘制。PointSprite只是Enable了一些OpenGL开关,然后把贴图贴到一个Point图元上。

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

编辑GLSL

我们只需vertex shader和fragment shader。

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

 #version  core

 in vec3 in_Position;

 uniform mat4 MVP;
uniform float pointSize; void main(void) {
gl_Position = MVP * vec4(in_Position, 1.0);
gl_PointSize = pointSize;
}

Fragment shader根据纹理坐标所在位置的纹理颜色决定此位置是否显示(透明与否)。这就绘制出了一个字形。还可以顺便用一个uniform vec3 textColor指定文字颜色。

 #version  core

 out vec4 out_Color;

 uniform sampler2D tex;
uniform vec3 textColor; void main(void) {
float transparency = texture2D(tex, gl_PointCoord).r;
if (transparency == 0.0f)
{
discard;
}
else
{
out_Color = vec4(, , , transparency) * vec4(textColor, 1.0f);
}
}

设定VAO

模型只需一个Point。

         private void InitVAO()
{
GL.GenVertexArrays(, vao);
GL.BindVertexArray(vao[]); // Create a vertex buffer for the vertex data.
{
UnmanagedArray<vec3> in_Position = new UnmanagedArray<vec3>();
in_Position[] = this.position; uint[] ids = new uint[];
GL.GenBuffers(, ids);
GL.BindBuffer(BufferTarget.ArrayBuffer, ids[]);
GL.BufferData(BufferTarget.ArrayBuffer, in_Position, BufferUsage.StaticDraw);
GL.VertexAttribPointer(attributeIndexPosition, , GL.GL_FLOAT, false, , IntPtr.Zero);
GL.EnableVertexAttribArray(attributeIndexPosition);
} // Unbind the vertex array, we've finished specifying data for it.
GL.BindVertexArray();
}

程序生成文字贴图

要想显示任意的字符串,必须借助前文的贴图来一个字符一个字符地拼接出需要的字符串贴图并用之生成Texture。

这是从上面的图片中计算出的"bithuwei.cnblogs.com"的贴图。

由于PointSprite支持的贴图大小有限(最大256),所以计算字符串贴图的程序有点繁琐。

         /// <summary>
/// 为指定的字符串生成贴图。
/// </summary>
/// <param name="fontResource"></param>
/// <param name="content"></param>
/// <param name="fontSize"></param>
/// <param name="maxRowWidth"></param>
/// <returns></returns>
public static System.Drawing.Bitmap GenerateBitmapForString(this FontResource fontResource,
string content, int fontSize, int maxRowWidth)
{
// step 1: get totalLength
int totalLength = ;
{
int glyphsLength = ;
for (int i = ; i < content.Length; i++)
{
char c = content[i];
CharacterInfo cInfo;
if (fontResource.CharInfoDict.TryGetValue(c, out cInfo))
{
int glyphWidth = cInfo.width;
glyphsLength += glyphWidth;
}
//else
//{ throw new Exception(string.Format("Not support for display the char [{0}]", c)); }
} //glyphsLength = (glyphsLength * this.fontSize / FontResource.Instance.FontHeight);
int interval = fontResource.FontHeight / ; if (interval < ) { interval = ; }
totalLength = glyphsLength + interval * (content.Length - );
} // step 2: setup contentBitmap
System.Drawing.Bitmap contentBitmap = null;
{
int interval = fontResource.FontHeight / ; if (interval < ) { interval = ; }
//int totalLength = glyphsLength + interval * (content.Length - 1);
int currentTextureWidth = ;
int currentWidthPos = ;
int currentHeightPos = ;
if (totalLength * fontSize > maxRowWidth * fontResource.FontHeight)// 超过1行能显示的内容
{
currentTextureWidth = maxRowWidth * fontResource.FontHeight / fontSize; int lineCount = (totalLength - ) / currentTextureWidth + ;
// 确保整篇文字的高度在贴图中间。
currentHeightPos = (currentTextureWidth - fontResource.FontHeight * lineCount) / ;
//- FontResource.Instance.FontHeight / 2;
}
else//只在一行内即可显示所有字符
{
if (totalLength >= fontResource.FontHeight)
{
currentTextureWidth = totalLength; // 确保整篇文字的高度在贴图中间。
currentHeightPos = (currentTextureWidth - fontResource.FontHeight) / ;
//- FontResource.Instance.FontHeight / 2;
}
else
{
currentTextureWidth = fontResource.FontHeight; currentWidthPos = (currentTextureWidth - totalLength) / ;
//glyphsLength = fontResource.FontHeight;
}
} //this.textureWidth = textureWidth * this.fontSize / FontResource.Instance.FontHeight;
//currentWidthPosition = currentWidthPosition * this.fontSize / FontResource.Instance.FontHeight;
//currentHeightPosition = currentHeightPosition * this.fontSize / FontResource.Instance.FontHeight; contentBitmap = new Bitmap(currentTextureWidth, currentTextureWidth);
Graphics gContentBitmap = Graphics.FromImage(contentBitmap);
Bitmap bigBitmap = fontResource.FontBitmap;
for (int i = ; i < content.Length; i++)
{
char c = content[i];
CharacterInfo cInfo;
if (fontResource.CharInfoDict.TryGetValue(c, out cInfo))
{
if (currentWidthPos + cInfo.width > contentBitmap.Width)
{
currentWidthPos = ;
currentHeightPos += fontResource.FontHeight;
} gContentBitmap.DrawImage(bigBitmap,
new Rectangle(currentWidthPos, currentHeightPos, cInfo.width, fontResource.FontHeight),
new Rectangle(cInfo.xoffset, cInfo.yoffset, cInfo.width, fontResource.FontHeight),
GraphicsUnit.Pixel); currentWidthPos += cInfo.width + interval;
}
}
gContentBitmap.Dispose();
//contentBitmap.Save("PointSpriteStringElement-contentBitmap.png");
System.Drawing.Bitmap bmp = null;
if (totalLength * fontSize > maxRowWidth * fontResource.FontHeight)// 超过1行能显示的内容
{
bmp = (System.Drawing.Bitmap)contentBitmap.GetThumbnailImage(
maxRowWidth, maxRowWidth, null, IntPtr.Zero);
}
else//只在一行内即可显示所有字符
{
if (totalLength >= fontResource.FontHeight)
{
bmp = (System.Drawing.Bitmap)contentBitmap.GetThumbnailImage(
totalLength * fontSize / fontResource.FontHeight,
totalLength * fontSize / fontResource.FontHeight,
null, IntPtr.Zero); }
else
{
bmp = (System.Drawing.Bitmap)contentBitmap.GetThumbnailImage(
fontSize, fontSize, null, IntPtr.Zero);
}
}
contentBitmap.Dispose();
contentBitmap = bmp;
//contentBitmap.Save("PointSpriteStringElement-contentBitmap-scaled.png");
} return contentBitmap; }

计算字符串贴图

缺陷

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

总结

现在能够绘制少量的文字,为其指定的位置的过程与为一个点指定位置的过程是相同的,所以此方式的应用范围还是比较广的。

C#+OpenGL+FreeType显示3D文字(3) - 用PointSprite绘制文字的更多相关文章

  1. C#+OpenGL+FreeType显示3D文字(1) - 从TTF文件导出字形贴图

    C#+OpenGL+FreeType显示3D文字(1) - 从TTF文件导出字形贴图 +BIT祝威+悄悄在此留下版了个权的信息说: 最近需要用OpenGL绘制文字,这是个很费时费力的事.一般的思路就是 ...

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

    C#+OpenGL+FreeType显示3D文字(2) - 用GLSL+VBO绘制文字 +BIT祝威+悄悄在此留下版了个权的信息说: 上一篇得到了字形贴图及其位置字典(可导出为XML).本篇就利用此贴 ...

  3. Android 使用Canvas在图片上绘制文字

    一个小应用,在图片上绘制文字,以下是绘制文字的方法,并且能够实现自动换行,字体自动适配屏幕大小 private void drawNewBitmap(ImageView imageView, Stri ...

  4. [OpenGL ES 03]3D变换:模型,视图,投影与Viewport

    [OpenGL ES 03]3D变换:模型,视图,投影与Viewport 罗朝辉 (http://blog.csdn.net/kesalin) 本文遵循“署名-非商业用途-保持一致”创作公用协议 系列 ...

  5. OPENGL绘制文字

    OPENGL没有提供直接绘制文字的功能,需要借助于操作系统. 用OPENGL绘制文字比较常见的方法是利用显示列表.创建一系列显示列表,每个字符对应一个列表编号.例如,'A'对应列表编号1000+'A' ...

  6. [iTyran原创]iPhone中OpenGL ES显示3DS MAX模型之二:lib3ds加载模型

    [iTyran原创]iPhone中OpenGL ES显示3DS MAX模型之二:lib3ds加载模型 作者:u0u0 - iTyran 在上一节中,我们分析了OBJ格式.OBJ格式优点是文本形式,可读 ...

  7. [iTyran原创]iPhone中OpenGL ES显示3DS MAX模型之一:OBJ格式分析

    [iTyran原创]iPhone中OpenGL ES显示3DS MAX模型之一:OBJ文件格式分析作者:yuezang - iTyran     在iOS的3D开发中常常需要导入通过3DS MAX之类 ...

  8. Windows MFC 两个OpenGL窗口显示与线程RC问题

    问题为:背景界面是一个OpenGL窗口(对话框),在其上弹出一个OpenGL窗口(模态对话框)时, 1.上方的OpenGL窗口能响应鼠标操作等并刷新: 2.当移动或放大缩小上方的OpenGL窗口时,其 ...

  9. Flash Stage3D 在2D UI 界面上显示3D模型问题完美解决

    一直以来很多Stage3D开发者都在为3D模型在2DUI上显示的问题头疼.Stage3D一直是在 Stage2D下面.为了做到3D模型在2DUI上显示通常大家有几种实现方式,下面来说说这几种实现方式吧 ...

随机推荐

  1. JQuery的无缝滚动

    图片无缝向左滚动的代码如下:   <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "h ...

  2. Beginning Scala study note(2) Basics of Scala

    1. Variables (1) Three ways to define variables: 1) val refers to define an immutable variable; scal ...

  3. Qt中暂停线程的执行

    在线程中定义一个信号量 QMutex pause; 把run()函数中循环执行的部分用信号量pause锁住: void run() { while(1) { pause.lock(); //循环执行的 ...

  4. jave ee之 servlet 记录

    1:没有自动生成web.xml文件 解决方法:新建web工程的时候最后会选择是否创建web.xml文件 2:通过url映射无法打开对应网站 <servlet> <servlet-na ...

  5. 转载:移动web开发规范

    本文来源:http://blog.csdn.net/joueu/article/details/44329825 以下是规范建议,均是日常在开发当中的的一些经验,仅供参考. 移动web开发规范 一.头 ...

  6. Android中ListView的几种常见的优化方法

    Android中的ListView应该算是布局中几种最常用的组件之一了,使用也十分方便,下面将介绍ListView几种比较常见的优化方法: 首先我们给出一个没有任何优化的Listview的Adapte ...

  7. servlet中文乱码问题

    通过response对象向页面输出内容时遇到的乱码问题可分为两种情况 1.字节流 字节流输出时可以通过设置响应头"Content-Type"的值为"text/html;c ...

  8. Dubbo与Zookeeper、SpringMVC整合和使用(负载均衡、容错)

    互联网的发展,网站应用的规模不断扩大,常规的垂直应用架构已无法应对,分布式服务架构以及流动计算架构势在必行,Dubbo是一个分布式服务框架,在这种情况下诞生的.现在核心业务抽取出来,作为独立的服务,使 ...

  9. 关于nginx.pid丢失的解决办法

    在停掉nginx的过程中突然出现如下的提示:

  10. 解决 adb.exe 停止工作小续

    继adb 停止工作的问题之后,又碰见了adb 停止工作的问题. 在使用adb install app.apk 之后给出错误信息如下: * daemon not running. starting it ...