버전 4.1 기준으로 OpenGL에서 텍스트 렌더링을위한 최첨단 기술은 무엇입니까? [닫은]
OpenGL의 텍스트 렌더링에 대한 많은 질문이 이미 있습니다.
그러나 대부분 논의 된 것은 고정 기능 파이프 라인을 사용하여 텍스처 쿼드를 렌더링하는 것입니다. 확실히 쉐이더가 더 나은 방법을 만들어야합니다.
나는 국제화에 대해 정말로 걱정하지 않습니다. 대부분의 문자열은 플롯 눈금 레이블 (날짜와 시간 또는 순수한 숫자)입니다. 그러나 플롯은 화면 새로 고침 빈도로 다시 렌더링되며 화면에 수천 개의 글리프가 아니라 하드웨어 가속 레이아웃이 충분할 정도로 텍스트가 상당히 많을 수 있습니다.
최신 OpenGL을 사용한 텍스트 렌더링에 권장되는 방법은 무엇입니까? (이 방법을 사용하여 기존 소프트웨어를 인용하는 것이 잘 작동한다는 좋은 증거입니다)
- 위치 및 방향 및 문자 시퀀스를 받아들이고 텍스처 쿼드를 방출하는 형상 쉐이더
- 벡터 글꼴을 렌더링하는 지오메트리 셰이더
- 위와 같이 테셀레이션 셰이더를 대신 사용
- 폰트 래스터 화를위한 계산 셰이더
총 12 자만 렌더링하지 않는 한 렌더링 외곽선은 곡률을 근사화하기 위해 문자 당 필요한 꼭짓점 수로 인해 "없음"으로 유지됩니다. 픽셀 쉐이더에서 베 지어 곡선을 평가하는 접근 방법이 있었지만, 이들은 앤티 앨리어싱이 쉽지 않기 때문에 거리 맵 텍스쳐 쿼드를 사용하는 것이 쉽지 않으며 쉐이더의 곡선을 평가하는 데 여전히 필요한 것보다 훨씬 비쌉니다.
"빠른"품질과 "품질"간의 최상의 균형은 여전히 서명 된 거리 필드 텍스처를 가진 텍스처 쿼드입니다. 그것은이다 매우 경미 하지만 너무 느린 일반 정상적인 질감 쿼드를 사용하는 것보다. 반면에 품질은 완전히 다른 야구장에 있습니다. 결과는 정말 놀랍고, 최대한 빨리 얻을 수 있으며, 글로우와 같은 효과도 쉽게 추가 할 수 있습니다. 또한 필요한 경우이 기술을 이전 하드웨어로 다운 그레이드 할 수 있습니다.
이 기술에 대해서는 유명한 밸브 용지 를 참조하십시오 .
이 기술은 다각형을 생성하지 않지만 암시 적 표면 (메타 볼 등)의 작동 방식과 개념적으로 유사합니다. 전적으로 픽셀 쉐이더에서 실행되며 텍스처에서 샘플링 된 거리를 거리 함수로 사용합니다. 선택한 임계 값 (일반적으로 0.5)을 초과하는 모든 항목은 "in"이고 다른 모든 항목은 "out"입니다. 가장 간단한 경우, 10 년 된 비 쉐이더 가능 하드웨어에서 알파 테스트 임계 값을 0.5로 설정하면 정확한 효과가 나타납니다 (특수 효과 및 앤티 앨리어싱은 없지만).
글꼴 (가짜 굵은 글꼴)에 약간 더 가중치를 추가하려면 한 줄의 코드를 수정하지 않고 약간 더 작은 임계 값을 사용하여 트릭을 수행합니다 ( "font_weight"유니폼 변경). 글로우 효과의 경우, 단순히 하나의 임계 값을 초과하는 모든 것을 "in"으로, 다른 (작은) 임계 값을 초과하는 모든 것을 "out, but in glow"로, LERP는 둘 사이를 고려합니다. 앤티 앨리어싱도 비슷하게 작동합니다.
단일 비트가 아닌 8 비트 부호있는 거리 값을 사용함으로써이 기법은 각 차원에서 텍스처 맵의 유효 해상도를 16 배 증가시킵니다 (흑백 대신 모든 가능한 음영이 사용되므로 256 배의 동일한 저장소를 사용하는 정보). 그러나 16 배 이상으로 확대하더라도 결과는 여전히 타당합니다. 긴 직선은 결국 약간 흔들리지 만 전형적인 "블록킹"샘플링 아티팩트는 없습니다.
점에서 쿼드를 생성하기 위해 지오메트리 쉐이더를 사용할 수 있지만 (버스 대역폭 감소) 솔직히 게인은 다소 미미합니다. GPG8에 설명 된 인스턴스화 된 문자 렌더링의 경우에도 마찬가지입니다. 인스턴스화의 오버 헤드는 그릴 텍스트가 많은 경우에만 상각됩니다 . 필자의 의견으로는 추가 된 복잡성과 비 다운 그레이드 가능성과 관련이 없다고 생각합니다. 또한 상수 레지스터의 양에 제한을 받거나 캐시 일관성에 대해 최적화되지 않은 텍스처 버퍼 객체에서 읽어야합니다 (그리고 의도는 처음부터 최적화하는 것입니다!).
업로드를 조금 미리 미리 예약하고 지난 15 년 동안 구축 된 모든 하드웨어에서 실행되는 경우 단순하고 평범한 오래된 정점 버퍼는 빠르거나 빠를 수 있습니다. 또한 글꼴의 특정 문자 수 또는 렌더링 할 특정 문자 수로 제한되지 않습니다.
글꼴에 256자를 초과하지 않는 경우 텍스처 셰이더는 지오메트리 셰이더의 포인트에서 쿼드를 생성하는 것과 유사한 방식으로 버스 대역폭을 제거하는 것이 좋습니다. 배열 텍스처를 사용할 때 모든 쿼드의 텍스처 좌표는 동일하고, 상수 s
이며, t
좌표 는 동일 하며 좌표 만 다릅니다 r
. 이는 렌더링 할 문자 인덱스와 같습니다.
그러나 다른 기술과 마찬가지로 이전 세대 하드웨어와 호환되지 않으면 예상되는 이득은 미미합니다.
거리 텍스처를 생성하기위한 Jonathan Dummer의 편리한 도구가 있습니다 : description page
업데이트 :
최근에 프로그래밍 가능한 정점 풀링 (D. Rákos, "OpenGL Insights", pp. 239) 에서 지적했듯이 최신 GPU의 셰이더에서 프로그래밍 방식으로 정점 데이터를 가져 오는 것과 관련된 추가 대기 시간이나 오버 헤드는 없습니다. 표준 고정 기능을 사용하여 동일한 작업을 수행하는 것과 비교할 때
또한 최신 세대의 GPU는 점점 더 합리적인 크기의 범용 L2 캐시 (예 : 엔비디아 케플러의 1536kiB)를 가지므로 버퍼 텍스처에서 쿼드 코너에 대한 임의의 오프셋을 가져올 때 비 일관적인 액세스 문제가 발생할 수 있습니다. 문제.
따라서 버퍼 텍스처에서 일정한 데이터 (예 : 쿼드 크기)를 가져 오는 아이디어가 더 매력적입니다. 따라서 가상 구현은 다음과 같은 접근 방식으로 GPU 메모리뿐만 아니라 PCIe 및 메모리 전송을 최소로 줄일 수 있습니다.
- 이 색인을 통과하는 정점 셰이더에 대한 유일한 입력으로 문자 색인 (표시 할 문자 당 하나) 만 업로드
gl_VertexID
하고을 형상 쉐이더의 4 점으로 증폭하여 문자 색인과 정점 ID를 유지하십시오. "버텍스 쉐이더에서 사용할 수있는 gl_primitiveID")가 유일한 속성으로 변환 피드백을 통해이를 캡처합니다. - 두 가지 출력 속성 (GS의 주요 병목 현상) 만 있고 두 단계 모두에서 "no-op"에 가깝기 때문에 이것은 빠릅니다.
- 글꼴의 각 문자에 대해 기준점을 기준으로 질감 처리 된 쿼드의 정점 위치를 포함하는 버퍼 텍스처를 바인딩합니다 (기본적으로 "글꼴 메트릭"임). 이 데이터는 왼쪽 하단 정점의 오프셋 만 저장하고 축 정렬 상자의 너비와 높이를 인코딩하여 쿼드 당 4 개의 숫자로 압축 할 수 있습니다 (반 부동 수를 가정하면 문자 당 8 바이트의 상수 버퍼 임). 일반적인 256 문자 글꼴은 2kiB의 L1 캐시에 완전히 들어갈 수 있습니다).
- 기준선에 유니폼을 설정
- 버퍼 오프셋을 수평 오프셋과 바인딩합니다. 이것들 은 아마도 GPU에서 계산 될 수도 있지만, CPU에서 이런 종류의 작업에 훨씬 쉽고 효율적입니다. 왜냐하면 엄격하게 순차적 인 작업이므로 전혀 중요하지 않습니다 (커닝에 대한 생각). 또한 다른 피드백 포인트가 필요하며 이는 다른 동기 점입니다.
- 피드백 버퍼에서 이전에 생성 된 데이터를 렌더링하면 정점 셰이더는 기준점의 수평 오프셋과 버퍼 객체에서 코너 정점의 오프셋을 가져옵니다 (기본 ID 및 문자 색인 사용). 제출 된 정점의 원래 정점 ID는 이제 "기본 ID"입니다 (GS가 정점을 쿼드로 바꾼 것을 기억하십시오).
이와 같이, 단일 정점 만 렌더링 할 수는 있지만 필요한 정점 대역을 75 %까지 줄일 수 있습니다. 한 번의 호출로 여러 줄을 렌더링하려면 유니폼을 사용하는 대신 버퍼 텍스처에 기준선을 추가해야합니다 (대역폭이 더 작아짐).
그러나 "합리적인"양의 텍스트를 표시하는 정점 데이터가 약 50-100kiB (실제로 0) 이기 때문에 75 % 감소를 가정하더라도GPU 또는 PCIe 버스에 연결)-여전히 복잡성이 증가하고 이전 버전과의 호환성을 잃는 것이 실제로 가치가 있다고 의심합니다. 0을 75 % 줄이면 여전히 0입니다. 나는 위의 접근법을 시도하지 않았으며, 진정으로 자격을 갖춘 진술을하기 위해서는 더 많은 연구가 필요할 것입니다. 그러나 여전히 누군가가 정말 놀라운 성능 차이 (수십억자가 아닌 "일반적인"양의 텍스트를 사용함)를 보여줄 수 없다면, 내 관점은 정점 데이터의 경우 단순하고 평범한 오래된 정점 버퍼가 충분히 훌륭하다는 것입니다. "최신 솔루션"의 일부로 간주됩니다. 간단하고 간단하며 작동하며 잘 작동합니다.
위에서 " OpenGL Insights " 를 이미 참조 했으므로 Stefan Gustavson의 "거리 필드에 의한 2D 모양 렌더링" 장을 참조하여 거리 필드 렌더링에 대해 자세히 설명합니다.
2016 업데이트 :
한편, 극단적 인 배율에서 방해되는 코너 라운딩 인공물을 제거하는 것을 목표로하는 몇 가지 추가 기술이 존재한다.
한 가지 접근 방식은 단순히 거리 필드 대신 의사 거리 필드를 사용합니다 (차이는 실제 윤곽선이 아니라 가장자리 또는 가장자리 위로 튀어 나오는 가상 선 까지의 최단 거리라는 차이점이 있습니다). 이것은 약간 더 좋으며 같은 양의 텍스처 메모리를 사용하여 같은 속도 (동일한 셰이더)로 실행됩니다.
다른 접근법은 github에서 사용 가능한 3 채널 텍스처 세부 사항 및 구현에서 3 중위를 사용합니다 . 이는 이전에 문제를 해결하기 위해 사용 된 해킹 및 / 또는 해킹에 비해 개선되는 것입니다. 좋은 품질, 약간, 거의 눈에 띄지는 않지만 느리지 만 텍스처 메모리의 3 배를 사용합니다. 또한 추가 효과 (예 : 광선)를 제대로 맞추기가 더 어렵습니다.
마지막으로, 캐릭터를 구성하는 실제 베 지어 곡선을 저장하고 프래그먼트 셰이더로 평가하는 것은 약간 열악한 성능 (그러나 문제가되지는 않지만)과 가장 높은 배율에서도 놀라운 결과를 제공하는 실용화되었습니다 .
이 기술을 사용하여 대형 PDF를 실시간으로 렌더링하는 WebGL 데모는 여기 에서 볼 수 있습니다 .
http://code.google.com/p/glyphy/
The main difference between GLyphy and other SDF-based OpenGL renderers is that most other projects sample the SDF into a texture. This has all the usual problems that sampling has. Ie. it distorts the outline and is low quality. GLyphy instead represents the SDF using actual vectors submitted to the GPU. This results in very high quality rendering.
The downside is that the code is for iOS with OpenGL ES. I'm probably going to make a Windows/Linux OpenGL 4.x port (hopefully the author will add some real documentation, though).
The most widespread technique is still textured quads. However in 2005 LORIA developed something called vector textures, i.e. rendering vector graphics as textures on primitives. If one uses this to convert TrueType or OpenType fonts into a vector texture you get this:
http://alice.loria.fr/index.php/publications.html?Paper=VTM@2005
I'm surprised Mark Kilgard's baby, NV_path_rendering (NVpr), was not mentioned by any of the above. Although its goals are more general than font rendering, it can also render text from fonts and with kerning. It doesn't even require OpenGL 4.1, but it is a vendor/Nvidia-only extension at the moment. It basically turns fonts into paths using glPathGlyphsNV
which depends on the freetype2 library to get the metrics, etc. Then you can also access the kerning info with glGetPathSpacingNV
and use NVpr's general path rendering mechanism to display text from using the path-"converted" fonts. (I put that in quotes, because there's no real conversion, the curves are used as is.)
The recorded demo for NVpr's font capabilities is unfortunately not particularly impressive. (Maybe someone should make one along the lines of the much snazzier SDF demo one can find on the intertubes...)
The 2011 NVpr API presentation talk for the fonts part starts here and continues in the next part; it is a bit unfortunate how that presentation is split.
More general materials on NVpr:
- Nvidia NVpr hub, but some material on the landing page is not the most up-to-date
- Siggraph 2012 paper for the brains of the path-rendering method, called "stencil, then cover" (StC); the paper also explains briefly how competing tech like Direct2D works. The font-related bits have been relegated to an annex of the paper. There are also some extras like videos/demos.
- GTC 2014 presentation for an update status; in a nutshell: it's now supported by Google's Skia (Nvidia contributed the code in late 2013 and 2014), which in turn is used in Google Chrome and [independently of Skia, I think] in a beta of Adobe Illustrator CC 2014
- the official documentation in the OpenGL extension registry
- USPTO has granted at least four patents to Kilgard/Nvidia in connection with NVpr, of which you should probably be aware of, in case you want to implement StC by yourself: US8698837, US8698808, US8704830 and US8730253. Note that there are something like 17 more USPTO documents connected to this as "also published as", most of which are patent applications, so it's entirely possible more patents may be granted from those.
And since the word "stencil" did not produce any hits on this page before my answer, it appears the subset of the SO community that participated on this page insofar, despite being pretty numerous, was unaware of tessellation-free, stencil-buffer-based methods for path/font rendering in general. Kilgard has a FAQ-like post at on the opengl forum which may illuminate how the tessellation-free path rendering methods differ from bog standard 3D graphics, even though they're still using a [GP]GPU. (NVpr needs a CUDA-capable chip.)
For historical perspective, Kilgard is also the author of the classic "A Simple OpenGL-based API for Texture Mapped Text", SGI, 1997, which should not be confused with the stencil-based NVpr that debuted in 2011.
Most if not all the recent methods discussed on this page, including stencil-based methods like NVpr or SDF-based methods like GLyphy (which I'm not discussing here any further because other answers already cover it) have however one limitation: they are suitable for large text display on conventional (~100 DPI) monitors without jaggies at any level of scaling, and they also look nice, even at small size, on high-DPI, retina-like displays. They don't fully provide what Microsoft's Direct2D+DirectWrite gives you however, namely hinting of small glyphs on mainstream displays. (For a visual survey of hinting in general see this typotheque page for instance. A more in-depth resource is on antigrain.com.)
I'm not aware of any open & productized OpenGL-based stuff that can do what Microsoft can with hinting at the moment. (I admit ignorance to Apple's OS X GL/Quartz internals, because to the best of my knowledge Apple hasn't published how they do GL-based font/path rendering stuff. It seems that OS X, unlike MacOS 9, doesn't do hinting at all, which annoys some people.) Anyway, there is one 2013 research paper that addresses hinting via OpenGL shaders written by INRIA's Nicolas P. Rougier; it is probably worth reading if you need to do hinting from OpenGL. While it may seem that a library like freetype already does all the work when it comes to hinting, that's not actually so for the following reason, which I'm quoting from the paper:
The FreeType library can rasterize a glyph using sub-pixel anti-aliasing in RGB mode. However, this is only half of the problem, since we also want to achieve sub-pixel positioning for accurate placement of the glyphs. Displaying the textured quad at fractional pixel coordinates does not solve the problem, since it only results in texture interpolation at the whole-pixel level. Instead, we want to achieve a precise shift (between 0 and 1) in the subpixel domain. This can be done in a fragment shader [...].
The solution is not exactly trivial, so I'm not going to try to explain it here. (The paper is open-access.)
One other thing I've learned from Rougier's paper (and which Kilgard doesn't seem to have considered) is that the font powers that be (Microsoft+Adobe) have created not one but two kerning specification methods. The old one is based on a so-called kern table and it is supported by freetype. The new one is called GPOS and it is only supported by newer font libraries like HarfBuzz or pango in the free software world. Since NVpr doesn't seem to support either of those libraries, kerning might not work out of the box with NVpr for some new fonts; there are some of those apparently in the wild, according to this forum discussion.
Finally, if you need to do complex text layout (CTL) you seem to be currently out of luck with OpenGL as no OpenGL-based library appears to exist for that. (DirectWrite on the other hand can handle CTL.) There are open-sourced libraries like HarfBuzz which can render CTL, but I don't know how you'd get them to work well (as in using the stencil-based methods) via OpenGL. You'd probably have to write the glue code to extract the re-shaped outlines and feed them into NVpr or SDF-based solutions as paths.
I think your best bet would be to look into cairo graphics with OpenGL backend.
The only problem I had when developing a prototype with 3.3 core was deprecated function usage in OpenGL backend. It was 1-2 years ago so situation might have improved...
Anyway, I hope in the future desktop opengl graphics drivers will implement OpenVG.
'IT story' 카테고리의 다른 글
문자열에“”를 추가하면 왜 메모리가 절약됩니까? (0) | 2020.05.12 |
---|---|
언제 Task.Yield ()를 사용합니까? (0) | 2020.05.12 |
Visual Studio에서 만든 obj 및 bin 폴더는 무엇에 사용됩니까? (0) | 2020.05.12 |
객체 리터럴과 함수로 선언 된 녹아웃 뷰 모델의 차이점 (0) | 2020.05.12 |
X-Requested-With 헤더의 요점은 무엇입니까? (0) | 2020.05.12 |