Perspectiva correta de mapeamento de texturas;z distância de cálculo pode estar errado

StackOverflow https://stackoverflow.com/questions/2068134

  •  20-09-2019
  •  | 
  •  

Pergunta

Eu estou fazendo um software de quadrícula, e eu ter um pouco de dificuldade:Eu não consigo ficar de perspectiva do correto mapeamento de textura para o trabalho.

Minha algoritmo é a primeiro ordenar as coordenadas para o plano de y.Isso retorna um mais alto, mais baixo e o ponto central.Eu, em seguida, atravessar as linhas digitalizadas usando o delta:

// ordering by y is put here

order[0] = &a_Triangle.p[v_order[0]];
order[1] = &a_Triangle.p[v_order[1]];
order[2] = &a_Triangle.p[v_order[2]];

float height1, height2, height3;

height1 = (float)((int)(order[2]->y + 1) - (int)(order[0]->y));
height2 = (float)((int)(order[1]->y + 1) - (int)(order[0]->y));
height3 = (float)((int)(order[2]->y + 1) - (int)(order[1]->y));

// x 

float x_start, x_end;
float x[3];
float x_delta[3];

x_delta[0] = (order[2]->x - order[0]->x) / height1;
x_delta[1] = (order[1]->x - order[0]->x) / height2;
x_delta[2] = (order[2]->x - order[1]->x) / height3;

x[0] = order[0]->x;
x[1] = order[0]->x;
x[2] = order[1]->x;

E então nós a compor a partir de order[0]->y para order[2]->y, aumentando a x_start e x_end por um delta.Ao renderizar a parte de cima, o delta do são x_delta[0] e x_delta[1].Quando a renderização parte inferior, o delta do são x_delta[0] e x_delta[2].Então nós interpolar linearmente entre x_start e x_end em nosso scanline.Coordenadas UV são interpolados no mesmo caminho, ordenados por y, começando por begin e end, para as quais a delta são aplicadas a cada passo.

Isso funciona bem, exceto quando tento fazer uma perspectiva correta de mapeamento UV.O algoritmo básico é tomar UV/z e 1/z para cada vértice e interpolar entre eles.Para cada pixel, o UV coordenar torna-se UV_current * z_current.No entanto, este é o resultado:

alt text

A inversa parte informa onde o delta do são invertidas.Como você pode ver, os dois triângulos ambos parecem estar indo em direção a pontos diferentes do horizonte.

Aqui está o que eu uso para calcular o Z em um ponto no espaço:

float GetZToPoint(Vec3 a_Point)
{
    Vec3 projected = m_Rotation * (a_Point - m_Position);

    // #define FOV_ANGLE 60.f
    // static const float FOCAL_LENGTH = 1 / tanf(_RadToDeg(FOV_ANGLE) / 2);
    // static const float DEPTH = HALFHEIGHT * FOCAL_LENGTH; 
    float zcamera = DEPTH / projected.z;

    return zcamera;
}

Estou certo, é um z buffer problema?

Foi útil?

Solução

ZBuffer tem nada a ver com isso.

O ZBuffer só é útil quando os triângulos são sobrepostos e você quer certificar-se de que eles são desenhados corretamente (por exemplo,corretamente ordenados em Z).O ZBuffer será, para cada pixel do triângulo, determinar se colocado anteriormente pixel está mais perto da câmara, e, se assim é, não chamar o pixel de seu triângulo.

Desde que você está desenhando 2 triângulos que não se sobrepõem, este pode não ser o problema.

Eu fiz um software de quadrícula no ponto fixo de uma vez (para um telefone celular), mas eu não tenho as fontes no meu laptop.Então, deixe-me ver esta noite, como eu fiz.Em essência, o que você tem não é ruim!Uma coisa como isto pode ser causado por um pequeno erro

Dicas gerais de depuração esta é a ter algumas teste de triângulos (inclinação lateral esquerda, inclinação lateral direita, ângulos de 90 graus, etc etc) e passo por isso com o depurador e veja como a sua lógica lida com os casos.

EDITAR:

peudocode da minha quadrícula (somente U, V e Z, são levadas em conta...se você também quer fazer gouraud você também tem que fazer de tudo para que o R G e B semelhantes, como o que você está fazendo para U e V e Z:

A idéia é que um triângulo pode ser dividida em 2 partes.A parte superior e a parte inferior.A parte superior é de y[0] y[1] e a parte inferior é de y[1] y[2].Para ambos os conjuntos, você precisa calcular o passo de variáveis com as quais você está interpolação.O exemplo abaixo mostra como fazer a parte de cima.Se necessário posso fornecer a parte de baixo também.

Por favor note que eu já calcular o necessário interpolação de deslocamentos para a parte inferior abaixo 'pseudocódigo' fragmento

  • primeira ordem, as coordenadas(x,y,z,u,v) em ordem, de modo que coord[0].y < coord[1].y < coord[2].y
  • próximo verifique se 2 conjuntos de coordenadas são idênticos (de verificação só de x e y).Se assim não chamar a
  • exceção:o triângulo tem um plano superior?se assim for, a primeira inclinação será infinito
  • exception2:faz o triângulo de ter um fundo plano (sim triângulos pode ter estes também;^) ), em seguida, a última inclinação também será infinito
  • calcular 2 pistas (lado esquerdo e lado direito)
    leftDeltaX = (x[1] - x[0]) / (y[1]-y[0]) e rightDeltaX = (x[2] x[0]) / (y[2]-y[0])
  • a segunda parte do triângulo é calculada dependente:se o lado esquerdo do triângulo é agora realmente no leftside (ou necessidades troca)

