问题在于您使用的转换不会将直线映射到直线。相反,直线通常会走向抛物线。您可以在示例图像中看到,2D 视图中从上到下或多或少笔直的主干道在 2.5D 视图中转换为弯曲的道路。如果您将示例中“疯狂”的行分成更短的段,您会看到同样的情况。
从数学上讲,您可以通过返回到您正在使用的转换来了解发生了什么:
x_ = (x - w/2)*(t1+(y/h)*(t2-t1)) + w/2
y_ = y
如果我们将一条直线表示为x = ay+b
,然后一个点(ay+b,y)
这条线上映射到(ay+b - w/2)*(t1+(y/h)*(t2-t1)) + w/2,y)
。这个表达式看起来很复杂,但你可以看到它的计算结果类似于(c*y^2+d*y+e,y)
,对于合适的值c,d,e
,这是一条抛物线。
所以你最好的选择是放弃这种转换并切换到透视变换.
在您最初的问题中,您提到渲染图像的非仿射变换太慢。看来您现在已经切换到在渲染线条之前转换线条,而且速度足够快。您现在唯一要做的就是更改变换。
这是建议的转换。这需要几个步骤,并将 2D (x,y) 坐标转换为 2.5D (u,v) 坐标。我假设您使用的是 C#。
t = 0.3 // tilt angle - try different values
X = x - w/2 ;
Y = y - h/2 ;
a = h/(h + Y*Math.Sin(t)) ;
u = a*X + w/2 ;
v = a*Y*Math.Cos(t) + h/2 ;
有一个参数t
这里定义倾斜量,以弧度表示。我建议使用 0.3 左右的值(正负)。
我已经用铅笔和纸解决了这个问题,但没有运行它,所以如果这不起作用,请告诉我......总是有可能存在转录错误。
Update:您希望避免绘制任何具有点的实体(线、多边形等)(x,y)
这样a
是非正数。更好的是,为了避免溢出,您应该避免在以下情况下绘制a<epsilon
, where epsilon
是一些小的正值,例如 0.05 或 0.1。