Pergunta

Atualmente, estou desenvolvendo um pequeno jogo do OpenGL para a plataforma Android e me pergunto se há uma maneira fácil de renderizar o texto no topo do quadro renderizado (como um HUD com a pontuação do jogador etc.). O texto também precisaria usar uma fonte personalizada.

Vi um exemplo usando uma exibição como uma sobreposição, mas não sei se quero fazer isso, pois posso querer portar o jogo para outras plataformas posteriormente.

Alguma ideia?

Foi útil?

Solução

O Android SDK não vem com uma maneira fácil de desenhar texto em visualizações OpenGL. Deixando você com as seguintes opções.

  1. Coloque uma visão de texto sobre sua visão de superfície. Isso é lento e ruim, mas a abordagem mais direta.
  2. Renderizar seqüências comuns às texturas e simplesmente desenhe essas texturas. Este é de longe o mais simples e mais rápido, mas o menos flexível.
  3. Roll-your-your-your-your text rendering Code com base em um sprite. Provavelmente a segunda melhor escolha se 2 não é uma opção. Uma boa maneira de molhar os pés, mas observe que, embora pareça simples (e os recursos básicos são), fica mais difícil e desafiador à medida que você adiciona mais recursos (alinhamento de textura, lidando com quebras de linha, fontes de largura de variável etc. ) - Se você seguir esse caminho, faça o mais simples possível!
  4. Use uma biblioteca pronta para uso/código aberto. Existem alguns se você caçar no Google, a parte complicada é integrá -los e funcionar. Mas, pelo menos, depois de fazer isso, você terá toda a flexibilidade e maturidade que eles fornecem.

Outras dicas

Renderizar o texto a uma textura é mais simples do que a demonstração de texto sprite que parece, a idéia básica é usar a classe Canvas para renderizar um bitmap e depois passar o bitmap para uma textura 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();

Eu escrevi a tutorial que expande a resposta postada por JVitela. Basicamente, ele usa a mesma idéia, mas, em vez de renderizar cada string a uma textura, ela renderiza todos os personagens de um arquivo de fonte a uma textura e o usa para permitir a renderização de texto dinâmico completo sem mais desacelerações (uma vez que a inicialização for concluída) .

A principal vantagem do meu método, em comparação com os vários geradores do Atlas, é que você pode enviar pequenos arquivos de fonte (.ttf .otf) com seu projeto, em vez de ter que enviar grandes bitmaps para cada variação e tamanho da fonte. Ele pode gerar fontes de qualidade perfeitas em qualquer resolução usando apenas um arquivo de fonte :)

o tutorial Inclui código completo que pode ser usado em qualquer projeto :)

De acordo com este link:

http://code.neenbedankt.com/how-to-render-an-android-view-to--bitmap

Você pode renderizar qualquer visão para um bitmap. Provavelmente vale a pena assumir que você pode fazer um layout uma visualização conforme necessário (incluindo texto, imagens etc.) e depois renderizá -la a um bitmap.

Usando o código da JVitela acima de Você deve usar esse bitmap como uma textura do OpenGL.

Dê uma olhada no CBFG e na porta Android do código de carregamento/renderização. Você poderá colocar o código em seu projeto e usá -lo imediatamente.

CBFG - http://www.codehead.co.uk/cbfg

Carregador Android - http://www.codehead.co.uk/cbfg/texfont.java

Eu olhei para o exemplo de texto sprite e ele parece terrivelmente complicado para essa tarefa, também pensei em renderizar uma textura, mas estou preocupado com o desempenho do desempenho que poderia causar. Talvez eu tenha que ir com uma visão e me preocupar em portar quando é hora de atravessar aquela ponte :)

Olhe para a amostra de "texto sprite" no Amostras de GlsurfaceView.

IMHO Existem três razões para usar o OpenGL ES em um jogo:

  1. Evite diferenças entre as plataformas móveis usando um padrão aberto;
  2. Ter mais controle do processo de renderização;
  3. Se beneficiar do processamento paralelo da GPU;

