Renderowanie tekstu/czcionki w OpenGLES 2 (iOS-CoreText?)- opcje i najlepsze praktyki?
Jest wiele pytań dotyczących renderowania czcionek OpenGL, wiele z nich jest zadowolonych przez atlasy tekstowe (szybkie, ale złe) lub tekstury łańcuchowe (tylko tekst stały).
Jednak te podejścia są słabe i wydają się być przestarzałe od lat (a co z użyciem shaderów, aby zrobić to lepiej/szybciej?). Dla OpenGL 4.1 jest to doskonałe pytanie patrząc na "co należy używać Dzisiaj ?":
Co to jest state-of-the-art do renderowania tekstu w OpenGL od wersji 4.1?
Więc, co powinniśmy dziś używać na iOS GL ES 2?
Jestem rozczarowany, że wydaje się, że nie ma open-source (lub nawet rozwiązanie komercyjne). Wiem, że wiele zespołów ssie to w dół i spędza tygodnie czasu na wymyślaniu tego koła, stopniowo ucząc się jak kernować i spacji itp (ugh)- ale musi być lepszy sposób niż przepisywanie całego "fontu" od zera?
Z tego co widzę, są dwie części:
- Jak renderujemy tekst czcionką?
- Jak wyświetlić wyjście?
Dla 1 (Jak renderować), Apple zapewnia wiele sposobów na uzyskanie" poprawnego " renderowanego wyjścia - ale "łatwe" nie obsługują OpenGL (może niektóre inne tak robią - np. czy istnieje prosty sposób na mapowanie wyjścia CoreText do OpenGL?).
Dla 2 (Jak wyświetlać), mamy shadery, mamy VBOs, mamy glif-textures, mamy lookup-textures i inne tecniques (np. rzeczy związane z OpenGL 4.1 powyżej?)
Oto dwa popularne podejścia OpenGL, które znam:
- Atlas tekstur (renderuje wszystkie glify raz, a następnie renderuje 1 x teksturowany kwadrat na znak, ze współdzielonej tekstury)
- to jest złe, chyba że używasz "czcionki bitmapowej" z lat 80. (i nawet wtedy: texture atlas wymaga więcej pracy, niż może się wydawać, jeśli potrzebujesz poprawnej dla nietrywialnych czcionek) {21]}
- (czcionki nie są "zbiorem glifów" istnieje ogromna ilość pozycjonowania, układu, owijania, odstępy, kerning, stylizacja, koloryzacja, ważenie itp. Atlasy tekstur fail)
- Naprawiono ciąg znaków (użyj dowolnej klasy Apple, aby renderować poprawnie, a następnie zrzut ekranu z danych obrazu i przesłać jako teksturę)
-
Po ludzku, to jest szybkie. W renderowaniu klatek jest to bardzo, bardzo wolne. Jeśli zrobisz to z dużą ilością zmieniającego się tekstu, liczba klatek na sekundę przechodzi przez podłogę
- technicznie jest to w większości poprawne (nie do końca: tracisz w ten sposób pewne informacje), ale ogromnie nieefektywne
Ja też widziałem, ale słyszałem i dobre i złe rzeczy o:
- Imagination / PowerVR " Print3D "(link uszkodzony) (od facetów, którzy produkują GPU! Ale ich strona została przeniesiona / usunięta strona renderowania tekstu)
- FreeType (wymaga wstępnego przetwarzania, interpretacji, dużo kodu, dodatkowych bibliotek?)
- ...i / lub FTGL http://sourceforge.net/projects/ftgl / (plotki: powoli? buggy? Nie aktualizowane od dłuższego czasu czas?)
- Font-Stash http://digestingduck.blogspot.co.uk/2009/08/font-stash.html (wysoka jakość, ale bardzo wolno?) 1.
Wewnątrz własnych bibliotek OS / standard Apple, znam kilka źródeł renderowania tekstu. NB: większość z nich wykorzystałem szczegółowo w projektach renderowania 2D, moje wypowiedzi na ich temat są oparte na bezpośrednim doświadczeniu
- CoreGraphics with NSString
- najprostszy ze wszystkich: render " do CGRect "
- wydaje się, że jest to nieco szybsza wersja podejścia "stałego ciągu", które ludzie zalecają (choć można oczekiwać, że będzie prawie taki sam)
- UILabel i UITextArea ze zwykłym tekstem
- NB: one nie są takie same! Niewielkie różnice w sposobie renderowania tekstu smae
- NSAttributedString, renderowany do jednego z powyższych
- ponownie: rendery inaczej (różnice, które znam, są dość subtelne i klasyfikowane jako "Błędy", różne więc pytania na ten temat)
- CATextLayer
- hybryda pomiędzy czcionkami iOS i starym renderowaniem C. Używa" Nie w pełni " płatnego pomostu cffont / UIFont, który ujawnia pewne różnice w renderowaniu / dziwności
- CoreText
- ... ostateczne rozwiązanie? Ale sama bestia...
3 answers
Przeprowadziłem kolejne eksperymenty i wydaje się, że CoreText może być idealnym rozwiązaniem w połączeniu z atlasem tekstur i teksturami podpisanymi przez Valve (które mogą zmienić glif bitmapowy w niezależną od rozdzielczości teksturę hi-res).
...ale jeszcze nie działa, wciąż eksperymentuje.
Aktualizacja: dokumenty Apple mówią, że dają dostęp do wszystkiego, z wyjątkiem ostatecznego szczegółu: który glif + układ glifów do renderowania (można uzyskać układ linii, a liczba glifów, ale nie sam glif, zgodnie z dokumentami). Bez wyraźnego powodu ten rdzeń informacji najwyraźniej brakuje w CoreText (jeśli tak, to czyni CT prawie bezwartościowym. Nadal poluję, aby zobaczyć, czy mogę znaleźć sposób, aby uzyskać rzeczywiste dane glpyhs + per-glyph)
UPDATE2: mam teraz to działa poprawnie z CT Apple (ale nie różne-tekstury), ale kończy się jako 3 pliki klas, 10 struktur danych, około 300 linii kodu, PLUS Kod OpenGL do renderowania go. Też dużo za odpowiedź SO: (.
Krótka odpowiedź brzmi: tak, możesz to zrobić, i to działa, Jeśli:
- Utwórz CTFrameSetter
- utwórz ramkę CTFrame dla teoretycznej ramki 2D
- Utwórz CGContext, który przekonwertujesz na teksturę GL W przeciwieństwie do innych aplikacji, Apple nie może korzystać z funkcji cgcontext.]} Gdy Apple renderuje glif, Oblicz boundingbox (jest to trudne) i zapisz go gdzieś]}
- i zapisać unikalny glif-ID (ten będzie różny dla np. "o", "f" I " of " (jeden glif!))
- na koniec Wyślij swój CGContext do GL jako teksturę
Podczas renderowania Użyj listy identyfikatorów glifów utworzonych przez Apple, a dla każdego z nich Użyj zapisanych informacji i tekstury, aby renderować quady za pomocą współordów tekstur, które wyciągają poszczególne glify z przesłanej tekstury.
To działa, jest szybkie, działa ze wszystkimi czcionkami, ma poprawny układ czcionek i kerning itp.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-01-14 17:15:47
Wiem, że ten post jest stary, ale natknąłem się na niego, próbując zrobić to dokładnie w mojej aplikacji. W moich poszukiwaniach natknąłem się na ten przykładowy projekt
Http://metalbyexample.com/rendering-text-in-metal-with-signed-distance-fields/
Jest to doskonała implementacja CoreText z OpenGL przy użyciu technik atlasowania tekstur i podpisanych pól odległości. To bardzo pomogło mi osiągnąć pożądane rezultaty. Mam nadzieję, że to pomoże komuś innemu.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-23 19:35:07
1.
Utwórz dowolny ciąg znaków przez 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.
Utwórz CTFrame. rect
Oblicz z mabstring
za pomocą CoreText.CTFramesetterSuggestFrameSizeWithConstraints
let framesetter = CTFramesetterCreateWithAttributedString(mabstring)
let path = CGMutablePath()
path.addRect(rect)
let frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, 0), path, nil)
3.
Tworzenie kontekstu bitmapowego.
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.
Rysowanie CTFrame w kontekście bitmapowym.
CTFrameDraw(frame, context)
Teraz mamy surowe dane pikseli rawData
. Utwórz OpenGL Texture
, MTLTexture
, UIImage
z rawData
jest ok.
Przykład,
Do Tekstury OpenGL:Konwersja interfejsu użytkownika w Tekstura
Ustaw teksturę:
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)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:16:46