扭曲网格中的坐标

时间:2010-05-31 08:01:55

标签: flash actionscript-3 graphics geometry matrix

我在2D系统中有一个网格,就像前一个图像中的一个网格,其中给出了所有点A,B,C,D,A',B',C',D'(意思是我知道相应的x-和y坐标)。

当网格失真时,我需要计算A(新),B(新),C(新)和D(新)的x坐标和y坐标(以便A'移动到A'( new),B'移到B'(新),C'移到C'(新),D'移到D'(新))。

失真以网格线被分成相等长度的子线的方式发生(意味着例如AB被分成相等长度的5个部分| AB | / 5和A(新的) )B(新)被分为等长的5个部分| A(新)B(新)| / 5)。

失真是使用Sandy 3D Flash engine的DistortImage类完成的。 (我的实际任务是使用此类扭曲图像,其中手柄不位于图像的角落like in this demo,而是位于图像的某个角落)。

alt text http://www.gefragt.de/distorted_grid.png

7 个答案:

答案 0 :(得分:3)

我不能给你完整的答案,但我很确定你会在Paul S. Heckbert的“纹理映射基础和图像变形”中找到它:http://www.cs.cmu.edu/~ph/texfund/texfund.pdf(在附录中它包含了源代码各种映射的代码)

答案 1 :(得分:2)

这看起来像是对我的线性转换。我们知道这一点,因为原始图形中的任何一条线也是变换图形中的一条线(对于您给出的演示,这并不总是如此,但如果您按照您在问题中给出的指示而不允许凹顶点,则为真) 。我相信AS3内置了对变换矩阵操作的支持。如果没有,您可以自己实施。

