Mode 7

A empresa dos consoles de Nintendo SNES tinha suas "armas secretas" para se colocar acima de seus concorrentes. Uma delas era a modelagem gráfica conhecida como Mode 7. Este tipo de modelagem foi utilizada nos jogos (F-Zero, Mario Kart, Pilotwings, The Legend of Zelda: A Link to the Past, entre outros...). Este post tem como intuito, mostrar de forma detalhada como funciona este tipo de modelagem, e como pode ser implementada. Utilizamos a linguagem Java e montamos um passo-a-
passo para você poder transformar seus gráficos 2D em gráficos pseudo-3D.



Mode 7 nada mais é que um mapeamento de uma imagem 2D em um resultado pseudo-3D. Pseudo-3D pois não é considerado um 3D real, como os gráficos do dia de hoje.

O fluxo para geração do Mode 7 é o seguinte:
1. Pegar as coordenadas X, Y
2. Dividir X e Y por Z gerando as coordenadas _X e _Y.
3. Atribuir as coordenadas X e Y com o valor das coordenadas _X e _Y da textura.

Isto funciona como um mapeamento de textura em um plano 3D. A fórmula a ser utilizada para este processo é basicamente a fórmula abaixo:

_X = X / Z
_Y = Y / Z

X - É a posição x da tela de renderização
Y - É a posição y da tela de renderização
Z - É uma variável incrementada para cada leitura Y da tela de renderização
_X - É a coordenada x gerada que deve ser utilizada para selecionar o valor da textura
_Y - É a coordenada y gerada que deve ser utilizada para selecionar o valor da textura

Claro que lendo os conceitos e as fórmulas matemáticas não é tão simples para entender o processo, portanto irei mostrar o processo de uma forma bem detalhada.

Basicamente o sistema repete a cor da textura quanto mais perto estiver da tela. Ou seja, lendo a tela de renderização começando pelas coordenadas X = 0 Y = 0 (Topo superior esquerdo), e começando Z = 0, temos a seguinte lógica:



Neste exemplo, podemos ver que no topo da tela de renderização, a textura não teve repetições. Já na segunda linha, houve uma repetição de 1 pixel, e assim sucessivamente. Quanto maior o Z, mais vezes o mesmo pixel da textura será mostrado, dando uma sensação de profundidade. No exemplo acima, só foram utilizadas as coordenadas X e _X para demonstração.

Agora vamos colocar isto no papel. Para a implementação, irei utilizar a linguagem JAVA, más é basicamente a mesma lógica para qualquer linguagem de programação.

1. Vamos iniciar nosso projeto.



2. Agora vamos criar nossa tela de renderização. Utilizei o tamanho 800 x 600 para a tela.



3. Com nossa tela criada, vamos agora criar nossas imagens em memória. A primeira imagem será a imagem que será renderizada na tela. A segunda será a imagem de nossa textura.



Utilizei a textura abaixo que eu mesmo desenhei no paint. Ela possui o tamanho 16 x 16.



4. Agora começaremos a fazer a lógica do Mode 7. Como teremos que percorrer todos os pixels da tela de cima para baixo, teremos que criar 2 comandos "for". Também aproveitaremos para criar nossas variáveis _x, _y e z. A variável z será somente uma variável que será incrementada conforme o a posição Y.



5. Vamos inserir nossa formula para obter a nova posição x e y, ou seja, as posições _x e _y.

Fórmula:
_X = X / Z
_Y = Y / Z


6. Podemos já buscar a cor da posição _x e _y da textura, e inserir esta cor obtida na posição x e y da tela de renderização. Utilizei os métodos setRGB e getRGB para facilitar a implementação, porém estes métodos não são recomendados pela perda de performance em seu uso.


7. Ops, uma exceção ocorreu! Obviamente estamos tentando pegar posições inexistentes em nossa textura. Isso acontece pois os valores de _x e _y ultrapassaram o tamanho limite de nossa textura.



8. Já que este tutorial foca em criar um Mode 7 infinito, iremos ter que repetir as posições da textura. Para isto utilizaremos o operador módulo.


9. Com isto, nossas posições não terão como ultrapassar os limites da textura. Após colocar este controle de limite, vamos inserir um loop para a imagem em memória ser desenhada na tela.



10. O resultado é algo parecido com nossa demonstração na planilha do excel.



11. Já que estamos trabalhando com uma imagem de textura 16x16, podemos criar duas variáveis de escala, para aumentar ou diminuir o tamanho da renderização da textura na tela.



12. Ao executar o código, vimos que o alvo de nossa perspectiva não está centralizado, más está no ponto X = 0 e Y = 0 (Canto superior esquerdo) de nossa tela de renderização. Queremos que o alvo seja no centro da tela, ou seja, no ponto X = 400 Y = 300. Primeiramente vamos centralizar a parte horizontal (X). Iremos subtrair o tamanho central da largura da tela na variável X, assim o valor de X iniciará em -400 e será percorrido até o valor 400.

Se tentarmos executar o código, iremos obter uma exceção, pois estaremos com valores negativos em nossa variável _x. Para isto, basta adicionar uma validação, para quando o valor de _x for menor que zero, torna-lo positivo.



13. Para obter o resultado final, vamos colocar a profundidade no centro da tela também. Já que a variável que controla a profundidade é a variável Z, vamos fazer o mesmo que fizemos com a variável X. Diminuiremos a metade da altura da tela em Z para começar na posição -300 e finalizar em 300. Podemos ver que temos que colocar uma validação também na variável _y para evitar que o valor fique abaixo de zero, causando uma exceção.



14. Finalizamos nosso Mode 7! O resultado é algo como:



Veja os outros posts para aprender como adicionar um "Fog", ou criar um movimento de rotação.

Caso você deseje acessar o código fonte, publiquei os códigos no GitHub. Segue o link abaixo:
https://github.com/vinibiavatti1/mode7

Comentários

  1. Ótimo tutorial, estava difícil encontrar um que explicasse de forma detalhada o processo, ainda mais em português. Obrigado!

    ResponderExcluir
  2. Amigo, você poderia fazer uma versão do código em C#?

    ResponderExcluir
    Respostas
    1. Eai Brendo, beleza? Eu acredito que o post detalha bem a lógica utilizada. Já que Java e C# são bem parecidos não seria tão diferente o modelo do código. Entretanto, futuramente posso disponibilizar o código em outras linguagens ;).

      Excluir
  3. Continua na atividade então Vinicius? E aí, tudo bem?

    ResponderExcluir
    Respostas
    1. Opa, continuo sim. Estou pretendendo trazer mais conteúdo ao blog :). Tudo certo, E com você?

      Excluir
  4. Tudo certo também.
    Você tem algum contato para passar?

    ResponderExcluir
    Respostas
    1. Pode utilizar meu e-mail vinicius.biavatti@gmail.com. Sempre tento me manter conectado ;)

      Excluir

Postar um comentário

Postagens mais visitadas deste blog

RayCasting

Mode 7 - Rotation