Perspective mappage de texture correcte; calcul de la distance z peut être erroné

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

  •  20-09-2019
  •  | 
  •  

Question

Je fais un rasterizer logiciel, et je l'ai rencontré un peu accroc. Je ne peux pas sembler obtenir la cartographie de texture en perspective correcte de travailler

Mon algorithme est d'abord trier les coordonnées pour tracer par y. Cela renvoie un plus haut, point le plus bas et le centre. Je marche puis à travers les lignes de balayage à l'aide du 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;

Et puis nous rendons de order[0]->y à order[2]->y, en augmentant la x_start et x_end par un delta. Lors du rendu la partie supérieure, sont x_delta[0] et x_delta[1] de delta. Lors du rendu la partie inférieure, sont x_delta[0] et x_delta[2] de delta. Ensuite, nous interpoler linéairement entre x_start et x_end sur notre ligne de balayage. Les coordonnées UV sont interpolés de la même manière ordonnée par y, à partir de début et de fin, à laquelle sont appliquées chaque étape de delta.

Cela fonctionne bien, sauf lorsque je tente de faire la cartographie UV correcte en perspective. L'algorithme de base est de prendre UV/z et 1/z pour chaque sommet et interpoler entre eux. Pour chaque pixel, les coordonnées UV devient UV_current * z_current. Cependant, cela est le résultat:

text alt

La partie inversée vous indique où sont retournées de delta. Comme vous pouvez le voir, les deux triangles les deux semblent aller vers différents points à l'horizon.

Voici ce que j'utilise pour calculer le Z à un point dans l'espace:

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;
}

Ai-je raison, est-ce un problème de mémoire tampon z?

Était-ce utile?

La solution

ZBuffer n'a rien à voir avec elle.

zbuffer est utile lorsque les triangles se chevauchent et que vous voulez vous assurer qu'ils sont tirés correctement (par exemple commandés correctement dans le Z). Le ZBuffer sera, pour chaque pixel du triangle, déterminer si un pixel précédemment placé est plus proche de la caméra, et si oui, pas dessiner le pixel de votre triangle.

Puisque vous dessinez 2 triangles qui ne se chevauchent pas, ce ne peut pas être la question.

Je l'ai fait un rasterizer logiciel au point fixe une fois (pour un téléphone mobile), mais je n'ai pas les sources sur mon ordinateur portable. Permettez-moi de vérifier ce soir, comme je l'ai fait. Essentiellement ce que vous avez est pas mal! Une chose comme cela pourrait être dû à une erreur très faible

Conseils généraux dans le débogage est d'avoir quelques triangles de test (pente du côté gauche, la pente du côté droit, un angle de 90 degrés, etc etc) et l'étape à travers avec le débogueur et voyez comment vos transactions logiques avec les cas.

EDIT:

peudocode de mon rastérisation (seulement U, V et Z sont pris en compte ... si vous voulez aussi vous ne Gouraud avez également tout faire pour RG et B similaire à ce que vous faites pour U et V et Z:

L'idée est que le triangle se décompose en 2 parties. La partie supérieure et la partie inférieure. La partie supérieure est de y [0] pour y [1] et la partie inférieure est de y [1] pour y [2]. Pour les deux ensembles vous devez calculer les variables étape qui vous INTERPOLATION. L'exemple ci-dessous vous montre comment faire la partie supérieure. Si nécessaire, je peux fournir la partie inférieure aussi.

S'il vous plaît noter que je ne calcule déjà les décalages d'interpolation nécessaires à la partie inférieure dans le fragment ci-dessous « pseudocode »

  • premier ordre les coords (x, y, z, u, v) dans l'ordre de sorte que Coord [0] .y
  • prochain contrôle si des 2 jeux de coordonnées sont identiques (uniquement vérifier x et y). Dans ce cas ne pas tirer
  • exception: Le triangle a un sommet plat? le cas échéant, la première pente sera infinie
  • Exception2: Le triangle a un fond plat (oui triangles peut avoir ces trop; ^)), la dernière pente trop sera infinie
  • calculer 2 pentes (côté gauche et côté droit)
    leftDeltaX = (x [1] - x [0]) / (y [1] -y [0]) et rightDeltaX = (x [2] - x [0]) / (y [2] -y [0] )
  • la deuxième partie du triangle dépend calculée: si le côté gauche du triangle est vraiment sur la Leftside (ou a besoin d'échange)

fragment de code:

 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
  }
  • définir la fois sur x currentLeftX et currentRightX [0]
  • set currentLeftU sur leftDeltaU, currentLeftV sur leftDeltaV et currentLeftZ sur leftDeltaZ
  • calc début et le point final pour la première plage de Y: startY = ceil (y [0]); endy = ceil (y [1])
  • prestep x, u, v et z pour la partie fractionnaire de y pour une précision de sous-pixel (je suppose que cela est également nécessaire pour les flotteurs) Pour mes algorithmes FixedPoint cela était nécessaire pour rendre les lignes et les textures donnent l'illusion de se déplacer dans les étapes beaucoup plus fines que la résolution de l'écran)
  • calculer où x doit être à y [1]: halfwayX = (x [2] -x [0]) * (y [1] -y [0]) / (y [2] -y [0] ) + x [0] et même pour U et V et z: halfwayU = (u [2] -u [0]) * (y [1] -y [0]) / (y [2] -y [0]) + u [0 ]
  • et en utilisant le calcul de la halfwayX pas à pas pour U et V et Z: si (halfwayX - x [1] == 0) {slopeU = 0, slopeV = 0, slopez = 0} else {slopeU = (halfwayU - U [1]) / (halfwayX - x [1])} // ( et même pour v et z)
  • n'écrêtage pour le haut Y (calcule donc où nous allons commencer à dessiner dans le cas où le sommet du triangle est hors de l'écran (ou hors du rectangle de découpage))
  • pour y = startY; y
  • est Y en bas de l'écran passé? arrêt rendu!
  • calc startX et EndX pour la première ligne horizontale leftCurX = ceil (startx); leftCurY = ceil (endy);
  • couper la ligne à tracer la frontière horizontale gauche de l'écran (ou d'une région de détourage)
  • préparer un pointeur sur le buff de destinationer (le faire à travers les indices de tableau à chaque fois est trop lent) unsigned int buf = destbuf + (y pitch) + startX; (Unsigned int en cas que vous faites 24bit ou 32 bits de rendu) préparer également votre pointeur ZBuffer ici (si vous utilisez ce)
  • for (x = startX; x
  • maintenant pour la cartographie de texture en perspective (en utilisant aucune interpolation bilineair vous procédez comme suit):

fragment de code:

         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
  • ligne fictive
    • ligne fictive
      • ligne fictive
      • option: vérifiez la zbuffer si le pixel tracé précédemment à cette coordonnée est supérieure ou rabattez nôtre
      • .
      • tracer le pixel
      • Startz + = slopez; startU + = slopeU; StarTV + = slopeV; // mettre à jour tous les interpolateurs
    • } extrémité de la boucle de x
    • leftCurX + = leftDeltaX; rightCurX + = rightDeltaX; leftCurU + = rightDeltaU; leftCurV + = rightDeltaV; leftCurZ + = rightDeltaZ; // mise à jour Y interpolateurs
  • } extrémité de la boucle de y

    // ceci est la fin de la première partie. Nous avons dessiné la moitié du triangle. à partir du haut, à la coordonnée Y du milieu. // nous faisons maintenant essentiellement la même chose, mais maintenant la moitié inférieure du triangle (en utilisant l'autre jeu d'interpolateurs)

désolé les «lignes factices .. ils ont besoin pour obtenir les codes de démarques synchronisés. (M'a pris un certain temps pour obtenir tout ce genre de recherche comme prévu)

laissez-moi savoir si cela vous aide à résoudre le problème que vous rencontrez!

Autres conseils

Je ne sais pas que je peux aider à votre question, mais l'un des meilleurs livres sur le rendu logiciel que j'avais lu au moment est disponible en ligne graphique de programmation Black Book par Michael Abrash.

Si vous INTERPOLATION 1/z, vous devez multiplier par UV/z z, non 1/z. En supposant que vous avez ceci:

UV = UV_current * z_current

et z_current est 1/z d'interpolation, vous devez le changer à:

UV = UV_current / z_current

Et alors vous voudrez peut-être renommer z_current à quelque chose comme one_over_z_current.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top