Por que as GPUs dividem o espaço do clipe Z por W, para a posição?

8

Antecedentes:
descobri que é muito fácil usar um buffer de profundidade linear, usando apenas uma ligeira modificação na transformação de vértice canônico. O método mais simples é encontrado na parte inferior de https://www.mvps.org/directx/articles/linear_z/linearz.htm .

No entanto, a ressalva é que ele funciona apenas para triângulos que não precisam ser cortados contra os planos próximo ou distante. (E uma solução alternativa, de realizar a divisão da perspectiva no sombreador de vértices, produzirá um problema semelhante para os outros quatro planos de frustum.)

Como o recorte requer interpolação linear para trabalhar em todas as quatro coordenadas do espaço do clipe, acho impossível trabalhar com profundidade linear, usando apenas um sombreador de vértice. Mas o motivo disso tudo é que Z é dividido por W.

Por que isso é feito? X e Y precisam ser divididos pela distância da câmera, mas a coordenada Z não, para se encaixar perfeitamente na caixa NDC.

Jessy
fonte

Respostas:

13

Se você estiver criando uma imagem em perspectiva e seu modelo tiver interseções implícitas, se você usar "Z linear", essas interseções aparecerão nos lugares errados.

Por exemplo, considere um plano de solo simples com uma linha de postes telefônicos, recuando para a distância, que perfuram o solo (e continuam abaixo). As interseções implícitas serão determinadas pelos valores de profundidade interpolados. Se não houver interpolação 1/Z, quando os vértices projetados forem computados com perspectiva, a imagem parecerá incorreta.

Peço desculpas pela qualidade não estética das ilustrações a seguir, mas as fiz em 97.

A primeira imagem mostra o efeito de renderização necessário. (Observe que os "postes" azuis percorrem uma longa distância sob o plano do solo e, portanto, são cortados na parte inferior das imagens)

insira a descrição da imagem aqui

Esta segunda imagem mostra o resultado do uso de um buffer de profundidade não recíproco: (Desculpas pela mudança de escala - elas foram copiadas de um documento antigo do MS Word e não faço ideia do que aconteceu com a escala).

insira a descrição da imagem aqui

Como você pode ver, os resultados estão incorretos.

Em outra nota, você tem certeza de que deseja realmente uma representação Z linear? Se você está criando uma perspectiva, certamente alguém quer mais precisão mais perto da câmera do que à distância?

Re seu comentário posterior:

"Se esses não são interpolados com 1 / Z" que eu não entendo. Que interpolação é essa?

A primeira coisa a observar é que, com uma projeção em perspectiva padrão, as retas no espaço do mundo permanecem retas no espaço da perspectiva. Distâncias / comprimentos, no entanto, não são preservados.

Para simplificar, vamos supor que uma transformação de perspectiva trivial seja usada para projetar os vértices, ou seja, Também devemos calcular uma profundidade recíproca no espaço da tela, por exemplo, mas o Z linear no buffer de profundidade exigiria algo como: (Podemos assumir aqui que escala = 1)

XScreen=XWoreudZWoreud
YScreen=YWoreudZWoreud
ZScreen=1 1ZWoreud
ZScreen=scumaeueZWoreud

Vamos supor que temos uma linha com os pontos finais do espaço mundial Com a perspectiva mapeada, esses mapas para coordenar o espaço da tela

[0 00 01 1]umand[2000 010]
[0 00 01 1]umand[200 00,1]

O sistema / hardware de renderização interpolará linearmente o espaço da tela z, portanto, no ponto 1/2 da linha, como aparece na tela, ou seja, no pixel (10, 0), obteríamos um Z (inverso) projetado 0,55, que corresponde a um valor de Z do espaço no mundo de ~ 1,818. Dados os valores Z inicial e final, isso é cerca de 20% ao longo do comprimento da linha.

Se, em vez disso, tentássemos interpolar usando os valores Z originais, acabaríamos com Z correspondente a um valor do espaço mundial de 5,5. Desde que nada se cruze, você pode ficar bem (não pensei muito nisso), mas qualquer coisa com interseções implícitas estará incorreta.

O que eu não mencionei é que, depois de introduzir a texturização correta da perspectiva (ou mesmo o sombreamento correto da perspectiva), você deve fazer uma interpolação por pixel de 1 / w e, além disso, também calcular, por pixel, o inverso desse valor interpolado.

