Quem já pensou em como funciona a parte gráfica de um retro acelerador 2D, representa grosso modo como ele desenha esses notórios Ladrilhos, que, aliás, pela definição não precisam ser retangulares. Tiling é sobre tiling. Sim, na maioria das vezes os desenvolvedores da API de hardware entendem isso e os métodos são chamados de drawRect e não drawTile. Qualquer retângulo pode ser um ladrilho, mas o inverso não é verdade! E aqui a questão está se formando: por que os aceleradores 2D aceleram persistentemente apenas ret ... A resposta simples para essa pergunta é porque todo o resto é muito complicado para uma simples peça de hardware. Mas aqui eu argumentaria. Pelo menos uma extensão simples, mas altamente funcional desta abstração básica pode ser proposta, a seguinte.
Faz muito tempo que não escrevo para Habr. Porque o tempo todo eu queria fazer perfeitamente ... Eu tenho uma doença dessas. O próprio Habr, por sua vez, baixou significativamente a fasquia, e ainda não escrevo e não escrevo. Portanto, o artigo de hoje nasceu sem preparação apenas de uma conversa com um amigo. No entanto, existem amigos com quem você deseja conversar profunda e completamente.
Que seja, talvez, meu retorno à regularidade. Se tal mais ou menos leitura fácil, com tinta às pressas, mas minimamente suficiente para esclarecimento, a narração não é sobrecarregada de detalhes, mas ainda com um acento conceitual, e como uma lâmpada, como uma vez, chegará a um leitor caro.
Em outras palavras, hoje procuro um compromisso entre a qualidade do conteúdo e o tempo que posso dedicar a ele. Esperança de compreensão.
Então, vamos começar ...
Considere, para uma amostra, a função geral de copiar uma área retangular arbitrária. Vemos que este é apenas um loop duplo através das linhas e através dos elementos das linhas:
Observe que este bloco de código é geralmente repetido trivialmente em x4 combinações de direções de passagem de ambos os loops para implementar Reflexões:
Outras combinações x2 são dadas pela permutação da ordem por dst [x] [y], refletindo ao longo do eixo y = x.
Ao longo do caminho, essas 8 opções de reflexos são todas rotações possíveis em múltiplos de 90gr com todos os seus reflexos de espelho da esquerda para a direita.
E agora vamos ver como, mesmo com adições mínimas, esse elemento básico pode ser bastante modificado.
Talvez nunca tenha ocorrido a ninguém, mas por que um ladrilho não pode ser, por exemplo, um paralelepípedo? Olhando para o futuro, direi que esta extensão tem sobrecarga mínima, porque para implementar isso, você precisa adicionar apenas alguns incrementos por linha:
Como resultado da combinação com a permutação x / y, obtemos um paralelepípedo com um par de lados sempre orientado ao longo de um ortogonal, e os outros dois estarão em um ângulo ... O que essa bagatela recebida de forma barata nos dá? Bem, em primeiro lugar, a capacidade de usar três projeções fixas:
Se o incremento não for uma constante, mas um número fracionário, o ângulo de deslocamento pode se tornar livre. Que pode ser perfeitamente utilizado tanto para os efeitos de ladrilhos oscilantes no cilindro lateral:
E para a construção de paredes no espaço de projeções isométricas:
E lembre-se de que falar fracionário não significa necessariamente suporte de flutuação! O que um programador mimado moderno às vezes começa a esquecer. float é fracionário com ponto flutuante, mas aqui é completamente desnecessário. Na verdade, qualquer processador com registradores duplos, onde a parte superior do par pode ser lida como um valor separado, tem "suporte" para ponto fixo fracionário (ponto fixo). Além disso, neste caso, NÃO uma única instrução extra será adicionada. (Bem, exceto que a inclinação será definida em 256 batidas) Então é tudo de graça, rapazes!
Outra etapa semelhante que o leitor atento deve induzir indutivamente é a repetição deste funcional para o segundo limite da enumeração do loop interno. Afinal, podemos desacoplar o incremento final separadamente. E então, no caso geral, poderemos desenhar qualquer trapézio com base em uma das ortogonais (como um caso especial de triângulos):
E o que diabos eles nos deram? Você vai pensar, mas vai adivinhar imediatamente que em apenas duas dessas chamadas de desenho, você está simplesmente texturizando um plano de hexágonos orientados ortogonalmente ou losangos orientados diagonalmente, de um tileset preparado para isso. A propósito, caixas de tiling que são bastante comuns na indústria de jogos.
Nos dias de J2ME
J2ME , . , ,
Seria ótimo ter suporte de hardware para eles no acelerador: O
resto descrito é mais uma funcionalidade bônus, uma vez que você pode implementá-lo melhor de forma intencional. No entanto, se falamos, entre outras coisas, apenas sobre preencher o primitivo apenas com cor (ou um padrão plano), para algumas adições simples ao espaço de jogo existente ...
O mesmo par de chamadas de empate pode formar qualquer triângulo que não seja limitado a particulares (ele é simplesmente cortado em dois por uma linha ortogonal ao longo do meio ponto, isso é muito semelhante ao seu algoritmo de desenho clássico) E a partir disso já é possível construir construções em perspectiva. A propósito, a partir dos próprios trapézios, por exemplo, uma projeção 3D verticalmente fixa DOOM1 da forma é obtida de forma elementar e barata:
Se desejar, você pode tentar pintar com preenchimento até mesmo algo mais ou menos voxel grande. Dependendo dos graus de liberdade da projeção, gastando mais ou menos chamadas de empate. As duas primeiras projeções em perspectiva abaixo são fixas, mas cada uma tem 4 visualizações simétricas - para um total de 8 ângulos de exibição. O terceiro é um caso comum e só é corrigido verticalmente. Girando em torno do eixo vertical, ele alternará entre o primeiro e o segundo:
É melhor dividir as figuras em trapézios, se possível, em peças que são mais alongadas ao longo da ortogonal do corte, porque a funcionalidade de chamada adicional, embora não seja cara, está associada a iterações do ciclo apenas externo, do qual é desejável que haja menos. Na verdade, isso é verdade até mesmo para desenhar o algoritmo retângulo básico - desenhar horizontalmente é mais eficiente do que vertical.
É possível realizar texturização em perspectiva na funcionalidade bônus nessas chamadas, mas requer a implementação de escalonamento fracionário e está associada à introdução de coeficientes de divergência adicionais para src e coeficientes de decimação, que, além disso, precisarão ser calculados dinamicamente em 3D de maneira tortuosa, o que não é aconselhável para isso arquitetura simples.
Bem, terminando a vingança antes de Habr para meu próprio interesse, eu ainda não consigo resistir a explicar brevemente de onde vem algebricamente toda essa mágica de coeficientes de incremento A fórmula da linha reta y = kx + b, que é ensinada nas escolas, nos envia aqui duas vezes ao mesmo tempo. Todos os coeficientes foram úteis em seus lugares:
Por que não encontrei aceleradores de hardware 2D com essa implementação de blocos, só posso imaginar:
- O conceito do Tile era um padrão tão rigidamente fixado na prática que ninguém pensou que poderia fazer um pouco mais ... obter muito mais.
- Ou ninguém queria gastar nem mesmo alguns ciclos de clock em tais funções, porque eles não analisaram as consequências generalizadas descritas, ou os desenvolvedores de jogos simples não criaram demanda para eles. No entanto, havia o mode7 (um algoritmo de trapaça para implementar texturização em perspectiva, através da saída de peças de sprites retangulares em hardware com suporte para escala fracionária)
- Ou não tenho idade suficiente e preciso continuar ...