Perspectiva asignación correcta textura; cálculo de la distancia z podría estar equivocado

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

  •  20-09-2019
  •  | 
  •  

Pregunta

Estoy haciendo una impresora de trama de software, y me he topado con un poco de un inconveniente:. Me parece que no puede obtener la asignación de texturas perspectiva correcta para trabajar

Mi algoritmo es para ordenar primero las coordenadas para trazar por y. Esto devuelve una más alta, punto más bajo y el centro. entonces camino a través de las líneas de exploración usando el delta de:

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

Y luego que prestamos desde order[0]->y a order[2]->y, el aumento de la x_start y x_end por un delta. Cuando se representa la parte superior, del delta son x_delta[0] y x_delta[1]. Cuando se representa la parte inferior, del delta son x_delta[0] y x_delta[2]. Luego linealmente interpolar entre x_start y x_end en nuestra línea de escaneo. coordenadas UV se interpolan de la misma forma, ordenado por y, a partir de inicio y fin, a la que el delta del se aplican cada paso.

Esto funciona bien, excepto cuando intento hacer mapeado UV correcta perspectiva. El algoritmo básico es tomar UV/z y 1/z para cada vértice e interpolar entre ellos. Para cada píxel, la coordenada UV se convierte en UV_current * z_current. Sin embargo, este es el resultado:

text alt

La parte Inversed le dice a donde el delta de se voltean. Como se puede ver, los dos triángulos ambos parecen ir hacia diferentes puntos en el horizonte.

Esto es lo que utilizo para calcular la Z en un punto en el espacio:

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

Estoy en lo cierto, ¿es un problema de memoria intermedia z?

¿Fue útil?

Solución

ZBuffer no tiene nada que ver con ello.

ZBuffer sólo es útil cuando triángulos se superponen y que desea asegurarse de que se dibujan correctamente (por ejemplo correctamente ordenados en el Z). El ZBuffer será, para cada píxel del triángulo, determinar si un pixel previamente colocada está más cerca de la cámara, y si es así, no dibujar el píxel de su triángulo.

Desde que está dibujando 2 triángulos que no se solapan, esto no puede ser el problema.

He hecho una impresora de trama de software de punto fijo una vez (para un teléfono móvil), pero no tienen las fuentes en mi portátil. Así que me permiten comprobar esta noche, cómo lo hice. En esencia lo que tienes no es malo! Una cosa como esta podría ser causado por un error muy pequeño

Consejos generales de depuración de esto es tener unos triángulos de prueba (pendiente lateral izquierdo, la pendiente del lado derecho, ángulos de 90 grados, etc, etc) y el paso a través de él con el depurador y ver cómo sus ofertas de lógica con los casos.

EDIT:

