【问题标题】:undistorted texture coordinates未扭曲的纹理坐标
【发布时间】:2011-03-17 21:20:06
【问题描述】:

如何计算平面上点的 UV 坐标?

我有一个多边形 - 3 个或 4 个或更多点 - 在一个平面上 - 也就是说,所有点都在一个平面上。但它可以在空间中的任何角度。

这个多边形的一侧 - 两个点 - 将被映射到纹理中的两个对应的 2D 点 - 我提前知道这两个点。我也知道纹理的 x 和 y 比例,并且没有点落在纹理范围或其他“边缘情况”之外。

这是最上面的纹理四边形扭曲的图像:

我用黄色勾勒出了一个坏的四边形。想象一下,我知道那个四边形上两个最底角的 UV 坐标,并且想要计算其他两个点的正确 UV 坐标...

如何计算平面中所有其他点相对于这两点的 UV 坐标?

想象我的纹理是现实生活中的一张纸,我想为你的(平的)车门制作纹理。我在我的纸上放了两个点,我把它和你车门上的两个点对齐。如何计算车门上其他位置在纸下的位置?

你可以使用三边测量吗?对于 2D 空间中的两个已知点,伪代码会是什么样子?


使用brainjam的代码成功:

def set_texture(self,texture,a_ofs,a,b):
    self.texture = texture
    self.colour = (1,1,1)
    self.texture_coords = tx = []
    A, B = self.m[a_ofs:a_ofs+2]
    for P in self.m:
        if P == A:
            tx.append(a)
        elif P == B:
            tx.append(b)
        else:
            scale = P.distance(A)/B.distance(A)
            theta = (P-A).dot((B-A)/(P.distance(A)*B.distance(A)))
            theta = math.acos(theta)
            x, y = b[0]-a[0], b[1]-a[1]
            x, y = x*math.cos(theta) - y*math.sin(theta), \
                x*math.sin(theta) + y*math.cos(theta)
            x, y = a[0]+ x*scale, a[1]+ y*scale
            tx.append((x,y))

