Eu tenho que escrever meu próprio software rasterizer 3d, e até agora eu sou capaz de projetar meu modelo 3d feito de triângulos no espaço 2D:
Giro, traduzo e projeto meus pontos para obter uma representação espacial em 2D de cada triângulo. Então, pego os 3 pontos do triângulo e implemento o algoritmo da linha de varredura (usando interpolação linear) para encontrar todos os pontos [x] [y] ao longo das bordas (esquerda e direita) dos triângulos, para que eu possa varrer o triângulo horizontalmente, linha por linha e preencha com pixels.
Isso funciona. Exceto que eu também tenho que implementar o z-buffering. Isso significa que, conhecendo as coordenadas z giradas e traduzidas dos 3 vértices do triângulo, devo interpolar a coordenada z para todos os outros pontos que encontro com o algoritmo da linha de varredura.
O conceito parece claro o suficiente, primeiro encontro Za e Zb com estes cálculos:
var Z_Slope = (bottom_point_z - top_point_z) / (bottom_point_y - top_point_y);
var Za = top_point_z + ((current_point_y - top_point_y) * Z_Slope);
Então, para cada Zp, faço a mesma interpolação horizontalmente:
var Z_Slope = (right_z - left_z) / (right_x - left_x);
var Zp = left_z + ((current_point_x - left_x) * Z_Slope);
E se z atual estiver mais próximo do visualizador do que o z anterior nesse índice, ENTÃO escreva a cor no buffer de cores E escreva o novo z no buffer de z. (meu sistema de coordenadas é x: esquerda -> direita; y: superior -> inferior; z: seu rosto -> tela do computador;)
O problema é que isso dá errado. O projeto está aqui e, se você selecionar o botão de opção "Z-Buffered", verá os resultados ... ( observe que eu uso o algoritmo do pintor (apenas para desenhar o wireframe) no modo "Z-Buffered" para fins de depuração )
PS: Eu li aqui que você deve transformar os z em seus recíprocos (significado z = 1/z
) antes de interpolar. Eu tentei isso, e parece que não há mudanças. o que estou perdendo? (alguém poderia esclarecer, precisamente onde você deve transformar z em 1 / z e onde (se) para transformá-lo de volta?)
[EDIT] Aqui estão alguns dados sobre quais valores z máximo e mínimo eu recebo:
max z: 1; min z: -1; //<-- obvious, original z of the vertices of the triangles
max z: 7.197753398761272; min z: 3.791703256899924; //<-- z of the points that were drawn to screen (you know, after rotation, translation), by the scanline with zbuffer, gotten with interpolation but not 1/z.
max z: 0.2649908532179404; min z: 0.13849507306889008;//<-- same as above except I interpolated 1/z instead of z.
//yes, I am aware that changing z to 1/z means flipping the comparison in the zBuffer check. otherwise nothing gets drawn.
Antes de entrar em uma depuração cuidadosa, alguém pode confirmar que meu conceito até agora está correto?
[EDIT2]
Eu resolvi o buffer z. Acontece que a ordem do desenho não foi alterada. As coordenadas z estavam sendo calculadas corretamente.
O problema era que, na tentativa de aumentar minha taxa de quadros, eu estava desenhando caixas 4px / 4px, a cada 4 pixels, em vez de pixels reais na tela. Então, eu estava desenhando 16px por pixel, mas verificando o buffer z para apenas um deles. Eu sou uma besteira.
TL / DR: A questão ainda permanece: Como / por que / quando você precisa usar o recíproco de Z (como em 1 / z) em vez de Z? Porque agora, tudo funciona de qualquer maneira. (não há diferença perceptível).