peudocode de mi impresora de trama (sólo U, V y Z se toman en cuenta ... si también queremos hacer GOURAUD también hay que hacer todo por RG y B similar a lo que está haciendo para U y V y Z:

La idea es que un triángulo se puede dividir en 2 partes. La parte superior y la parte inferior. La parte superior es de y [0] para y [1] y la parte inferior es de y [1] para y [2]. Para ambos conjuntos es necesario calcular las variables de paso con el que está interpolación. El siguiente ejemplo muestra cómo hacer la parte superior. Si es necesario puedo suministrar la parte inferior también.

Tenga en cuenta que yo ya calcular las compensaciones necesarias para la interpolación de la parte inferior en el fragmento a continuación 'pseudo'

  • primer orden las coordenadas (x, y, z, u, v) en el orden de manera que coord [0] .y
  • siguiente verificación si cualquiera de los 2 conjuntos de coordenadas son idénticos (sólo comprobar x y y). Si es así no dibujar
  • excepción: hace el triángulo tiene una parte superior plana? si es así, la primera pendiente será infinito
  • exception2: ¿El triángulo tiene un fondo plano (sí triángulos puede tener estos también; ^)), entonces la última cuesta demasiado será infinito
  • 2 calcular las pendientes (lado izquierdo y lado derecho)
    leftDeltaX = (x [1] - x [0]) / (y [1] -y [0]) y rightDeltaX = (x [2] - x [0]) / (y [2] -y [0] )
  • la segunda parte del triángulo se calcula depende: si el lado izquierdo del triángulo es ahora realmente en el lado izquierdo (o las necesidades del intercambio)

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
  }
  • establecer el currentLeftX y currentRightX tanto en x [0]
  • set currentLeftU en leftDeltaU, currentLeftV en leftDeltaV y currentLeftZ en leftDeltaZ
  • calc iniciar y punto final para primera gama Y: starty = ceil (y [0]); EndY = ceil (y [1])
  • prestep x, u, v y z para la parte fraccionaria de y para la precisión subpixel (supongo que esto también es necesario para flotadores) Para mis algoritmos FixedPoint esto era necesario para que las líneas y texturas dan la ilusión de moverse en pasos mucho más finos entonces la resolución de la pantalla)
  • calcular donde x debe ser de al y [1]: halfwayX = (x [2] -x [0]) * (y [1] -y [0]) / (y [2] -y [0] ) + x [0] y lo mismo para U y V y z: halfwayU = (u [2] -u [0]) * (y [1] -y [0]) / (y [2] -y [0]) + u [0 ]
  • y utilizando el halfwayX calcular el paso a paso para la U y V y z: si (halfwayX - x [1] == 0) {slopeU = 0, slopeV = 0, slopez = 0} else {slopeU = (halfwayU - U [1]) / (halfwayX - x [1])} // ( y lo mismo para v y z)
  • recortes por la parte superior Y (por lo que calculamos dónde vamos a empezar a dibujar en caso de que la parte superior del triángulo está fuera de la pantalla (dentro o fuera del área de recorte))
  • para y = starty; y
  • Y es inferior más allá de la pantalla? detener el procesamiento!
  • calc startX y EndX para la primera línea horizontal leftCurX = ceil (startx); leftCurY = ceil (endy);
  • clip de la línea que se puede sacar a la frontera horizontal izquierda de la pantalla (o región de recorte)
  • preparar un puntero a la piel de ante de destinoer (hacerlo a través de los índices de matriz cada vez que es demasiado lento) unsigned int buf = destbuf + (y pitch) + startX; (Unsigned int en caso de que lo están haciendo de 24 bits o 32 bits renderizado) También preparar el puntero ZBuffer aquí (si está usando este)
  • para (x = startX; x
  • ahora para mapeo perspectiva textura (sin interpolación usando bilineair hace lo siguiente):

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
  • línea ficticia
    • línea ficticia
      • línea ficticia
      • opcional: compruebe la ZBuffer si el píxel representados previamente en esta coordenada es superior o inferior a continuación, nuestro
      • .
      • solar del píxel
      • Startz + = slopez; startU + = slopeU; StarTV + = slopeV; // actualizar todos los interpoladores
    • } final de x bucle
    • leftCurX + = leftDeltaX; rightCurX + = rightDeltaX; leftCurU + = rightDeltaU; leftCurV + = rightDeltaV; leftCurZ + = rightDeltaZ; // interpoladores actualización y
  • } final de y bucle

    // esto es el final de la primera parte. Ahora hemos dibujado la mitad del triángulo. desde la parte superior, a la Y medio de coordenadas. // ahora, básicamente, hacemos exactamente lo mismo, pero ahora para la mitad inferior del triángulo (usando el otro juego de interpoladores)

lo de las 'líneas ficticias' .. se necesitaban para obtener los códigos de reducción del precio en sincronía. (Me tomó un tiempo para conseguir todo tipo de mirar como se pretende)

quiero saber si esto ayuda a resolver el problema que se enfrentan!

Otros consejos

No sé que puedo ayudarle con su pregunta, pero uno de los mejores libros sobre la representación del software que había leído en el momento está disponible en línea Gráficos Programación libro Negro por Michael Abrash.

Si está interpolación 1/z, es necesario multiplicar por UV/z z, no 1/z. Asumiendo que tiene esto:

UV = UV_current * z_current

y se z_current interpolación 1/z, se debe cambiar a:

UV = UV_current / z_current

Y entonces puede que desee cambiar el nombre a algo así como z_current one_over_z_current.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top