# texture in perspective by vertices not interpolation

I am writing a software renderer with allegro5, but without using its own triangle drawing functions, I use the al_draw_prim function to draw the triangles but with all the z coordinates at zero, the problem I have is precisely with the textures that are not visible In perspective, I have looked for a lot of information about it and I know that I have to take into account the z or w coordinate of the projection matrix in some way, but I can't make it work, this is my drawing function to draw the triangles:

It works this way:

1. the function receives a matrix with the result of the multiplication of all the matrices, whether rotation or translation, and multiplies them by the projection matrix.
2. then I multiply this 4x4 matrix by all the vertices of the triangle
3. I order the triangles with the furthest one first in the array and the closest one last.
4. I painted the triangle with al_draw_prim from allegro5 and all the z coordinates at zero.

If you look at my cube, you'll see the wrong perspective of the texture.

Note: I have to multiply the texture coordinates by the width and height since the Allegro 5 function only accepts pixels.

void drawTrianglePerspective(typeFace *caras, int lenCaras, typeMatrix &m1, int modo, ALLEGRO_BITMAP *imagen, float fov, float nearFov,float anchoPantalla,float altoPantalla) {
typeVertex nv;
float escala = 0;
float x = 0;
float y = 0;
float z = 0;
float u = 0;
float v = 0;
float anchoImagen = (imagen!=NULL)? al_get_bitmap_width(imagen) : 0;
float altoImagen = (imagen!=NULL)? al_get_bitmap_height(imagen) : 0;

typeMatrix proyeccion;
matrixProjection(proyeccion,nearFov,fov,100.0f,anchoPantalla,altoPantalla);

typeMatrix P;
addMatrix(proyeccion,m1,P); // multiply two matrices, the projection matrix and the result of the rotations, translations, etc. and save the result in P

dcaras Tri[lenCaras]; // triangle

for(int i = 0; i < lenCaras; i++ ) {

Tri[i].vert[0] = { .x = 0, .y = 0, .z = 0, .u = 0, .v = 0 };
Tri[i].vert[1] = { .x = 0, .y = 0, .z = 0, .u = 0, .v = 0 };
Tri[i].vert[2] = { .x = 0, .y = 0, .z = 0, .u = 0, .v = 0 };

matrixToVector(P, *caras[i].v0 ,nv);

//escala = fov / ( nearFov + nv.z );
x = (nv.x+1.0f) * 0.5f * anchoPantalla;//nv.x * escala + anchoPantalla / 2;
y = (nv.y+1.0f) * 0.5f * altoPantalla;//nv.y * escala + altoPantalla / 2;
Tri[i].vert[0].x = x;
Tri[i].vert[0].y = y;
Tri[i].z[0] = nv.z; // to paint the triangle in order of depth
Tri[i].vert[0].u = (*caras[i].v0).u*anchoImagen;
Tri[i].vert[0].v = (*caras[i].v0).v*altoImagen;
Tri[i].vert[0].color = al_map_rgba_f((*caras[i].v0).r, (*caras[i].v0).g, (*caras[i].v0).b, (*caras[i].v0).a);

matrixToVector(P, *caras[i].v1 ,nv);

//escala = fov / ( nearFov + nv.z );
x = (nv.x+1.0f) * 0.5f * anchoPantalla;//nv.x * escala + anchoPantalla / 2;
y = (nv.y+1.0f) * 0.5f * altoPantalla;//nv.y * escala + altoPantalla / 2;
Tri[i].vert[1].x = x;
Tri[i].vert[1].y = y;
Tri[i].z[1] = nv.z; // to paint the triangle in order of depth
Tri[i].vert[1].u = (*caras[i].v1).u*anchoImagen;
Tri[i].vert[1].v = (*caras[i].v1).v*altoImagen;
Tri[i].vert[1].color = al_map_rgba_f((*caras[i].v1).r, (*caras[i].v1).g, (*caras[i].v1).b, (*caras[i].v1).a);

matrixToVector(P, *caras[i].v2 ,nv);

//escala = fov / ( nearFov + nv.z );
x = (nv.x+1.0f) * 0.5f * anchoPantalla;//nv.x * escala + anchoPantalla / 2;
y = (nv.y+1.0f) * 0.5f * altoPantalla;//nv.y * escala + altoPantalla / 2;
Tri[i].vert[2].x = x;
Tri[i].vert[2].y = y;
Tri[i].z[2] = nv.z; // to paint the triangle in order of depth
Tri[i].vert[2].u = (*caras[i].v2).u*anchoImagen;
Tri[i].vert[2].v = (*caras[i].v2).v*altoImagen;
Tri[i].vert[2].color = al_map_rgba_f((*caras[i].v2).r, (*caras[i].v2).g, (*caras[i].v2).b, (*caras[i].v2).a);

}

// arranges the triangles in the array in order, the furthest one is painted first and the nearest one last
ZOrden(Tri,lenCaras);

// paint the triangle with allegro 5 with al_draw_prim the z coordinate is ignored
for(int i = 0; i < lenCaras; i++ ) {
al_draw_prim(Tri[i].vert, NULL, imagen, 0, 3, ALLEGRO_PRIM_TRIANGLE_STRIP);
al_draw_prim(Tri[i].vert, NULL, NULL, 0, 3, ALLEGRO_PRIM_LINE_LOOP);
}
}

• You're using affine texture mapping, which does not account for the nonlinearity induced by the depth divide in a perspective projection. Check out past Q&A on perspective-correct texturing to see how to fix this. Apr 2 at 2:38
• Hello, thanks for your comment, but the problem with those solutions is that they are designed for a custom triangle drawing algorithm, but I use allegro to draw the triangle so I can only adjust the texture by the UV of the triangle vertices. and not per pixel Apr 2 at 10:24
• You'll need to remove the perspective projection and z-flattening steps from your code and instead provide the perspective transformation to Allegro, so it can both transform the vertices and apply perspective-correct interpolation. Without access to this depth information, it won't be able to adjust the texturing correctly. Apr 2 at 11:31
• I had also tried passing the Z coordinate to the allegro function, but the cube was not displayed, I handle all the vertices manually with math, rotation, translation, etc, but when multiplying the vertices by the matrix containing all the rotation, translation transformations , projection, etc. There was simply nothing shown on the screen, I thought it was because I was behind the camera but no, when I set the z coordinate of the vertices to zero it does work, the idea of what I do is to control the vertices with mathematics Apr 2 at 12:40
• , I try From learning software to render well with math, I know I could pass the z coordinate to allegro and try to control the vertices with math but it doesn't work and I'm using 4x4 matrices that are supposed to be for 3D transformations Apr 2 at 12:40