如何进行UV坐标插值?

5
我正在尝试给我的.md2模型应用纹理。我使用了Gouraud着色来着色它(底部/顶部平面三角形的标准算法),我必须使用类似的代码来处理纹理坐标U和V。但我不太明白如何插值它们。从我尝试过的结果来看,我的代码似乎只在边缘之间插值,而不是在它们之间插值。我错过了什么吗? 谢谢。 enter image description here 这里颜色由u作为红色,v作为绿色和255作为蓝色形成(只针对底部平面三角形): enter image description here
 void Rasteriser::TfillBottomFlatTriangle(Vertex vertex1, Vertex vertex2, Vertex vertex3, COLORREF c1, COLORREF c2, COLORREF c3, HDC hdc)
    {
        float slope1 = (vertex2.GetX() - vertex1.GetX()) / (vertex2.GetY() - vertex1.GetY());
        float slope2 = (vertex3.GetX() - vertex1.GetX()) / (vertex3.GetY() - vertex1.GetY());

    //U and V
    float slope1U = (vertex2.GetU() - vertex1.GetU()) / (vertex2.GetY() - vertex1.GetY());
    float slope2U = (vertex3.GetU() - vertex1.GetU()) / (vertex3.GetY() - vertex1.GetY());

    float slope1V = (vertex2.GetV() - vertex1.GetV()) / (vertex2.GetY() - vertex1.GetY());
    float slope2V = (vertex3.GetV() - vertex1.GetV()) / (vertex3.GetY() - vertex1.GetY());

    float x1 = vertex1.GetX();
    float x2 = vertex1.GetX() + 0.5f;

    //U and V
    float x1U = vertex1.GetU();
    float x2U = x1U;

    float x1V = vertex1.GetV();
    float x2V = x1V;


    if (slope2 < slope1)
    {
        float slopeTmp = slope1;
        slope1 = slope2;
        slope2 = slopeTmp;

        float slopeTmpU = slope1U;
        slope1U = slope2U;
        slope2U = slopeTmpU;

        float slopeTmpV = slope1V;
        slope1V = slope2V;
        slope2V = slopeTmpV;

    }

    for (float scanlineY = vertex1.GetY(); scanlineY <= vertex2.GetY(); scanlineY++)
    {
        /* loop over each pixel of horizontal line */

        for (float xPos = ceil(x1); xPos < x2; xPos++)
        {

                float t = (xPos - x1) / (x2 - x1);
                float u = (1 - t) * x1U + t * x2U;
                float v = (1 - t) * x1V + t * x2V;
                COLORREF colour = _model.GetTexture().GetTextureValue((int)u, (int)v);
                SetPixel(hdc, (int)xPos, (int)scanlineY, colour);

        }
        // get new x-coordinate of endpoints of horizontal line 
        x1 += slope1;
        x2 += slope2;
        x1U += slope1U;
        x2U += slope2U;
        x1V += slope1V;
        x2V += slope2V;
    }

}

在任何渲染问题中,发布一个图像通常比仅有文本描述更有帮助。由于您正在谈论渲染 .md2 模型,我假设这些顶点是 3D 场景的投影顶点?我假设您现在不关心透视正确插值?输入顶点是否按某种特定顺序排序? - Michael Kenzel
@MichaelKenzel 我更新了我的帖子并加上了一张图片。首先,我只想应用纹理,然后再考虑透视校正是否有时间。顶点按升序排列。 - Monica Hotea
1
尝试将uv作为颜色输出,而不是采样。生成的图像将给您一个生成的想法。 - 3Dave
1
是的,我明白。关键是要将生成的UV视为颜色来查看。这是一种诊断技术,已经使用了几十年。 - 3Dave
@iliar 是的,我能看到。 - 3Dave
显示剩余3条评论
1个回答

0

问题出在这里:

    //U and V
    float x1U = vertex1.GetU();
    float x2U = vertex1.GetU() + 0.5f;

    float x1V = vertex1.GetV();
    float x2V = vertex1.GetV() + 0.5f;

0.5 对于 UV 坐标来说太大了,这说明它是错误的。

我认为正确的方式应该是:

    //U and V
    float x1U = vertex1.GetU();
    float x2U = x1U;

    float x1V = vertex1.GetV();
    float x2V = x1V;

快速的合理性测试:对于初始的y,我们有x1U = Vertex1.ux2U = Vertex1.u。对于最终的y,我们有x1U = Vertex2.ux2U = Vertex3.u,我是对的吗?

我认为发生的事情是每个三角形包含了你的纹理的一半,我认为我们可以在图片中看到它。

编辑: 我用Python实现了同样的算法,并得到了预期的结果:

import numpy as np

p = np.array([[0,0],
              [-5,10],
              [10,10]],dtype=np.float)

uv = np.array([[0.1,0.6],
               [0.2,0.5],
               [0.3,0.4]])

slope = (p[[1,2],0] - p[0,0])/(p[[1,2],1] - p[0,1])

slope_uv = (uv[[1,2],:] - uv[0,:])/(p[[1,2],1] - p[0,1]).reshape(-1,1)

x1 = p[0,0]
x2 = p[0,0] + 0.5

uv1 = uv[0,:]
uv2 = np.copy(uv1)

result = []

for scanY in range(int(p[0,1]),int(p[1,1])):
    for x in range(int(np.ceil(x1)),int(x2)):
        t = (x-x1)/(x2-x1)
        u = (1-t) * uv1 + t * uv2
        result.append((x,scanY,u[0],u[1]))
    x1 += slope[0]
    x2 += slope[1]
    uv1 += slope_uv[0,:]
    uv2 += slope_uv[1,:]

#%%
R = np.array(result,dtype=float)
from matplotlib import pyplot as plt

plt.figure()
plt.subplot(2,1,1)
plt.scatter(R[:,0],R[:,1],c = R[:,2])
plt.title('u')
plt.colorbar()
plt.subplot(2,1,2)
plt.scatter(R[:,0],R[:,1],c = R[:,3])
plt.title('v')
plt.colorbar()

得到以下结果:

enter image description here

我猜你的问题是顶点的uv值不正确。
此外,我在你的代码中看到以下行:
                COLORREF colour = _model.GetTexture().GetTextureValue((int)u, (int)v);

这一点并没有太多道理,因为 u,v 通常在 0 到 1 之间。我认为你可能需要在调用 GetTextureValue 之前将其除以纹理的大小,或者乘以纹理的大小或其他什么东西。


我改变了x2U和x2V的值,但结果仍然相同... - Monica Hotea
@MonicaHotea 作为一种调试措施,请将计算出的UV输出为颜色。例如,红色=U,蓝色=V。然后将生成的图像添加到您的问题中。 - iliar
我添加了照片,红色= u,绿色= v,蓝色= 255。 - Monica Hotea
@MonicaHotea 请查看“EDIT:”后面的内容。 - iliar
所以你的意思是算法是正确的,非常感谢你的努力。我按照教程获取了UV值,所以说实话,我不知道我是否做对了。 - Monica Hotea
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接