私は現在、Androidプラットフォーム用の小さなOpenGLゲームを開発しています。レンダリングされたフレームの上にテキストを簡単にレンダリングする方法(プレーヤーのスコアのあるHUDなど)があるかどうか疑問に思っています。テキストもカスタムフォントを使用する必要があります。
ビューをオーバーレイとして使用する例を見てきましたが、後で他のプラットフォームにゲームを移植する可能性があるため、それを実行するかどうかはわかりません。
何か案は?
私は現在、Androidプラットフォーム用の小さなOpenGLゲームを開発しています。レンダリングされたフレームの上にテキストを簡単にレンダリングする方法(プレーヤーのスコアのあるHUDなど)があるかどうか疑問に思っています。テキストもカスタムフォントを使用する必要があります。
ビューをオーバーレイとして使用する例を見てきましたが、後で他のプラットフォームにゲームを移植する可能性があるため、それを実行するかどうかはわかりません。
何か案は?
回答:
Android SDKには、OpenGLビューでテキストを描画する簡単な方法はありません。次のオプションをご利用いただけます。
テキストのテクスチャへのレンダリングは、Sprite Textのデモのように簡単です。基本的な考え方は、Canvasクラスを使用してビットマップにレンダリングし、ビットマップをOpenGLテクスチャに渡すことです。
// Create an empty, mutable bitmap
Bitmap bitmap = Bitmap.createBitmap(256, 256, Bitmap.Config.ARGB_4444);
// get a canvas to paint over the bitmap
Canvas canvas = new Canvas(bitmap);
bitmap.eraseColor(0);
// get a background image from resources
// note the image format must match the bitmap format
Drawable background = context.getResources().getDrawable(R.drawable.background);
background.setBounds(0, 0, 256, 256);
background.draw(canvas); // draw the background to our bitmap
// Draw the text
Paint textPaint = new Paint();
textPaint.setTextSize(32);
textPaint.setAntiAlias(true);
textPaint.setARGB(0xff, 0x00, 0x00, 0x00);
// draw the text centered
canvas.drawText("Hello World", 16,112, textPaint);
//Generate one texture pointer...
gl.glGenTextures(1, textures, 0);
//...and bind it to our array
gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);
//Create Nearest Filtered Texture
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
//Different possible texture parameters, e.g. GL10.GL_CLAMP_TO_EDGE
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_REPEAT);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_REPEAT);
//Use the Android GLUtils to specify a two-dimensional texture image from our bitmap
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);
//Clean up
bitmap.recycle();
JVitelaが投稿した回答を拡張するチュートリアルを作成しました。基本的には同じアイデアを使用しますが、各文字列をテクスチャにレンダリングするのではなく、フォントファイルからテクスチャにすべての文字をレンダリングし、それを使用して(初期化が完了すると)それ以上の速度低下なしに完全なダイナミックテキストレンダリングを可能にします。 。
さまざまなフォントアトラスジェネレーターと比較した私の方法の主な利点は、フォントのバリエーションやサイズごとに大きなビットマップを出荷する必要がなく、プロジェクトに小さなフォントファイル(.ttf .otf)を出荷できることです。フォントファイルのみを使用して、あらゆる解像度で完璧な品質のフォントを生成できます。
チュートリアルでは、任意のプロジェクトで使用することができ、完全なコードが含まれています:)
このリンクによると:
http://code.neenbedankt.com/how-to-render-an-android-view-to-a-bitmap
任意のビューをビットマップにレンダリングできます。必要に応じてビューをレイアウトし(テキスト、画像などを含む)、ビットマップにレンダリングできると想定することはおそらく価値があります。
上記の JVitelaのコードを使用すると、そのビットマップをOpenGLテクスチャとして使用できるはずです。
ロード/レンダリングコードのCBFGとAndroidポートを見てください。コードをプロジェクトにドロップして、すぐに使用できるはずです。
CBFG- http://www.codehead.co.uk/cbfg
Androidローダー-http ://www.codehead.co.uk/cbfg/TexFont.java
GLSurfaceViewサンプルの「Sprite Text」サンプルを見てください。
私見ゲームでOpenGL ESを使用する3つの理由があります。
ゲームデザインでは、テキストを描画することは常に問題になります。描画しているため、ウィジェットなどを使用して、一般的なアクティビティのルックアンドフィールを実現することはできません。
フレームワークを使用して、TrueTypeフォントからビットマップフォントを生成し、レンダリングできます。私が見たすべてのフレームワークは同じように動作します:描画時にテキストの頂点とテクスチャ座標を生成します。これはOpenGLの最も効率的な使用法ではありません。
最善の方法は、コードの早い段階で頂点とテクスチャにリモートバッファー(頂点バッファーオブジェクト-VBO)を割り当てることで、描画時のレイジーメモリ転送操作を回避することです。
ゲームプレーヤーはテキストを読みたくないので、動的に生成された長いテキストは書きません。ラベルには、静的テクスチャを使用して、時間とスコアに動的テキストを残すことができます。どちらも数文字の数字です。
だから、私の解決策は簡単です:
リモート静的バッファーを使用すると、描画操作が高速になります。
画面の位置(画面の対角線のパーセンテージに基づく)とテクスチャー(静的および文字)を含むXMLファイルを作成し、レンダリング前にこのXMLをロードします。
高いFPSレートを得るには、描画時にVBOを生成しないようにする必要があります。
CBFG
読み込み/レンダリングコードのAndroidポートを見てください。コードをプロジェクトにドロップして、すぐに使用できるはずです。
この実装に問題があります。フォントのビットマップのサイズを変更しようとすると、1文字しか表示されません(特殊文字が必要です)全体の描画が失敗します:(
私はこれを数時間探していました。これは最初に出くわした記事であり、最良の答えはありますが、最も人気のある答えはマークから外れています。確かに私が必要なもののために。weichselとshakazedの答えはボタン上で正しかったが、記事では少しあいまいであった。あなたをプロジェクトに権利を置くために。ここ:既存のサンプルに基づいて新しいAndroidプロジェクトを作成するだけです。ApiDemosを選択します。
ソースフォルダの下を見てください
ApiDemos/src/com/example/android/apis/graphics/spritetext
そして、あなたはあなたが必要とするすべてを見つけるでしょう。
以下のための静的なテキスト:
たまに更新する必要がある長いテキストの場合:
以下のための番号(00.0フォーマット)。
onDrawイベントでは、シェーダーに送信された値変数のみを更新します。
precision highp float;
precision highp sampler2D;
uniform float uTime;
uniform float uValue;
uniform vec3 iResolution;
varying vec4 v_Color;
varying vec2 vTextureCoord;
uniform sampler2D s_texture;
void main() {
vec4 fragColor = vec4(1.0, 0.5, 0.2, 0.5);
vec2 uv = vTextureCoord;
float devisor = 10.75;
float digit;
float i;
float uCol;
float uRow;
if (uv.y < 0.45) {
if (uv.x > 0.75) {
digit = floor(uValue*10.0);
digit = digit - floor(digit/10.0)*10.0;
i = 48.0 - 32.0 + digit;
uRow = floor(i / 10.0);
uCol = i - 10.0 * uRow;
fragColor = texture2D( s_texture, uv / devisor * 2.0 + vec2((uCol-1.5) / devisor, uRow / devisor) );
} else if (uv.x > 0.5) {
uCol = 4.0;
uRow = 1.0;
fragColor = texture2D( s_texture, uv / devisor * 2.0 + vec2((uCol-1.0) / devisor, uRow / devisor) );
} else if (uv.x > 0.25) {
digit = floor(uValue);
digit = digit - floor(digit/10.0)*10.0;
i = 48.0 - 32.0 + digit;
uRow = floor(i / 10.0);
uCol = i - 10.0 * uRow;
fragColor = texture2D( s_texture, uv / devisor * 2.0 + vec2((uCol-0.5) / devisor, uRow / devisor) );
} else if (uValue >= 10.0) {
digit = floor(uValue/10.0);
digit = digit - floor(digit/10.0)*10.0;
i = 48.0 - 32.0 + digit;
uRow = floor(i / 10.0);
uCol = i - 10.0 * uRow;
fragColor = texture2D( s_texture, uv / devisor * 2.0 + vec2((uCol-0.0) / devisor, uRow / devisor) );
} else {
fragColor = vec4(0.0, 0.0, 0.0, 0.0);
}
} else {
fragColor = vec4(0.0, 0.0, 0.0, 0.0);
}
gl_FragColor = fragColor;
}
上記のコードは、フォントアトラス(テクスチャ)の2行目の7列目が0から始まるテクスチャアトラスで機能します。
デモについては、https://www.shadertoy.com/view/Xl23Dwを参照してください(ただし、テクスチャは正しくありません)。
OpenGL ES 2.0 / 3.0では、OGLビューとAndroidのUI要素を組み合わせることもできます。
public class GameActivity extends AppCompatActivity {
private SurfaceView surfaceView;
@Override
protected void onCreate(Bundle state) {
setContentView(R.layout.activity_gl);
surfaceView = findViewById(R.id.oglView);
surfaceView.init(this.getApplicationContext());
...
}
}
public class SurfaceView extends GLSurfaceView {
private SceneRenderer renderer;
public SurfaceView(Context context) {
super(context);
}
public SurfaceView(Context context, AttributeSet attributes) {
super(context, attributes);
}
public void init(Context context) {
renderer = new SceneRenderer(context);
setRenderer(renderer);
...
}
}
レイアウトactivity_gl.xmlを作成します。
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
tools:context=".activities.GameActivity">
<com.app.SurfaceView
android:id="@+id/oglView"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<TextView ... />
<TextView ... />
<TextView ... />
</androidx.constraintlayout.widget.ConstraintLayout>
レンダースレッドから要素を更新するには、ハンドラー/ルーパーを使用できます。