O texto do desenho é sempre um problema no design do jogo, porque você está desenhando coisas, para que você não possa ter a aparência de uma atividade comum, com widgets e assim por diante.

Você pode usar uma estrutura para gerar fontes de bitmap a partir de fontes TrueType e renderizá -las. Todas as estruturas que eu já vi operam da mesma maneira: gerar o vértice e as coordenadas de textura para o texto em tempo de desenho. Este não é o uso mais eficiente do OpenGL.

A melhor maneira é alocar buffers remotos (objetos de buffer de vértices - VBOS) para os vértices e texturas no início do código, evitando as operações de transferência de memória preguiçosas no tempo de desenho.

Lembre -se de que os jogadores do jogo não gostam de ler o texto, para que você não escreva um texto longo dinamicamente gerado. Para rótulos, você pode usar texturas estáticas, deixando texto dinâmico para tempo e pontuação, e ambos são numéricos com alguns caracteres.

Então, minha solução é simples:

  1. Criar textura para rótulos e avisos comuns;
  2. Crie textura para números 0-9, ":", "+" e "-". Uma textura para cada personagem;
  3. Gere VBOs remotos para todas as posições na tela. Eu posso renderizar texto estático ou dinâmico nessas posições, mas os VBOs são estáticos;
  4. Gerar apenas uma textura VBO, pois o texto é sempre renderizado de uma maneira;
  5. No tempo de empate, eu renderizo o texto estático;
  6. Para um texto dinâmico, posso espiar na posição VBO, obter a textura do personagem e desenhá -la, um personagem de cada vez.

As operações de desenho são rápidas, se você usar buffers estáticos remotos.

Eu crio um arquivo XML com posições de tela (com base na porcentagem diagonal da tela) e texturas (estáticas e caracteres) e, em seguida, carrego esse XML antes de renderizar.

Para obter uma alta taxa de FPS, você deve evitar a geração de VBOS no tempo de empate.

Se você insistir em usar GL, poderá renderizar o texto em texturas. Supondo que a maior parte do HUD seja relativamente estática, você não deve carregar as texturas para texturar a memória com muita frequência.

Dar uma olhada em CBFG e a porta Android do código de carregamento/renderização. Você poderá colocar o código em seu projeto e usá -lo imediatamente.

  1. Cbfg

  2. Carregador Android

Tenho problemas com esta implementação. Ele exibe apenas um personagem, quando tento mudar o tamanho do bitmap da fonte (preciso de letras especiais) falhas inteiras :(

Eu tenho procurado isso há algumas horas, este foi o primeiro artigo que cheguei e, embora tenha a melhor resposta, as respostas mais populares que acho que estão erradas. Certamente pelo que eu precisava. As respostas de Weichsel e Shakazed estavam certas no botão, mas um pouco obscurecidas nos artigos. Para colocá -lo direto para o projeto. Aqui: basta criar um novo projeto Android com base na amostra existente. Escolha Apidemos:

Olhe sob a pasta de origem

ApiDemos/src/com/example/android/apis/graphics/spritetext

E você encontrará tudo o que precisa.

Por texto estático:

  • Gere uma imagem com todas as palavras usadas no seu PC (por exemplo, com o GIMP).
  • Carregue isso como uma textura e use -o como material para um plano.

Por texto longo Isso precisa ser atualizado de vez em quando:

  • Deixe o Android usar uma tela de bitmap (solução de JVitela).
  • Carregue isso como material para um avião.
  • Use diferentes coordenadas de textura para cada palavra.

Por um número (formatado 00.0):

  • Gere uma imagem com todos os números e um ponto.
  • Carregue isso como material para um avião.
  • Use abaixo do shader.
  • No seu evento ONDRAW, atualize apenas a variável de valor enviada ao shader.

    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;
    
    }
    

O código acima funciona para um atlas de textura, onde os números começam a partir de 0 na 7ª coluna da 2ª linha do Atlas da fonte (textura).

Referir-se https://www.shaderoy.com/view/xl23dw Para demonstração (com textura errada)

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top