Essa é uma resposta longa, mas, na verdade, a premissa básica de dividir por câmera-z é muito simples: quanto mais algo estiver longe de você, menor será a aparência. Além disso, as distâncias menores entre duas coisas aparecem.
Posições (leitura obrigatória se você estiver usando o Unity!)
Em primeiro lugar, você precisa renderizar posições / pontos usando a perspectiva correta.
As posições estão em um plano plano. Você deseja algo como a imagem à direita ... considere os cantos dos ladrilhos como pontos / posições de amostra.
Veja como você aborda a transformação de pontos:
- Seu sistema de coordenadas é o seguinte: o positivo
z
é executado na tela, enquanto x
é executado da esquerda para a direita e y
é interrompido. A câmera z é o mundo z. Esse é o atalho que torna isso muito mais fácil do que escrever um mecanismo 3D completo. Desvantagem? A câmera não pode alterar a orientação (embora possa mudar de posição).
- Armazene a posição 3D inicial da sua câmera. Coloque um pouco de volta (menos
z
) da origem mundial.
- Armazene uma coleção de pontos 3D no plano xz (forneça-os
y=0
). Tente centrar-los em toda a origem mundo x
, (0,0,0)
ou seja, de negativa n
para positiva n
. Isso é para centralizá-los na viewport, quando a renderização começar.
- Considere a origem decrescente do ponto / plotagem de pixels como o centro da tela.
- Decida a distância da câmera em que 1 unidade espacial mundial = 1 pixel. Isso significa que, se você mover a câmera para apenas 1 unidade espacial mundial, qualquer objeto a 10 unidades de distância mudaria em apenas 1 pixel - muito longe! Armazene essa distância como uma constante
K
.
Agora, para cada ponto, renderize em uma posição usando a seguinte fórmula: screenPosition(x,y) = screenOrigin + (worldPosition(x,y) - cameraPosition(x,y)) / ((worldPosition(z) - cameraPosition(z)) * K)
... como você pode ver, baseamos a posição de renderização na z
distância-entre o ponto atual e a câmera.
Brinque com a posição z da câmera até ver os pontos sendo renderizados. Mas o que você verá é que todos os pontos serão exibidos na linha central da tela. Então, precisamos remediar isso. Tente K=1
vs. K=10
para ver a diferença.
Agora você pode mover a câmera y
para ver como ela fica acima e abaixo do plano de pontos (ou seja, os pontos serão renderizados, com perspectiva correta, abaixo ou acima da linha média da tela, respectivamente, conforme você move a câmera para cima e para baixo )
Essas são diretrizes muito grosseiras. Existem vários detalhes de implementação que dependem de você. O primeiro passo é apenas mostrar algo e depois alterar a partir daí. Um detalhe que vem à mente é que, se você deseja que a câmera pareça mais como se estivesse olhando para o chão, precisará mudar sua origem de renderização para cima, mais perto do topo da janela de visualização. Outro detalhe é que sua distância entre a câmera e o ponto pode precisar incluir uma taxa de trigonometria ... Eu acho que usartan
oferece uma perspectiva mais realista. Não se lembre claramente disso, mas você verá rapidamente se a perspectiva parece estranha e pode se adaptar de acordo. Não posso ser mais específico sem reescrever uma amostra.
Deformação e dimensionamento por outdoor (obrigatório)
Agora que você pode ver a perspectiva entre o seu conjunto de posições de pontos e pode adicionar, remover ou mover (como nos caracteres) as posições à vontade, também é necessário aplicar a perspectiva aos sprites individuais que serão enraizados nessas posições.
No D2, sempre me pareceu uma função simples de distorção lateral que é aplicada mais aos outdoors que estão na parte inferior da tela do que àqueles na parte superior da tela, e também mais à medida que você se afasta da linha média que desce. a tela.
Também pode haver alguma escala vertical aplicada aos outdoors, por exemplo. as árvores diminuem em comparação com a escala esperada, mais perto da parte inferior da tela (para fazer parecer que a câmera está olhando para as árvores - achei as árvores de Tristram a melhor maneira de explorar isso com segurança, de volta ao dia ;) ).
O que eu faria é:
- Enfrente a função de escala básica com base na distância da câmera ao chão em diferentes pontos. Portanto, você teria uma escala semelhante para cada linha de verificação.
- Somente depois de fazer isso, eu olhava para a dobra lateral - primeiro com base na distância da linha média que descia pela tela.
- Por fim, investigaria como essa distorção lateral é afetada pela distância abaixo da tela (e tenho a sensação de que uma simples razão trigonométrica estaria no centro disso).
Lado a lado com perspectiva correta (leitura desnecessária se você estiver usando o Unity!)
Espera-se que o item acima dê a você sprites de "stand up" corretamente posicionados e deformados (ou seja, objetos perpendiculares ao plano do solo, como personagens, árvores, casas).
No entanto, você também precisa considerar como fazer com que os ladrilhos do solo sejam deformados corretamente e sem problemas. E acho que você descobrirá que é a parte que, em particular, exigia uma GPU no D2. Lembro que em sistemas sem GPU, a opção de perspectiva foi desativada. A razão para isso quase certamente seria que a GPU pode pegar uma superfície de textura e aplicar a correção de perspectiva muito rapidamente, sem falhas entre os blocos e sem preocupações com a realização de transformações não afins no código do aplicativo, o que envolve alguma matemática matricial e pode ser um pouco caro:
Tenho algumas sugestões para você lidar com isso:
- (Unidade) Use uma câmera Unity para fornecer a renderização do plano de chão plano e texturizado, e lide com as distorções do outdoor separadamente com base nas posições do espaço na tela.
- Faça essa lógica (ou mesmo todas processam lógica) nos shaders da GPU.
- Não use peças de terra. Em vez disso, use apenas sprites pontuais - como os próprios personagens - em um plano de cor uniforme (por exemplo, verde para grama) para fornecer detalhes para que o plano não pareça monótono. Isso aumentará seus custos de renderização, mas certamente é a maneira mais fácil de resolver esse problema.