4
$\begingroup$

Recently, I am writing a simple software rasterizer for self-studying and fun. But the texture mapping has problems. The texture I want to map is below:

Texture

But the final image of two triangles is problematic, it shows below:

final image

The triangle rasterizing algorithm I use is the Triangle barycentric coordinates interpolation. It seems the mapping of second triangle is not correct. My code is below, As the code shows, the three vertices of the triangle is, p1, p2, p3.

I hope someone can help me to fix the problem. Thanks very much!

if (mRenderState & (RENDERING_TEXTURE | RENDERING_COLOR))
{
    int x0 = p1.x();
    int x1 = p2.x();
    int x2 = p3.x();
    int y0 = p1.y();
    int y1 = p2.y();
    int y2 = p3.y();

    //Firstly build the bounding box
    int xMin = std::min(x0, std::min(x1, x2));
    int xMax = std::max(x0, std::max(x1, x2));
    int yMin = std::min(y0, std::min(y1, y2));
    int yMax = std::max(y0, std::max(y1, y2));

    // Triangle setup.
    // Compute the edge equation coefficients.
    float edge_a_0 = -(y1 - y0);
    float edge_a_1 = -(y2 - y1);
    float edge_a_2 = -(y0 - y2);

    float edge_b_0 =   x1 - x0;
    float edge_b_1 =   x2 - x1;
    float edge_b_2 =   x0 - x2;

    float edge_c_0 = edge_a_0 * -x0 + edge_b_0 * -y0;
    float edge_c_1 = edge_a_1 * -x1 + edge_b_1 * -y1;
    float edge_c_2 = edge_a_2 * -x2 + edge_b_2 * -y2;

    // Triangle area and inverse area
    float area = 0.5f * ((x1 - x0) * (y2 - y0) - (y1 - y0) * (x2 - x0));
    float inv2Area = 1.f / (2.f * area);

    // Check the triangle is backfacing.
    if (area <= 0.)
        return;

    // Loop over the bounding box of the pixels that the triangle possibly
    // covers.
    int py;
    int px;
    for (int py = yMin; py < yMax; ++py)
    for (int px = xMin; px < xMax; ++px)
    {
        float e0 = edge_a_0 * px + edge_b_0 * py + edge_c_0;
        float e1 = edge_a_1 * px + edge_b_1 * py + edge_c_1;
        float e2 = edge_a_2 * px + edge_b_2 * py + edge_c_2;

        //Check the sample is outside the triangle
        if (e0 <= 0.f || e1 <= 0.f || e2 <= 0.f)
            continue;

        float wt0 = e1 * inv2Area;
        float wt1 = e2 * inv2Area;
        float wt2 = e0 * inv2Area;

        // Interpolate z
        float z = (wt0 * p1.z() + wt1 * p2.z() + wt2 * p3.z());
        float zrhw = 1.0f / z;

        if (z < mZBuffer[py*mWidth + px])
        {
            mZBuffer[py*mWidth + px] = z;

            if (mRenderState & RENDERING_COLOR)
            {
                float r = wt0 * v1->r + wt1 * v2->r + wt2 * v3->r;
                float g = wt0 * v1->g + wt1 * v2->g + wt2 * v3->g;
                float b = wt0 * v1->b + wt1 * v2->b + wt2 * v3->b;
                DrawPixel(px, py, Color(r, g, b));
            }

            if (mRenderState & RENDERING_TEXTURE)
            {
                float u = wt0 * v1->u + wt1 * v2->u + wt2 * v3->u;
                float v = wt0 * v1->v + wt1 * v2->v + wt2 * v3->v;
                unsigned int cc = TextureRead(u, v);
                unsigned char r = (cc & (0xff << 16)) >> 16;
                unsigned char g = (cc & (0xff << 8 )) >> 8;
                unsigned char b = cc & (0xff);
                Color color;
                color.setColor(r, g, b);
                DrawPixel(px, py, color);
            }
        }
    }
}
$\endgroup$
2
  • 1
    $\begingroup$ Without looking at your code I'd guess the error is perspective correction, similar to this question $\endgroup$
    – Dan Hulme
    Commented Mar 3, 2017 at 10:22
  • $\begingroup$ you are interpolating in screenspace, you should be interpolating in clipspace. $\endgroup$ Commented Mar 3, 2017 at 11:42

1 Answer 1

5
$\begingroup$

You aren't doing perspective correct texturing. At each pixel, $(X,Y)$, you need to be computing U and V with the equivalent of:

$U=\frac{aX+bY+c}{pX+qY+r}$

$V=\frac{dX+eY+f}{pX+qY+r}$

The denominator of both is linearly interpolating 1/W, while the numerators are, respectively, interpolating U/W and V/W.

I.E. for each triangle vertex you need to compute 1/W, U/W and V/W and then interpolate these. You can do it via barycentrics if you wish but you must do the division per pixel.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.