ssloy/tinyrenderer

Problem about texture mapping

a42027756 opened this issue · 6 comments

So I tried to accomplish the texture mapping job at the end of Lesson 3, and when I interpolated the uv values, got the color, I get this:
image
Well, it looks similar to the one in Lesson 3, but slightly different.. This guy's face is not so flat(or smooth?) as the guy in Lesson 3
I want to know if this is a serious problem that if I don't fix it now, it will affect Lessons afterwards and if it is, how can I fix it?
Here's my code:
`void rst::triangle_texture(Vec3f pts[3], Vec2f uvs[3], Vec3f norms[3], float* zbuffer, TGAImage& image, TGAImage& texture, const int& width, float intensity) {
//bounding box
int minx = min(pts[0].x, min(pts[1].x, pts[2].x));
int maxx = max(pts[0].x, max(pts[1].x, pts[2].x));
int miny = min(pts[0].y, min(pts[1].y, pts[2].y));
int maxy = max(pts[0].y, max(pts[1].y, pts[2].y));

    for (int i = minx; i <= maxx; ++i) {
        for (int j = miny; j <= maxy; ++j) {
            Vec3f P(i, j, 0);
            Vec2f T(0, 0);
            Vec3f N(0, 0, 0);
            Vec3f coord = barycentric(pts, P); //returns coord[] containing barycentric coordinates
            int w = texture.get_width();
            int h = texture.get_height();
            //optimization for small black holes (REALLY DISGUSTING)
            if (coord.x < -.01 || coord.y < -.01 || coord.z < -.01) continue;
            //interpolation
            for (int i = 0; i < 3; i++) {
                P.z += pts[i].z * coord[i];
                T.x += uvs[i].x * coord[i];
                //cout << "uv.x : " << T.x << endl;
                T.y += uvs[i].y * coord[i];
                //cout << "uv.y : " << T.y << endl;
                /*N.x += norms[i].x * coord[i];
                N.y += norms[i].y * coord[i];
                N.z += norms[i].z * coord[i];*/


            }

            //Texture Sampling
            //w *= T.x;
            w = (int)(w * T.x);
            //cout << "width of the texture: " << w << endl;
            h = (int)(h * T.y);
            //h *= T.y;
            //cout << "height of the texture: " << h << endl;
            TGAColor color = texture.get(w, h);
            

            //z-buffering
            if (zbuffer[int(P.x + P.y * width)] < P.z) {
                zbuffer[int(P.x + P.y * width)] = P.z;
                image.set(P.x, P.y, TGAColor(color.r * intensity, color.g * intensity, color.b * intensity));
            }`

Please let me know if any other code/information is needed.

ssloy commented

it seems that you need to permute your barycentric coordinates, like in this example:

https://github.com/ssloy/tinyrenderer/wiki/Visual-troubleshooting#texturing

it seems that you need to permute your barycentric coordinates, like in this example:

https://github.com/ssloy/tinyrenderer/wiki/Visual-troubleshooting#texturing

Hey, big thanks to you for your reply, but I still don't know understand how this works... I am confused by several problems:

  1. What does "circular permutation" mean?
  2. I guess I do have a problem in uv-interpolation. And how is "circular permutation" going to fix that?
    this is how I interpolate uvs for now:
Vec3f coord = barycentric(pts, P);  //to get barycentric coords
for (int i = 0; i < 3; ++i) {
      P.z += pts[i].z * coord[i];  //to interpolate z
      T.x += uvs[i].x * coord[i];  //to interpolate uv.x
      T.y += uvs[i].y * coord[i];  //to interpolate uv.y
}             

Is it that I should not interpolate uvs the way I interpolate z coords?
3. I have run some tests on my barycentric calculations by setting the three vertices in each triangle red, green and blue, and then interpolate the colors. The result looks like this:
image
Should this indicate that my barycentric interpolation is doing fine?

It would be a great help if I get your reply again!

I think circular permutation means your barycentric coord transforms like this: <a, b, c> -> <b,c,a> -> <c,a,b>.
There exists some correct permutation order that fixes your problem.

Here is my pic for my barycentric coords. You can see the color position is different. I am also using r, g, b orders for my barycentric coords
download (6)
.

From what I can see, the green and blue positions should be switched. which means you should change your barycentric order a,b,c to a,c,b. R is mapped to a, G is mapped to b, and B is mapped to c. I think you should figure out this problem now. Technically this is not a circular permutation? But another random permutation.

From what I can see, the green and blue positions should be switched. which means you should change your barycentric order a,b,c to a,c,b. R is mapped to a, G is mapped to b, and B is mapped to c. I think you should figure out this problem now. Technically this is not a circular permutation? But another random permutation.

Thank you so much!!! This is exactly where the problem is! By switching the mapping of G and B, it perfectly solves the problem. Never thought that the order of barycentric coordinates would affect anything.
What I did is indeed not a "circular permutation", but changing the order from like(a, b, c) to (a, c, b), which in this case, switched the mapping of Green/Blue color. Hope this can help others who are being through similar situations.
Again, thank you for helping me solve this puzzle that bothered me for a long long time!

ssloy commented

Thank you @XiaofanLinUS , did not find time to answer properly.