현재 Android 플랫폼을위한 작은 OpenGL 게임을 개발 중이며 렌더링 된 프레임 위에 텍스트를 렌더링하는 쉬운 방법이 있는지 궁금합니다 (플레이어 점수 등의 HUD 등). 텍스트도 사용자 정의 글꼴을 사용해야합니다.
View를 오버레이로 사용하는 예를 보았지만 나중에 다른 플랫폼으로 게임을 이식하고 싶을 수도 있으므로 알지 모르겠습니다.
어떤 아이디어?
현재 Android 플랫폼을위한 작은 OpenGL 게임을 개발 중이며 렌더링 된 프레임 위에 텍스트를 렌더링하는 쉬운 방법이 있는지 궁금합니다 (플레이어 점수 등의 HUD 등). 텍스트도 사용자 정의 글꼴을 사용해야합니다.
View를 오버레이로 사용하는 예를 보았지만 나중에 다른 플랫폼으로 게임을 이식하고 싶을 수도 있으므로 알지 모르겠습니다.
어떤 아이디어?
답변:
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
안드로이드 로더-http: //www.codehead.co.uk/cbfg/TexFont.java
GLSurfaceView 샘플 에서 "Sprite Text"샘플을 보십시오 .
IMHO 게임에서 OpenGL ES를 사용해야하는 세 가지 이유가 있습니다.
텍스트를 그리는 것은 게임 디자인에서 항상 문제가됩니다. 물건을 그리기 때문에 위젯 등을 사용하여 일반적인 활동의 모양과 느낌을 가질 수 없습니다.
프레임 워크를 사용하여 트루 타입 글꼴에서 비트 맵 글꼴을 생성하고 렌더링 할 수 있습니다. 내가 본 모든 프레임 워크는 같은 방식으로 작동합니다. 그리기 시간에 텍스트의 정점 및 텍스처 좌표를 생성하십시오. 이것이 OpenGL을 가장 효율적으로 사용하는 것은 아닙니다.
가장 좋은 방법은 코드 초기에 정점과 텍스처에 원격 버퍼 (정점 버퍼 객체-VBO)를 할당하여 그리기 시간에 게으른 메모리 전송 작업을 피하는 것입니다.
게임 플레이어는 텍스트를 읽는 것을 좋아하지 않으므로 동적으로 긴 텍스트를 작성하지 마십시오. 레이블의 경우 정적 텍스처를 사용하여 시간과 점수에 대한 동적 텍스트를 남길 수 있으며 둘 다 길이가 몇 자릿수입니다.
따라서 내 솔루션은 간단합니다.
원격 정적 버퍼를 사용하면 그리기 작업이 빠릅니다.
화면 위치 (화면의 대각선 비율을 기준으로)와 텍스처 (정적 및 문자)로 XML 파일을 만든 다음 렌더링하기 전에이 XML을로드합니다.
높은 FPS 속도를 얻으려면 그리기시 VBO 생성을 피해야합니다.
나는 이것을 몇 시간 동안 찾고 있었는데, 이것이 내가 처음 접한 기사 였고 가장 좋은 답변을 받았지만 가장 인기있는 답변은 내가 표시하지 않았다고 생각합니다. 확실히 내가 필요한 것에. weichsel 's와 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;
}
위의 코드는 글꼴 아틀라스 (텍스처)의 두 번째 행의 7 번째 열에서 숫자가 0에서 시작하는 텍스처 아틀라스에 대해 작동합니다.
데모 는 https://www.shadertoy.com/view/Xl23Dw 를 참조하십시오 (잘못된 질감으로)
OpenGL ES 2.0 / 3.0에서는 OGL View와 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>
렌더 스레드에서 요소를 업데이트하려면 Handler / Looper를 사용할 수 있습니다.