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只是进行最基本的变换操作,并负责传递纹理坐标。

 #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的研究范围,而是更高层的功能了,所以暂时不再深入考虑。

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

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

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

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

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

    C#+OpenGL+FreeType显示3D文字(3) - 用PointSprite绘制文字 上一篇实现了把文字绘制到OpenGL窗口,但实质上只是把含有文字的贴图贴到矩形模型上.本篇我们介绍用Poi ...

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

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

  4. OPENGL绘制文字

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

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

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

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

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

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

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

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

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

  9. ArcGIS API for JavaScript 4.2学习笔记[2] 显示3D地图

    3D地图又叫场景. 由上一篇可知, require入口函数的第一个参数是字符串数组 ["esri/Map", "esri/views/MapView", &qu ...

随机推荐

  1. maven权威指南学习笔记(四)—— maven生命周期(lifecycle)

    定义: 生命周期是包含在一个项目构建中的一系列有序的阶段 举个例子来说就是maven 对一个工程进行: 验证(validate) -- 编译源码(compile) -- 编译测试源码(test-com ...

  2. (UWP)通过编写算法实现在地图中的渐变路径

    目前的一个App中需要实现这个需求,但是在UWP自带的Bing Map中,绘制的MapPolyline的StrokeColor的类型是Windows.UI.Color,也就是说一条MapPolylin ...

  3. Linux下安装Tomcat服务器和部署Web应用

    一.上传Tomcat服务器

  4. OX中修改文件名

    右击文件,显示简介,名称与扩展名

  5. Shell_3 函数

    1 函数 函数可以让我们将一个复杂功能划分成若干模块,让程序结构更加清晰,代码重复利用率更高.像其他编程语言一样,Shell 也支持函数.Shell 函数必须先定义后使用. 函数返回值,可以显式增加r ...

  6. startssl申请配置免费https证书

    之前给业务配置都是在沃通上申请免费证书,而后通过反向代理层的Nginx进行https认证. 今天来了个新需求,要求域名直接解析至阿里云SLB.https配置需要通过阿里云的控制台部署这倒无所谓,只是在 ...

  7. Shader实例:序列帧动画

    效果: 序列帧图片网上随便找的,质量不是很好,重点不是它,不要在意. 思路: 1.之前都是在一张面片上直接映射一张纹理,IN.uv的范围是0~1 现在要映射一张纹理上的一小块区域,就要用这块区域的uv ...

  8. 使用Jmeter录制web脚本

    1:启动Jmeter: 2:选择测试计划,右键->添加->Threads(users)>线程组 3:选择这个线程组,右键->添加->配置元件->HTTP请求默认值, ...

  9. weex逻辑控制

    在WEEX中,有if 和 repeat 两种逻辑运算,需要注意的是,逻辑控制不能够作用于<template>这样的根节点. if 控制判断条件true/false直接对节点进行操作,if= ...

  10. java反射学习之二万能EXCEL导出

    一.EXCEL导出的实现过程 假设有一个对象的集合,现在需要将此集合内的所有对象导出到EXCEL中,对象有N个属性:那么我们实现的方式是这样的: 循环这个集合,在循环集合中某个对象的所有属性,将这个对 ...