私は現在、OpenGL ES の初心者であり、iOS ゲームのプログラミング方法を独学で学んでいます。私は現在、いくつかのカスタム テキストで HUD を配置したいプロジェクトで遊んでいます。私はUILabelを使用してこれを行いたくありません.現在、Quadsを使用してpngなどのテキストを切り取り、表示に使用する通常のテキストに添付する方法がわかりません. 最終結果がコマンド/メソッドに単純な文字列を提供し、クワッドのテクスチャ/ビットマップを使用して出力が表示されるようにしたいと考えています。glPrint("Hello World"); と言います。誰かが私を適切な方向に導くことができますか? OpenGL ES 2.0 (OpenGL のみ) でこれを行う方法に関する単一の優れたチュートリアルはないようです。また、サードパーティの API の使用を避けたいと考えています。私は本当にこれに取り組む方法を理解する必要があります/理解したいと思っています.
2 に答える
現在の 2D プロジェクトで OpenGL ES を使い始めたとき、Ray のチュートリアルを使用しました。これは、テクスチャ付きの 2D クワッドのレンダリングを理解するのに役立ちました。彼の3D OpenGL ES チュートリアルと併せて、やりたいことをつなぎ合わせることができるかもしれません。チュートリアルのようにすべてのクワッドを個別にレンダリングすることはおそらくないことに注意してください。これは非常に非効率的です。代わりに、キャラクターのすべての頂点を 2 つの大きな配列/頂点バッファーに集めて、キャラクターをバッチ レンダリングします。各フレームをレンダリングするための基本的なフローは、おそらく次のようになります。3D レンダリング用の通常の透視投影マトリックスを渡し、3D シーンの頂点情報を何らかの方法でシェーダーに取得し、3D シーンをレンダリングします。この部分はすでに完了しています。テキストについては、直後に正射影行列を渡し、フォント テクスチャをバインドします (通常は、以前にGLKTextureLoader
glDrawArrays
クラス) をアクティブなテクスチャ ユニットに追加し、文字のテクスチャとジオメトリック頂点の 2 つの大きな配列を生成し、テキストが変更されている場合は VBO を更新し、それを渡し、またはglDrawElements
(インデックスが必要)を使用してすべての文字を一度にバッチ レンダリングします。 )。
また、私も OpenGL を使用するのが初めてなので、これのいくつかは間違っている/非効率的である可能性があります。私はまだ OpenGL ES を使用して 3D をレンダリングしたことがないので、3D シーンと 2D シーン (テキスト) のレンダリングの間に別の射影行列が必要になる可能性がある以外に、他にどのような状態変更 (有効化、無効化など) が必要なのかわかりません。 .
OpenGL のみを使用してテキストを描画するのは比較的難しく退屈な作業のようです。そのため、フレーム レートなどを表示する HUD オーバーレイをレンダリングするだけの場合はUILabel
、特にプロジェクトがあまり複雑ではありません。これにより、ラッピング、カーニング、フォントサイズ、色、さまざまな言語、およびより複雑なものが必要な場合にテキストレンダリングを非常に複雑にするその他の負荷に対処する必要がなくなります.
各文字の位置を追跡するのではなく、Core Graphics を使用して文字列全体をビットマップに描画し、それをテクスチャとしてアップロードしてみませんか? そのテキスト文字列に対して描画するクワッドのサイズを知るには、ビットマップから寸法を取得するだけで済みます。
オープン ソースの GPUImage フレームワーク内に、同様の処理を行う GPUImageUIElement という入力クラスがあります。その入力からの関連コードは次のとおりです。
CGSize layerPixelSize = [self layerSizeInPixels];
GLubyte *imageData = (GLubyte *) calloc(1, (int)layerPixelSize.width * (int)layerPixelSize.height * 4);
CGColorSpaceRef genericRGBColorspace = CGColorSpaceCreateDeviceRGB();
CGContextRef imageContext = CGBitmapContextCreate(imageData, (int)layerPixelSize.width, (int)layerPixelSize.height, 8, (int)layerPixelSize.width * 4, genericRGBColorspace, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst);
CGContextTranslateCTM(imageContext, 0.0f, layerPixelSize.height);
CGContextScaleCTM(imageContext, layer.contentsScale, -layer.contentsScale);
[layer renderInContext:imageContext];
CGContextRelease(imageContext);
CGColorSpaceRelease(genericRGBColorspace);
glBindTexture(GL_TEXTURE_2D, outputTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (int)layerPixelSize.width, (int)layerPixelSize.height, 0, GL_BGRA, GL_UNSIGNED_BYTE, imageData);
free(imageData);
このコードは、CALayer を (直接または UIView のバッキング レイヤーから) 取得し、その内容をテクスチャにレンダリングします。この前に既にテクスチャを初期化しているので、コードはビットマップ コンテキストを設定し、 を使用してレイヤーをそのコンテキストにレンダリングし、-renderInContext:
そのビットマップをテクスチャにアップロードして OpenGL ES で使用します。
ヘルパー メソッド-layerSizeInPixels
は、現在の Retina スケール ファクターを次のように考慮します。
- (CGSize)layerSizeInPixels;
{
CGSize pointSize = layer.bounds.size;
return CGSizeMake(layer.contentsScale * pointSize.width, layer.contentsScale * pointSize.height);
}
ビューに UILabel を使用し、テキストに合わせて自動サイズ調整した場合、テキストを設定し、上記を使用してテクスチャをレンダリングおよびアップロードし、要素のピクセル サイズを取得してクワッド サイズを決定できます。-drawAtPoint:withFont:fontForSize:
ただし、 NSString などを使用して自分でテキストを描画する方がおそらく効率的です。
Core Graphics を使用してテキストをレンダリングすると、テキストを NSString として操作しやすくなり、自分で作成する代わりに Core Graphics のすべての組版機能を使用できます。