C#+OpenGL+FreeType显示3D文字(2) - 用GLSL+VBO绘制文字
C#+OpenGL+FreeType显示3D文字(2) - 用GLSL+VBO绘制文字
上一篇得到了字形贴图及其位置字典(可导出为XML)。本篇就利用此贴图和位置字典,把文字绘制到OpenGL窗口。
基本流程
有了贴图,绘制文字和绘制普通纹理的过程是一样的。我们需要用glTexImage2D设定纹理,然后用GLSL+VBO设置一个长方形,把纹理的某个字形所占据的位置贴到长方形上,就可以绘制一个字符。连续设置多个长方形,就可以显示字符串了。
当然,用legacy opengl里的glVertex和glTexCoord来设置长方形和贴图也可以,不过本文推荐用modern opengl的GLSL+VBO的方式来实现。
您可以在此下载查看上图所示的demo。为节省空间,此demo只能显示ASCII范围内的字符。实际上它具有显示所有Unicode字符的能力。
编辑GLSL
我们只需vertex shader和fragment shader。
Vertex shader只是进行最基本的变换操作,并负责传递纹理坐标。
#version attribute vec3 in_Position;
attribute vec2 in_TexCoord;
varying vec2 texcoord;
uniform mat4 projectionMatrix;
uniform mat4 viewMatrix;
uniform mat4 modelMatrix; void main(void) {
gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(in_Position, );
texcoord = in_TexCoord;
}
Fragment shader根据纹理坐标所在位置的纹理颜色决定此位置是否显示(透明与否)。这就绘制出了一个字形。
#version varying vec2 texcoord;
uniform sampler2D tex;
uniform vec4 color; void main(void) {
gl_FragColor = vec4(, , , texture2D(tex, texcoord).r) * color;
}
设定VAO
每个字符的宽度是不同的,所以每个长方形都要据此调整宽度。下面是根据字符串生成VAO/VBO的片段。
private void InitVAO(string value)
{
if (value == null) { value = string.Empty; } this.mode = PrimitiveModes.Quads;
this.vertexCount = * value.Length; // Create a vertex buffer for the vertex data.
UnmanagedArray<vec3> in_Position = new UnmanagedArray<vec3>(this.vertexCount);
UnmanagedArray<vec2> in_TexCoord = new UnmanagedArray<vec2>(this.vertexCount);
Bitmap bigBitmap = this.ttfTexture.BigBitmap;
vec3[] tmpPositions = new vec3[this.vertexCount];
float totalLength = ;
for (int i = ; i < value.Length; i++)
{
char c = value[i];
CharacterInfo cInfo;
if (this.ttfTexture.CharInfoDict.TryGetValue(c, out cInfo))
{
float glyphWidth = (float)cInfo.width / (float)this.ttfTexture.FontHeight;
if (i == )
{
tmpPositions[i * + ] = new vec3(, , );
tmpPositions[i * + ] = new vec3(glyphWidth, , );
tmpPositions[i * + ] = new vec3(glyphWidth, , );
tmpPositions[i * + ] = new vec3(, , );
}
else
{
tmpPositions[i * + ] = tmpPositions[i * + - + ];
tmpPositions[i * + ] = tmpPositions[i * + ] + new vec3(glyphWidth, , );
tmpPositions[i * + ] = tmpPositions[i * + - - ];
tmpPositions[i * + ] = tmpPositions[i * + ] + new vec3(glyphWidth, , );
}
totalLength += glyphWidth;
} }
for (int i = ; i < value.Length; i++)
{
char c = value[i];
CharacterInfo cInfo;
float x1 = ;
float x2 = ;
float y1 = ;
float y2 = ;
if (this.ttfTexture.CharInfoDict.TryGetValue(c, out cInfo))
{
x1 = (float)cInfo.xoffset / (float)bigBitmap.Width;
x2 = (float)(cInfo.xoffset + cInfo.width) / (float)bigBitmap.Width;
y1 = (float)cInfo.yoffset / (float)bigBitmap.Height;
y2 = (float)(cInfo.yoffset + this.ttfTexture.FontHeight) / (float)bigBitmap.Height;
} in_Position[i * + ] = tmpPositions[i * + ] - new vec3(totalLength / , , );
in_Position[i * + ] = tmpPositions[i * + ] - new vec3(totalLength / , , );
in_Position[i * + ] = tmpPositions[i * + ] - new vec3(totalLength / , , );
in_Position[i * + ] = tmpPositions[i * + ] - new vec3(totalLength / , , ); in_TexCoord[i * + ] = new vec2(x1, y2);
in_TexCoord[i * + ] = new vec2(x2, y2);
in_TexCoord[i * + ] = new vec2(x2, y1);
in_TexCoord[i * + ] = new vec2(x1, y1);
} GL.GenVertexArrays(, vao);
GL.BindVertexArray(vao[]); GL.GenBuffers(, vbo); uint in_PositionLocation = shaderProgram.GetAttributeLocation(strin_Position);
GL.BindBuffer(BufferTarget.ArrayBuffer, vbo[]);
GL.BufferData(BufferTarget.ArrayBuffer, in_Position, BufferUsage.StaticDraw);
GL.VertexAttribPointer(in_PositionLocation, , GL.GL_FLOAT, false, , IntPtr.Zero);
GL.EnableVertexAttribArray(in_PositionLocation); uint in_TexCoordLocation = shaderProgram.GetAttributeLocation(strin_TexCoord);
GL.BindBuffer(BufferTarget.ArrayBuffer, vbo[]);
GL.BufferData(BufferTarget.ArrayBuffer, in_TexCoord, BufferUsage.StaticDraw);
GL.VertexAttribPointer(in_TexCoordLocation, , GL.GL_FLOAT, false, , IntPtr.Zero);
GL.EnableVertexAttribArray(in_TexCoordLocation); GL.BindVertexArray(); in_Position.Dispose();
in_TexCoord.Dispose();
}
根据字符串生成VAO/VBO
其它
在上一篇,我们通过TTF文件得到了贴图文件及其位置信息(XML文件)。此时其实不再需要借助freetype就可以直接使用这些贴图了。
另外,本文所给的demo已经包含了perspective和ortho两种透视的camera功能,固定在窗口左下角显示坐标系的功能,感兴趣的话通过反编译即可得到。
总结
现在能够绘制文字了,但是换行之类的高级功能还没有实现。这已经不熟悉opengl的研究范围,而是更高层的功能了,所以暂时不再深入考虑。
C#+OpenGL+FreeType显示3D文字(2) - 用GLSL+VBO绘制文字的更多相关文章
- C#+OpenGL+FreeType显示3D文字(1) - 从TTF文件导出字形贴图
C#+OpenGL+FreeType显示3D文字(1) - 从TTF文件导出字形贴图 +BIT祝威+悄悄在此留下版了个权的信息说: 最近需要用OpenGL绘制文字,这是个很费时费力的事.一般的思路就是 ...
- C#+OpenGL+FreeType显示3D文字(3) - 用PointSprite绘制文字
C#+OpenGL+FreeType显示3D文字(3) - 用PointSprite绘制文字 上一篇实现了把文字绘制到OpenGL窗口,但实质上只是把含有文字的贴图贴到矩形模型上.本篇我们介绍用Poi ...
- [OpenGL ES 03]3D变换:模型,视图,投影与Viewport
[OpenGL ES 03]3D变换:模型,视图,投影与Viewport 罗朝辉 (http://blog.csdn.net/kesalin) 本文遵循“署名-非商业用途-保持一致”创作公用协议 系列 ...
- OPENGL绘制文字
OPENGL没有提供直接绘制文字的功能,需要借助于操作系统. 用OPENGL绘制文字比较常见的方法是利用显示列表.创建一系列显示列表,每个字符对应一个列表编号.例如,'A'对应列表编号1000+'A' ...
- [iTyran原创]iPhone中OpenGL ES显示3DS MAX模型之二:lib3ds加载模型
[iTyran原创]iPhone中OpenGL ES显示3DS MAX模型之二:lib3ds加载模型 作者:u0u0 - iTyran 在上一节中,我们分析了OBJ格式.OBJ格式优点是文本形式,可读 ...
- [iTyran原创]iPhone中OpenGL ES显示3DS MAX模型之一:OBJ格式分析
[iTyran原创]iPhone中OpenGL ES显示3DS MAX模型之一:OBJ文件格式分析作者:yuezang - iTyran 在iOS的3D开发中常常需要导入通过3DS MAX之类 ...
- Windows MFC 两个OpenGL窗口显示与线程RC问题
问题为:背景界面是一个OpenGL窗口(对话框),在其上弹出一个OpenGL窗口(模态对话框)时, 1.上方的OpenGL窗口能响应鼠标操作等并刷新: 2.当移动或放大缩小上方的OpenGL窗口时,其 ...
- Flash Stage3D 在2D UI 界面上显示3D模型问题完美解决
一直以来很多Stage3D开发者都在为3D模型在2DUI上显示的问题头疼.Stage3D一直是在 Stage2D下面.为了做到3D模型在2DUI上显示通常大家有几种实现方式,下面来说说这几种实现方式吧 ...
- ArcGIS API for JavaScript 4.2学习笔记[2] 显示3D地图
3D地图又叫场景. 由上一篇可知, require入口函数的第一个参数是字符串数组 ["esri/Map", "esri/views/MapView", &qu ...
随机推荐
- F#之旅1 - Why use F#?为什么要用F#?
原文地址:http://fsharpforfunandprofit.com/why-use-fsharp/ Why use F#?Why you should consider using F# fo ...
- 注解 @RequestParam,@RequestHeader,@CookieValue,Pojo,servlet原生API
1.@RequestParam 我们的超链接:<a href="springMvc/testRequestParam">testRequestParam</a&g ...
- QT生成流水账号
在做数据库课程的时候,要生成财务表,每条记录应该有一个流水账号. 实现思路: 当前时间+随机一个四位数 上代码 //生成流水号 QString adminRecharge::getNumber() { ...
- TProfiler
下载:访问 TProfiler 的 GitHub 主页,https://github.com/alibaba/TProfiler,点击 Clone or download 按钮的打开下载选项,点击该选 ...
- ajax返回json数据,对其中日期的解析
JS 对其格式化 方法如下 function ChangeDateFormat(d){ //将时间戳转为int类型,构造Date类型 var date = new Date(parseInt(d.ti ...
- 读取web项目properties文件路径 解决tomcat服务器找不到properties路径问题
1.需求:有时候我们产品经理给我们的需求是会不断变化的,例如数量是1000现在变成500,我们不可以去改代码吧,这样很麻烦,所以就可以改配置文件properties(这个数据库链接一样),当然也有js ...
- 洛谷 P1201 [USACO1.1]贪婪的送礼者Greedy Gift Givers Label:ExWater
题目描述 对于一群(NP个)要互送礼物的朋友,GY要确定每个人送出的钱比收到的多多少.在这一个问题中,每个人都准备了一些钱来送礼物,而这些钱将会被平均分给那些将收到他的礼物的人.然而,在任何一群朋友中 ...
- db2 日期时间格式
db2日期和时间常用汇总 1.db2可以通过SYSIBM.SYSDUMMY1.SYSIBM.DUAL获取寄存器中的值,也可以通过VALUES关键字获取寄存器中的值. SELECT 'HELLO DB2 ...
- Ajax基础(小猫)
Ajax 1.什么是Ajax: 不用刷新整个页面便可与服务器通讯的办法 2.Ajax的基本使用 2.1XMLHttpRequest l XMLHttpRequest对象 XMLHttpRequest是 ...
- C#输出文本树形层次,前或者后自定义空格位数
Indent String with Spaces This example shows how to indent strings using method for padding in C#. T ...