[ x' ]  =   [ a b ] x [ x ]
[ y' ]      [ c d ]   [ y ]

这些是矩阵。第一个是向量(你的最终点),它等于某个2x2矩阵乘以向量(你的原始点)

如果你不熟悉矩阵乘法,可以简化为:

x' = a*x + b*y
y' = c*x + b*y

任何线性变换都可以用a,b,c和d的二乘二矩阵表示。为每个选择数字,然后进行线性变换。那么如何找到能给你的a,b,c和d的值呢?

对于四个未知数,你需要四个方程。如果你看一下上面的等式,你会看到一个点(“向量”)及其变换将给你两个方程式。所以......我们需要两点。正如您稍后将看到的,选择未变换形式(m,0)和(0,n)中的点(即沿着x轴的一个,沿y轴的另一个)是有用的。

在您的示例中,这些很容易找到!它们是B和D(如果A或C是你的起源)!

我将使用一些不同的符号:“素数”用于转换版本的点。

B => B'
B_x => B'_x
B_y => B'_y

如果你知道B和D的前后坐标,你可以找到你的变换矩阵a,b,c,d。

设置方程式:

B'_x = a * B_x + b * B_y
B'_y = c * B_x + d * B_y

D'_x = a * D_x + b * D_y
D'_y = c * D_x + d * D_y

现在,假设B是你的x轴点,形式为(B_x,0)。假设D是你的y轴点,形式为(0,D_y)。如果相反,请切换它们。在这里,我们假设您的原点是A =(0,0),就像大多数Flash应用程序一样。

设置B_y = 0和D_x = 0,我们得到:

B'_x = a * B_x + b * 0
B'_y = c * B_x + d * 0
D'_x = a * 0   + b * D_y
D'_y = c * 0   + d * D_y

使用代数的力量,我们发现:

a = B'_x / B_x
c = B'_y / B_x
b = D'_x / D_y
d = D'_y / D_y

因此,简而言之:

如果您知道原始点:(原始x和y轴上的顶点)

M = (M_x, 0)
N = (0  , N_x)

及其变形/扭曲点

M' = (M'_x, M'_y)
N' = (N'_x, N'_y)

(因此M => M'且N => N')

然后计算并存储这四个变量:

a = M'_x / M_x
b = N'_x / N_y
c = M'_y / M_x
d = N'_y / N_y

最后:

(x, y)  =>  ( a*x + b*y , c*x + d*y )

编辑:好的,我完成了一些你的任意角落处理转换,并意识到当我认为你的转换是线性的时候我会跳到结论。上述等式在两种情况下只是线性的:

  1. 您的新网格是某些旋转parallelogram的形状(原来是正方形,'正常'网格)
  2. 您的(0,0)原点的位置不会改变。
  3. 现在,我不确定您允许手柄定位的自由度,但也许您可以限制它们,以便您的网格空间始终遵循旋转的平行四边形的形式。

答案 2 :(得分:1)

设(u,v)表示“纹理”坐标。无论网格扭曲如何,您的手柄都保持相同的纹理坐标。

因此,在纹理空间中,A =(0,0)B =(1,0)C =(1,1)D =(0,1)A'=(au,av)B'=(bu ,bv)...

我们可以从纹理空间转换为像素空间。

P(u,v)= A *(1-u)(1-v)+ B u *(1-v)+ C u v + d *(1-u)的* v

(u,v是纹理坐标,A,B,C,D指像素坐标)

因此,如果你的句柄A'被定义为具有纹理坐标(.35,.15),那么像素空间中A'的位置由P(。35,。15)给出。

现在,假设用户拖动句柄A'。我们需要解决A. B,C,D的新位置保持固定。这只是简单的代数。

A' = A*(1-au)*(1-av) + B*au*(1-av) + C*au*av + D*(1-au)*av
A' - B*au*(1-av) - C*au*av - D*(1-au)*av = A*(1-au)*(1-av)
A = (A' - B*au*(1-av) - C*au*av - D*(1-au)*av) / ((1-au)*(1-av))

还不错。相同的过程获取其他句柄的公式。这是我的C#代码。当任何8个“拇指”被拖动时,它会被调用:

     double au = .35, av = .15; // texture coordinates of A'
     double bu = .8, bv = .2;   // texture coordinates of B'
     double cu = .8, cv = .6;   // texture coordinates of C'
     double du = .2, dv = .9;   // texture coordinates of D'

     // if we're dragging A' (AA), then move A, etc.
     if (sender == ThumbAA) A = (AA - B*au*(1-av) - C*au*av - D*(1-au)*av) / ((1-au)*(1-av));
     if (sender == ThumbBB) B = (BB - A*(1-bu)*(1-bv) - C*bu*bv - D*(1-bu)*bv) / (bu*(1-bv));
     if (sender == ThumbCC) C = (CC - A*(1-cu)*(1-cv) - B*cu*(1-cv) - D*(1-cu)*cv) / (cu*cv);
     if (sender == ThumbDD) D = (DD - A*(1-du)*(1-dv) - B*du*(1-dv) - C*du*dv) / ((1-du)*dv);

     // update position of A', B', C', D'   
     AA = A*(1-au)*(1-av) + B*au*(1-av) + C*au*av + D*(1-au)*av;
     BB = A*(1-bu)*(1-bv) + B*bu*(1-bv) + C*bu*bv + D*(1-bu)*bv;
     CC = A*(1-cu)*(1-cv) + B*cu*(1-cv) + C*cu*cv + D*(1-cu)*cv;
     DD = A*(1-du)*(1-dv) + B*du*(1-dv) + C*du*dv + D*(1-du)*dv;

我的演示应用的视频: http://screencast.com/t/NDU2ZWRj

这并不能回答您关于同时重新定位4个句柄的确切问题。那是你真正想要的吗?另外,如果您的手柄的纹理坐标没有预先确定,请告诉我。您可以从像素转换为纹理坐标,但它更复杂。

答案 3 :(得分:0)

你确定你想要进入所有这些处理手柄吗?在示例中,手柄用作动画片段上的参考点以进行绘制,它们与图像或扭曲无关。如果你想在图像中只有处理程序,那么你只需要偏移点计算值(例如topRightCorner = new Point(pointb.x +10, point.y - 10)

如果您真的想要计算精确点,那么您可以尝试从处理程序调用{​​{1}}来计算它的位置(以及因此应用于它的转换)。否则你将不得不处理转换矩阵,并确切地计算出类如何计算它的三角形。

有关转换基质的非常好的指南,请参见此处:senoular.com

祝你好运

答案 4 :(得分:0)

您是否需要从算法角度(转换等)获得帮助,或者您是否正在寻求有关如何使用Sandy 3D闪存引擎实现转换的帮助?

答案 5 :(得分:0)

你可能想出一些东西,但我怀疑你或你的用户会喜欢这个结果。

要了解原因,请选择图像内部的一个点。假设你想稍微向上移动它。您可以通过移动四个角中的任何一个来完成此操作(在演示中尝试)。这意味着如果你想把手柄放在那里并将其向上移动,那么四个角落会以某种组合方式移动。很可能角落不会做你想要的。例如,它们中的所有四个都可以向上移动相同的量,从而产生纯粹的平移并且没有扭曲。或者一个角落可以移动,但也许不是你期望的那个角落。有无穷无尽的解决方案,很可能你选择的解决方案不是你(或其他人)期待的解决方案。

顺便说一下,演示中使用的失真方法是“双线性插值”。在拐角处设置把手可能是控制它的最佳方式。

答案 6 :(得分:0)

你说的是2D系统,但是你所应用的失真是3D失真(当然,虽然预测为2d) - 这是故意的吗?

一般来说,我不确定在没有关于透视投影的更多信息而不仅仅是ABCD的新位置的情况下计算A'new的新位置。毕竟,透视投影会夸大附近的距离并压缩远处的距离 - 它的作用程度取决于与焦点的距离(等效于FOV)。

在任何情况下,最简单的方法是首先重新使用为投影计算的任何内容 - 如果你能得到原始的变换矩阵和透视变换,你可以直接将它们应用到A'B'和D'也是。