OpenGL字体渲染有很多问题,其中很多都是纹理图集(快速但错误)或字符串纹理(仅限固定文本)。
然而,这些方法很差,似乎已经过时了(使用着色器更好/更快地做到这一点怎么样?)。对于OpenGL 4.1,有一个很好的问题,看看“你今天应该使用什么?”:
What is state-of-the-art for text rendering in OpenGL as of version 4.1?
那么,今天我们应该在iOS GL ES 2上使用什么?
我很失望,似乎没有开源(甚至是商业解决方案)。我知道有很多团队把它搞砸了,花了几周的时间重新发明这个轮子,逐渐学习如何克服和空间等(呃) - 但必须有一个比重写整个“字体”更好的方法从头开始?
据我所知,这有两个部分:
对于1(如何渲染),Apple提供了许多方法来获得“正确的”渲染输出 - 但“简单”的方法不支持OpenGL(也许其他一些人也可以 - 例如,有一种简单的方法可以将CoreText输出映射到OpenGL?)。
对于2(如何显示),我们有着色器,我们有VBO,我们有字形纹理,我们有查找纹理和其他技术(例如上面链接的OpenGL 4.1内容?)
以下是我所知道的两种常见的OpenGL方法:
我也看到了,但是听到了好的和坏的事情:
在Apple自己的操作系统/标准库中,我知道几种文本渲染源。注意:我已经在2D渲染项目中详细使用了大部分内容,我关于它们输出不同渲染的陈述是基于直接体验
答案 0 :(得分:7)
我做了一些实验,看起来CoreText在与纹理图集和Valve的有符号差异纹理(可以将位图字形转换为与分辨率无关的高分辨率纹理)结合时可能会提供完美的解决方案。
......但我还没有工作,还在尝试。
更新:Apple的文档说他们可以访问除最终细节之外的所有内容:要呈现的字形+字形布局(根据文档,您可以获得行布局,字形数量,但不能使用字形本身) 。由于没有明显的原因,CoreText显然缺少这个核心信息(如果是这样,那使得CT几乎一文不值。我还在寻找能否找到实现glpyhs + per-glyph数据的方法) / p>
UPDATE2:我现在可以正常使用Apple的CT(但没有不同的纹理),但它最终成为3个类文件,10个数据结构,大约300行代码,再加上OpenGL代码来渲染它。 SO答案太多了:(。
简短的回答是:是的,你可以做到,如果你这样做,它就可以了:
渲染时,使用Apple创建的字形ID列表,并使用保存的信息和纹理,使用纹理协作渲染四边形,从而将单个字形拉出您上传的纹理
这很有效,它很快,适用于所有字体,它可以获得所有字体布局和字距调整等等。
答案 1 :(得分:1)
我知道这篇文章很老了,但是我试图在我的应用程序中完成此操作时遇到了它。在我的搜索中,我遇到了这个示例项目
http://metalbyexample.com/rendering-text-in-metal-with-signed-distance-fields/
使用纹理图集和签名距离字段技术,OpenGL是CoreText的完美实现。它极大地帮助我实现了我想要的结果。希望这有助于其他人。
答案 2 :(得分:0)
1
按NSMutableAttributedString
创建任意字符串。
let mabstring = NSMutableAttributedString(string: "This is a test of characterAttribute.")
mabstring.beginEditing()
var matrix = CGAffineTransform(rotationAngle: CGFloat(GLKMathDegreesToRadians(0)))
let font = CTFontCreateWithName("Georgia" as CFString?, 40, &matrix)
mabstring.addAttribute(kCTFontAttributeName as String, value: font, range: NSRange(location: 0, length: 4))
var number: Int8 = 2
let kdl = CFNumberCreate(kCFAllocatorDefault, .sInt8Type, &number)!
mabstring.addAttribute(kCTStrokeWidthAttributeName as String, value: kdl, range: NSRange(location: 0, length: mabstring.length))
mabstring.endEditing()
2
创建CTFrame。 rect
由mabstring
按CoreText计算。CTFramesetterSuggestFrameSizeWithConstraints
let framesetter = CTFramesetterCreateWithAttributedString(mabstring)
let path = CGMutablePath()
path.addRect(rect)
let frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, 0), path, nil)
3
创建位图上下文。
let imageWidth = Int(rect.width)
let imageHeight = Int(rect.height)
var rawData = [UInt8](repeating: 0, count: Int(imageWidth * imageHeight * 4))
let bitmapInfo = CGBitmapInfo(rawValue: CGBitmapInfo.byteOrder32Big.rawValue | CGImageAlphaInfo.premultipliedLast.rawValue)
let rgbColorSpace = CGColorSpaceCreateDeviceRGB()
let bitsPerComponent = 8
let bytesPerRow = Int(rect.width) * 4
let context = CGContext(data: &rawData, width: imageWidth, height: imageHeight, bitsPerComponent: bitsPerComponent, bytesPerRow: bytesPerRow, space: rgbColorSpace, bitmapInfo: bitmapInfo.rawValue)!
4
在位图上下文中绘制CTFrame。
CTFrameDraw(frame, context)
现在,我们获得了原始像素数据rawData
。使用OpenGL Texture
创建MTLTexture
,UIImage
,rawData
即可。
实施例,
到OpenGL纹理:Convert an UIImage in a texture
设置纹理:
GLuint textureID;
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glGenTextures(1, &textureID);
glBindTexture(GL_TEXTURE_2D, textureID);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, textureData);
,
//to MTLTexture
let textureDescriptor = MTLTextureDescriptor.texture2DDescriptor(pixelFormat: .rgba8Unorm, width: Int(imageWidth), height: Int(imageHeight), mipmapped: true)
let device = MTLCreateSystemDefaultDevice()!
let texture = device.makeTexture(descriptor: textureDescriptor)
let region = MTLRegionMake2D(0, 0, Int(imageWidth), Int(imageHeight))
texture.replace(region: region, mipmapLevel: 0, withBytes: &rawData, bytesPerRow: imageRef.bytesPerRow)
,
//to UIImage
let providerRef = CGDataProvider(data: NSData(bytes: &rawData, length: rawData.count * MemoryLayout.size(ofValue: UInt8(0))))
let renderingIntent = CGColorRenderingIntent.defaultIntent
let imageRef = CGImage(width: imageWidth, height: imageHeight, bitsPerComponent: 8, bitsPerPixel: 32, bytesPerRow: bytesPerRow, space: rgbColorSpace, bitmapInfo: bitmapInfo, provider: providerRef!, decode: nil, shouldInterpolate: false, intent: renderingIntent)!
let image = UIImage.init(cgImage: imageRef)