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

<p>$U=\frac{aX+bY+c}{pX+qY+r}$</p>

<p>$V=\frac{dX+eY+f}{pX+qY+r}$</p>

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

<p>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.</p>

CC BY-SA 3.0
2017-03-03T12:25:02.800Z
2017-03-03T14:08:30.720Z
2017-03-03T14:08:30.720Z
Simon F
<p>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:</p>

<p><a href="https://i.sstatic.net/8xj8w.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/8xj8w.png" alt="Texture"></a> </p>

<p>But the final image of two triangles is problematic, it shows below:</p>

<p><a href="https://i.sstatic.net/lqNhi.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/lqNhi.png" alt="final image"></a></p>

<p>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.</p>

<p>I hope someone can help me to fix the problem. Thanks very much!</p>

<pre><code>if (mRenderState &amp; (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 &lt;= 0.)
        return;

    // Loop over the bounding box of the pixels that the triangle possibly
    // covers.
    int py;
    int px;
    for (int py = yMin; py &lt; yMax; ++py)
    for (int px = xMin; px &lt; 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 &lt;= 0.f || e1 &lt;= 0.f || e2 &lt;= 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 &lt; mZBuffer[py*mWidth + px])
        {
            mZBuffer[py*mWidth + px] = z;

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

            if (mRenderState &amp; RENDERING_TEXTURE)
            {
                float u = wt0 * v1-&gt;u + wt1 * v2-&gt;u + wt2 * v3-&gt;u;
                float v = wt0 * v1-&gt;v + wt1 * v2-&gt;v + wt2 * v3-&gt;v;
                unsigned int cc = TextureRead(u, v);
                unsigned char r = (cc &amp; (0xff &lt;&lt; 16)) &gt;&gt; 16;
                unsigned char g = (cc &amp; (0xff &lt;&lt; 8 )) &gt;&gt; 8;
                unsigned char b = cc &amp; (0xff);
                Color color;
                color.setColor(r, g, b);
                DrawPixel(px, py, color);
            }
        }
    }
}
</code></pre>

CC BY-SA 3.0
2017-03-03T10:22:11.410Z
Without looking at your code I'd guess the error is perspective correction, similar to [this question](http://computergraphics.stackexchange.com/questions/4079/perspective-correct-texture-mapping?rq=1)
Dan Hulme
CC BY-SA 3.0
2017-03-03T11:42:49.877Z
you are interpolating in screenspace, you should be interpolating in clipspace.
ratchet freak
<texture>
What happened to my texture mapping?
alexunder
# What happened to my texture mapping?

(Asked by: username_0 on 2017-03-03)

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](https://i.sstatic.net/8xj8w.png)](https://i.sstatic.net/8xj8w.png)

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

[![final image](https://i.sstatic.net/lqNhi.png)](https://i.sstatic.net/lqNhi.png)

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

```

**Tags:** texture

> **Comments:**
> **username_1**: Without looking at your code I'd guess the error is perspective correction, similar to [this question](http://computergraphics.stackexchange.com/questions/4079/perspective-correct-texture-mapping?rq=1)  
> **username_2**: you are interpolating in screenspace, you should be interpolating in clipspace.  

---

## 1 answers

### Answer by username_3 on 2017-03-03. Score: 5

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.


---

