Traçando um globo pseudo 3D

Sep 06 2020

Eu gostaria de traçar um pequeno globo onde o personagem principal pode andar, exatamente como o Sonic & Knukles Bonus Stage. Para quem não quer pesquisar no Google, aqui está uma foto .

Estou familiarizado com Raycasting, usado em Wolfenstein e outros jogos para "simular" uma perspectiva 3D em um mapa 2D.

Mas eu não consegui descobrir como programar o globo, e suponho que não fosse uma renderização 3D real, já que Sonic era um jogo de 16 bits.

Alguma ideia de como fazer isso sem nenhum sofisticado mecanismo 3D?

Respostas

1 Engineer Sep 06 2020 at 15:22

Visão geral

  • Configure uma trilha 1D infinita de planos 2D 2x. Conforme você corre para frente, o avião atrás de você avança para mantê-lo funcionando; isso continua acontecendo repetidamente, quer você corra para frente ou para trás.
  • Agora faça a mesma coisa em 2D, ou seja, com planos 2D 2x2. Onde quer que você vá, o mundo continua sob seus pés.
  • Transforme os planos em uma vista em perspectiva.
  • Agora crie um efeito de protuberância esférica através da transformação do espaço da tela, ou seja, ajustando todos os pixels do solo para fazê-los parecer curvos, mesmo que seja realmente plana, uma superfície repetitiva.
  • Mesmo quando o personagem gira 90 graus em alguns quadros, isso ainda mostra o mesmo efeito de mundo curvo.

Planos 3D em 2D

Vamos supor que você tenha planos planos 2x2 renderizando na tela como quadrados (vistos de cima para baixo) e que você possa se mover neles conforme descrito acima.

Agora precisamos transformar esses planos (coletivamente), vistos de cima para baixo, em uma perspectiva oblíqua ao solo.

Isso é feito em 2 etapas:

  1. comprima o plano de solo combinado de modo que sua metade superior "aperte" a largura da janela de visualização e sua metade inferior exceda a largura da janela de visualização. Isso é feito usando yRatioo calculado na seção de código abaixo, ou seja, quanto mais perto estamos do topo, mais escalamos xpara apertar o topo do quadrado para que se pareça com um tronco ou triângulo.
  2. Reduza-o e reposicione-o em y de modo que sua parte inferior fique alinhada com a parte inferior da janela de visualização e sua parte superior esteja (digamos) no meio da tela - este é o seu horizonte.

Ambas as etapas dependem de onde o jogador está atualmente.

Curvatura

Uma fórmula de semicírculo é necessária para a transformação dos pixels, que serão deslocados ao longo da tela y para obter o efeito de protuberância. Esta parte é deixada para sua pesquisa.

semicircleDisplace(xCurrent)
{
    
    //formula to calculate maximal (horizon) yDisplacement from xCurrent
    //...
    
    return yDisplacement;
}

pixels[xCurrent][yCurrent].y += semicircleDisplace(xCurrent);

O problema com isso é que aumentamos todos os pixels tanto perto da parte inferior da tela quanto perto do topo, levando a uma espécie de U de cabeça para baixo para o terreno, quando o que realmente queremos perto da parte inferior do a tela é uma linha quase reta; no meio do caminho, algum deslocamento / protuberância; e no horizonte, deslocamento máximo. Conseguimos isso usando um fator interpolado (possivelmente linear):

semicircleDisplace(xCurrent, yCurrent)
{
    
    //formula to calculate maximal (horizon) yDisplacement from xCurrent
    //...

    //linear interpolation based on where we are between bottom of screen and horizon
    yRange  = yMax - yMin
    yRatio  = yCurrent - yMin
    yFactor = yRatio / yRange

    return yDisplacement * yFactor;

}
pixels[xCurrent][yCurrent].y += semicircleDisplace(xCurrent, yCurrent);

yFactoré um valor entre 0.0e 1.0pelo qual você multiplica yDisplacement. Se a interpolação linear (que é barata) não der uma boa aparência, você pode brincar com interpolações não lineares para obter o tipo certo de curvatura do solo. Mas meu palpite é que linear ficará bem.