【问题讨论】:

    标签: 3d texture-mapping trilateration


    【解决方案1】:

    你必须用两个选定的向量和一个原点来表达其他点。

    我会做这样的事情:

    选择 3 个 3D 点和对应的 UV 点:

    • A(x,y,z,u,v)
    • B(x,y,z,u,v)
    • C(x,y,z,u,v)

    然后使用 x,y,z 坐标,我们想将给定的 3D 点 D 表示为:

    D = A + alpha ( B - A ) + beta ( C - A ) + gamma ( B - A ) X ( C - A )

    我们有 x,y,z 的 3 个方程,X 是叉积,而 alpha,beta,gamma 是未知的。 我们希望它在 uv 和 xyz 之间创建线性关系。

    计算 W = ( B - A ) X ( C - A ),我们需要解决:

    Dx - Ax = alpha.(Bx-Ax) + beta.(Cx-Ax) + gamma.Wx

    Dy - Ay = alpha.(By-Ay) + beta.(Cy-Ay) + gamma.Wy

    Dz - Az = alpha.(Bz-Az) + beta.(Cz-Az) + gamma.Wz

    this method计算矩阵M的逆矩阵:

           | (Bx-Ax) , Cx-Ax , Wx | 
       M = | (By-Ay) , Cy-Ay , Wy | 
           | (Bz-Az) , Cz-Az , Wz | 
    

    我们称结果矩阵为 N,注意它不依赖于 D。

    然后计算 D 的 alpha,beta,gamma :

    (alpha,beta,gamma) = N.(D-A)

    然后计算 D 的 u,v :

    Du = Au + alpha( Bu - Au ) + beta( Cu - Au )

    Dv = Av + alpha( Bv - Av ) + beta( Cv - Av )

    不使用伽玛,因为它是 D 和 (A,B,C) 3D 平面之间的距离。

    【讨论】:

    • 非常有前途,谢谢!什么是 alpha beta 和 gamma?它在 c 或 python 伪代码中看起来如何,所以我可以掌握你的意思?
    • alpha、beta、gamma 是实数系数,它们表示 D-A 在由 3 个向量 B-A、C-A 和 (B-A)X(C-A) 形成的基础上的分解。这是一个基础变化,但不是正交的。
    【解决方案2】:

    以逆时针顺序标记 3D 多边形的顶点,从已知 UV 坐标的两个顶点开始。将这些标签称为 ABCD。 UV空间中对应顶点的标签分别为abcd,其中 ab 是已知的。

    你说的问题是,对于原始多边形中的一点P,要确定对应的UV坐标p。 (相信你只关心计算点CD的UV坐标cd,但 P 的一般解决方案是相同的。)

    首先,计算P-AB-A之间的夹角θ。使用归一化向量的dot product 和 acos 很容易做到这一点。

    α = (P-A)⋅(B-A)/(|P-A||B-A|)

    θ = acos(α)

    我们还计算长度的比率:

    σ = |P-A|/|B-A|

    现在要在 UV 空间中计算 p,我们只需将矢量 b-a 旋转角度 θ(保持 a 固定)并按 σ 缩放.

    Rmatrix for a rotation by angle θ,成为

    | +cos(θ) -sin(θ) |
    | +sin(θ) +cos(θ) |

    那么 p = a + σR(b-a)。

    你已经完成了。

    【讨论】:

    • @brainjam 这确实很有希望,但我无法尝试将其转换为我的 python 以使其正常工作;我已经用细节更新了这个问题,希望它是我代码中的一个明显错误?
    • @Will,尝试将x, y = a[0]-b[0], a[1]-b[1] 替换为x, y = b[0]-a[0], b[1]-a[1]
    • 谢谢,是的;我想我最初在转录时就有了,我想我昨晚在沮丧地发布我的代码时忘记了由于疲劳而尝试的所有随机更改!它不再以错误的方式旋转,而是涂抹,好像它在 Y 轴上没有变化一样。我更新了问题附录中的图片。
    • @Will,是的,看起来 Y 坐标都一样。你不喜欢图形调试吗?此时最好的办法可能是打印循环中每一行的结果并查看正在计算的内容。然后还打印self.mtx 的值。如果我能看到所有内容,我可以检查它的正确性。您可以在此处发布,也可以随意查找我的电子邮件地址并将其发送到那里。
    • P(-0.39432,0.37187,0.23580)(1.283621949056725C-17,1.2096313728906054)P(-0.39432,0.29261,0.39432)(0.0,1.0)(0.0,1.0)(0.45113,0.29261,0.39432) (1.0, 1.0) (B) P(0.45113,0.37187,0.23580) (0.99999999999999989, 1.2096313728906052)
    【解决方案3】:

    U 和 V 是 0 到 1 之间的数字。

    因此,假设在您的情况下,较大边的大小为 10,较小的边为 5,每个“间隙”为 2.5。然后将其标准化,为您提供所需的数字。

    所以一些示例伪代码:

    bottomLeftVector(0,0,0)
    bottomLeftTexture(0,0)
    topLeftVector(2.5, 5, 0)
    topLeftTexture(0.25, 0)
    topRightVector(7.5, 5, 0)
    topRightTexture(0, 0.75)
    bottomRightVector(10, 0, 0)
    bottomRightTexture(1,1)
    

    希望这会有所帮助!

    【讨论】:

    • 你已经在 2D 中完成了。每个纹理演示都从在具有漂亮方形边的立方体上涂抹纹理开始。问题是计算一堆 3D 点所在平面上的 2D 坐标。
    • 好吧,如果使用 2D 纹理,这也是同样的一般问题。需要从 3D 形状中找到导致问题的两点之间的距离,然后放入 2D 纹理中。这就是我自己解决同样问题的方法。
    • 那么你是如何从 3D 点到平面上对应的 2D 点的呢?
    • 如果您的对象是圆形的,则不需要考虑 3D 点。这是因为您将 2D 纹理映射到它。因此,只需将要渲染纹理的面视为 2D 形状即可。这使工作更容易弄清楚。
    • 或另一种说法是,如果纹理将 2D 纹理映射到 3D 对象,则映射每个面,而不是每个顶点。
    猜你喜欢
    • 1970-01-01
    • 2021-11-08
    • 2020-06-11
    • 1970-01-01
    • 2011-10-21
    • 1970-01-01
    • 2021-03-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多