Simon F
fonte
Acho que não vou conseguir entender essa resposta sem mais diagramas / matemática. E sim, mais precisão, mais perto, provavelmente faz sentido, mas uma escala linear far / z, que é padrão, não faz sentido. Ele produz um buffer de profundidade que se torna mais linear quanto mais próximos os dois planos de clipe estiverem um do outro. Parece uma fusão de dois conceitos: Z espaço-linear da tela e um mapeamento de buffer de profundidade não constante para um hack de desempenho.
Jessy
Especificamente, é o "se esses não são interpolados com 1 / Z" que eu não entendo. Que interpolação é essa?
Jessy
11
Vou adicionar um texto adicional para explicar, espero
Simon F
Obrigado! Penso que o problema se resume a "O sistema / hardware de renderização interpolará linearmente o espaço da tela z". Fiquei com a impressão de que a posição da NDC seria computada como (x, y, z) / wpor fragmento, mas aparentemente, em vez disso, temos que lidar com uma versão interpolada linearmente de (x/w, y/w, z/w)? Isso não me parece razoável em 2018, mas seria bom saber se esse é o truque com o qual temos que conviver por enquanto!
Jessy
Para executar a correta texturização / sombreamento / qualquer outra perspectiva, é necessário interpolar linearmente os valores (Val / w) e, em seguida, por fragmento, fazer uma divisão pelo 1 / w interpolado linearmente. É um pouco difícil de explicar apenas em um comentário, mas há uma pequena explicação em computergraphics.stackexchange.com/a/4799/209 . Como alternativa, procure o artigo de Jim Blinn "Interpolação hiperbólica"
Simon F
6

O uso de Z / W para o buffer de profundidade é mais profundo do que apenas recortar nos planos próximos e distantes. Como Simon mencionou, isso tem a ver com interpolação entre os vértices de um triângulo, durante a rasterização.

Z / W é a opção exclusiva que permite que os valores de profundidade de NDC sejam calculados corretamente para pontos no interior do triângulo, interpolando simplesmente linearmente os valores de profundidade de NDC dos vértices, no espaço da tela . Em princípio, poderíamos usar qualquer função que gostamos de mapear o espaço da câmera Z para o valor do buffer de profundidade - mas qualquer outra opção além de Z / W exigiria uma matemática mais complicada por pixel, que seria mais lenta e mais difícil de executar. construir em hardware.

Observe que se você usar um buffer de profundidade linear, é claro que os valores de profundidade interpolados linearmente estarão corretos no espaço do mundo ... mas não, em geral, no espaço da tela! E é o espaço da tela que importa para a rasterização, pois precisamos gerar valores de profundidade com perspectiva correta (e outros valores de atributo, como UVs) para cada centro de pixel ou outro ponto de amostra dentro dos limites do espaço da tela de um triângulo sendo rasterizado.

Nathan Reed
fonte
Não sei como projetar uma GPU, mas parece-me que tudo o que é necessário é interpolar Z em vez de Z / W, para profundidade linear, e a interpolação Z / W ainda pode ocorrer posteriormente para qualquer coisa visível. Ainda não sei dizer se é uma questão de bom raciocínio ou se alguém não se importa com a atualização.
Jessy
Interpolar Z em vez de Z / W não fornece resultados corretos no espaço da tela. Z / W faz.
Nathan Reed
Direita. Porém, se o buffer de profundidade é quantizado com uma precisão menor que a posição, além de ter um bom desempenho quando funciona, não é uma boa idéia armazenar um pedaço escalado do espaço da tela Z. Se a interpolação linear é tudo o que obtemos, então é necessário recorte acontecer no espaço de visualização. E Z precisa ser interpolado antes da divisão por W, para o buffer de profundidade e depois para o que você analisou. Então, é a resposta para minha pergunta: "porque as GPUs sempre interpolaram apenas no espaço do clipe, porque era a única solução prática nas primeiras GPUs e funcionou bem desde então"?
Jessy 10/10
Não estou seguindo o que você quer dizer com "quantizado com uma precisão menor que a posição" ou "armazena um pedaço em escala do espaço da tela Z".
Nathan Reed
11
Além disso, "Z precisa ser interpolado antes da divisão por W, para o buffer de profundidade" - não. É o que tenho tentado explicar. Você obtém as respostas erradas se interpolar Z (ou qualquer outra coisa) no espaço da tela sem dividi-lo por W primeiro. Você parece estar preso à idéia de que um buffer Z linear funcionaria se não dividíssemos por W. Mas não funcionará - ele não irá interpolar adequadamente no espaço da tela.
Nathan Reed