fragmento de código:

 if (leftDeltaX < rightDeltaX)
 {
      leftDeltaX2 = (x[2]-x[1]) / (y[2]-y[1])
      rightDeltaX2 = rightDeltaX
      leftDeltaU = (u[1]-u[0]) / (y[1]-y[0]) //for texture mapping
      leftDeltaU2 = (u[2]-u[1]) / (y[2]-y[1])
      leftDeltaV = (v[1]-v[0]) / (y[1]-y[0]) //for texture mapping
      leftDeltaV2 = (v[2]-v[1]) / (y[2]-y[1])
      leftDeltaZ = (z[1]-z[0]) / (y[1]-y[0]) //for texture mapping
      leftDeltaZ2 = (z[2]-z[1]) / (y[2]-y[1])
 }
 else
 {
      swap(leftDeltaX, rightDeltaX);
      leftDeltaX2 = leftDeltaX;
      rightDeltaX2 = (x[2]-x[1]) / (y[2]-y[1])
      leftDeltaU = (u[2]-u[0]) / (y[2]-y[0]) //for texture mapping
      leftDeltaU2 = leftDeltaU
      leftDeltaV = (v[2]-v[0]) / (y[2]-y[0]) //for texture mapping
      leftDeltaV2 = leftDeltaV
      leftDeltaZ = (z[2]-z[0]) / (y[2]-y[0]) //for texture mapping
      leftDeltaZ2 = leftDeltaZ
  }
  • definir o currentLeftX e currentRightX tanto no x[0]
  • conjunto currentLeftU no leftDeltaU, currentLeftV no leftDeltaV e currentLeftZ no leftDeltaZ
  • calc início e o ponto final para o primeiro intervalo de Y:startY = ceil(y[0]);endY = ceil(y[1])
  • prestep x,u,v e z para a parte fracionária de y para subpixel precisão (eu acho que isso também é necessário para floats) Para o meu fixedpoint algoritmos isso foi necessário para fazer as linhas e texturas dão a ilusão de movimento em muito mais etapas, em seguida, a resolução do display)
  • calcular onde x deve estar em y[1]:halfwayX = (x[2] x[0]) * (y[1]-y[0]) / (y[2]-y[0]) + x[0] e mesmo para U e V e z:halfwayU = (u[2]-u[0]) * (y[1]-y[0]) / (y[2]-y[0]) + u[0]
  • e usando o halfwayX calcular o deslizante para a U e a V e z:se(halfwayX - x[1] == 0){ slopeU=0, slopeV=0, slopeZ=0 } else { slopeU = (halfwayU - U[1]) / (halfwayX - x[1])} //(e mesmo para v e z)
  • fazer recorte para Y, cima (para calcular onde vamos começar a desenhar no caso, a parte superior do triângulo é fora da tela (ou fora do rectângulo de recorte))
  • para y=startY;y < endY;y++) {
    • é Y passado inferior da tela?parar de renderização!
    • calc startX e endX para a primeira linha horizontal leftCurX = ceil(startx);leftCurY = ceil(endy);
    • clip a linha a ser desenhada para a esquerda borda horizontal do ecrã (ou região de recorte)
    • preparar um ponteiro para o buffer de destino (a fazê-lo através de índices de array, sempre é muito lento) unsigned int buf = destbuf + (ypitch) + startX;(unsigned int no caso de você está fazendo 24 bits ou 32 bits de processamento) também preparar o seu ZBuffer ponteiro aqui (se você estiver usando este)
    • for(x=startX;x < endX;x++) {
      • agora para a perspectiva de mapeamento de texturas (sem usar bilineair interpolação você faça o seguinte):

fragmento de código:

         float tv = startV / startZ
         float tu = startU / startZ;
         tv %= texturePitch;  //make sure the texture coordinates stay on the texture if they are too wide/high
         tu %= texturePitch;  //I'm assuming square textures here. With fixed point you could have used &=
         unsigned int *textPtr = textureBuf+tu + (tv*texturePitch);   //in case of fixedpoints one could have shifted the tv. Now we have to multiply everytime. 
         int destColTm = *(textPtr);  //this is the color (if we only use texture mapping)  we'll be needing for the pixel
  • linha fictícia
    • linha fictícia
      • linha fictícia
      • opcional:verifique o zbuffer se previamente desenhados pixel nas coordenadas é maior ou menor do que a nossa.
      • enredo do pixel
      • startZ += slopeZ;startU+=slopeU;startV += slopeV;//atualização de todos os interpolators
    • } fim do x ciclo
    • leftCurX+= leftDeltaX;rightCurX += rightDeltaX;leftCurU+= rightDeltaU;leftCurV += rightDeltaV;leftCurZ += rightDeltaZ;//update Y interpolators
  • } fim de y loop

    //este é o final da primeira parte.Agora temos desenhado metade do triângulo.a partir do topo, do meio coordenada Y.// agora, nós, basicamente, fazer exatamente a mesma coisa, mas agora com a metade inferior do triângulo (usando o conjunto de interpolators)

desculpem o 'fictício linhas'..eles eram necessários para obter o markdown códigos em sincronia.(levei um tempo para começar tudo de classificação fora olhando como se pretende)

deixe-me saber se isso ajuda a resolver o problema que você está enfrentando!

Outras dicas

Não sei se posso ajudar com sua pergunta, mas um dos melhores livros sobre renderização de software que eu li no momento está disponível online Livro preto de programação de gráficos Por Michael Abrash.

Se você está interpolando 1/z, você precisa se multiplicar UV/z por z, não 1/z. Supondo que você tenha isso:

UV = UV_current * z_current

e z_current está interpolando 1/z, você deve mudar para:

UV = UV_current / z_current

E então você pode querer renomear z_current para algo como one_over_z_current.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top