HTML5 透视网格

Posted

技术标签:

【中文标题】HTML5 透视网格【英文标题】:HTML5 Perspective Grid 【发布时间】:2013-07-21 20:55:49 【问题描述】:

我试图在我的画布上做一个透视网格,我已经从另一个网站更改了功能,结果如下:

    function keystoneAndDisplayImage(ctx, img, x, y, pixelHeight, scalingFactor) 
    var h = img.height,
            w = img.width,

            numSlices = Math.abs(pixelHeight),

            sliceHeight = h / numSlices,

            polarity = (pixelHeight > 0) ? 1 : -1,
            heightScale = Math.abs(pixelHeight) / h,

            widthScale = (1 - scalingFactor) / numSlices;

    for(var n = 0; n < numSlices; n++) 

        var sy = sliceHeight * n,
                sx = 0,
                sHeight = sliceHeight,
                sWidth = w;

        var dy = y + (sliceHeight * n * heightScale * polarity),
                dx = x + ((w * widthScale * n) / 2),
                dHeight = sliceHeight * heightScale,
                dWidth = w * (1 - (widthScale * n));

        ctx.drawImage(img, sx, sy, sWidth, sHeight,
                dx, dy, dWidth, dHeight);
    

它创建了几乎很好的透视网格,但它没有缩放高度,所以每个正方形都有相同的高度。 Here's a working jsFiddle 以及它的外观,就在画布下方。我想不出任何数学公式来扭曲与“透视距离”(顶部)成比例的高度。 我希望你明白。抱歉语言错误。

任何帮助将不胜感激

问候

【问题讨论】:

如果你想要一个透视正确的网格,那么就会涉及到很多 3D 数学。最重要的构造是Matrix。如果您不想构建自己的 3D 引擎,您可以使用现有的,例如 three.js。从this例子看源码。 我想要的画布中唯一的 3D 东西就是那个网格。如果没有严肃的 3D 数学,有没有办法做到这一点?我只需要添加一些东西来改变每行水平线之间的距离(类似的东西)。 有什么想法吗?我什么也没找到。 使用图片作为背景有什么问题? 我正在学习,我想知道如何做诸如全透视网格之类的事情。 【参考方案1】:

遗憾的是,除了使用 3D 方法之外,没有其他合适的方法。但幸运的是它并没有那么复杂。

以下将生成一个可沿 X 轴旋转的网格(如您的图片中所示),因此我们只需要关注该轴即可。

要了解发生了什么:我们在笛卡尔坐标空间中定义网格。说我们将点定义为向量而不是绝对坐标的花哨的词。也就是说,一个网格单元可以从 0,0 到 1,1 而不是例如 10,20 到 45, 45 只是为了取一些数字。

投影阶段,我们将这些笛卡尔坐标投影到我们的屏幕坐标中。

结果会是这样的:

ONLINE DEMO

好的,让我们深入研究一下 - 首先我们设置一些投影等所需的变量:

fov = 512,         /// Field of view kind of the lense, smaller values = spheric
viewDist = 22,     /// view distance, higher values = further away
w = ez.width / 2,  /// center of screen
h = ez.height / 2,
angle = -27,       /// grid angle
i, p1, p2,         /// counter and two points (corners)
grid = 10;         /// grid size in Cartesian

要调整网格,我们不调整循环(见下文),而是更改 fovviewDist 以及修改 grid 以增加或减少单元格的数量。

假设您想要一个更极端的视图 - 通过将 fov 设置为 128 并将 viewDist 设置为 5,您将使用相同的 gridangle 获得此结果:

执行所有数学运算的“魔术”函数如下:

function rotateX(x, y) 

    var rd, ca, sa, ry, rz, f;

    rd = angle * Math.PI / 180; /// convert angle into radians
    ca = Math.cos(rd);
    sa = Math.sin(rd);

    ry = y * ca;   /// convert y value as we are rotating
    rz = y * sa;   /// only around x. Z will also change

    /// Project the new coords into screen coords
    f = fov / (viewDist + rz);
    x = x * f + w;
    y = ry * f + h;

    return [x, y];

就是这样。值得一提的是,新的 Y 和 Z 的组合使顶部的线条更小(在这个角度)。

现在我们可以像这样在笛卡尔空间中创建一个网格,并将这些点直接旋转到屏幕坐标空间中:

/// create vertical lines
for(i = -grid; i <= grid; i++) 
    p1 = rotateX(i, -grid);
    p2 = rotateX(i, grid);
    ez.strokeLine(p1[0], p1[1], p2[0], p2[1]); //from easyCanvasJS, see demo


/// create horizontal lines
for(i = -grid; i <= grid; i++) 
    p1 = rotateX(-grid, i);
    p2 = rotateX(grid, i);
    ez.strokeLine(p1[0], p1[1], p2[0], p2[1]);

还要注意位置 0,0 是屏幕的中心。这就是为什么我们使用负值从左侧或上方退出的原因。可以看到两条中心线是直线。

仅此而已。要为单元格着色,您只需选择笛卡尔坐标,然后通过调用rotateX() 对其进行转换,您将获得角所需的坐标。

例如 - 随机选取一个单元格编号(X 轴和 Y 轴上的 -10 到 10 之间):

c1 = rotateX(cx, cy);         /// upper left corner
c2 = rotateX(cx + 1, cy);     /// upper right corner
c3 = rotateX(cx + 1, cy + 1); /// bottom right corner
c4 = rotateX(cx, cy + 1);     /// bottom left corner

/// draw a polygon between the points
ctx.beginPath();
ctx.moveTo(c1[0], c1[1]);
ctx.lineTo(c2[0], c2[1]);
ctx.lineTo(c3[0], c3[1]);
ctx.lineTo(c4[0], c4[1]);
ctx.closePath();

/// fill the polygon
ctx.fillStyle = 'rgb(200,0,0)';
ctx.fill();

An animated version 可以帮助了解发生了什么。

【讨论】:

EasyCanvas 很强大,我看了文档。我将使用它与信用:) 另外,一个问题:脚本通过在两侧添加单元格来创建网格,这就是它在网格中间旋转 X 的原因。有没有办法以相同的方式旋转,而不是中间,以最后一条水平线旋转?我现在正在努力实现这一目标。 @VixinG 当然可以。只需“翻译”网格,即。添加从 -20 到 0 的单元格,然后 0 将是枢轴点,或旋转的基础。如果您想在旋转后移动整个网格,只需在 rotateX() 生成的 Y 值中添加一个值。 @Ken-AbdiasSoftware 是的,我已经自己翻译了。再次感谢,祝您有美好的一天! 404 链接到 jsfiddle

以上是关于HTML5 透视网格的主要内容,如果未能解决你的问题,请参考以下文章

如何在 ag 网格透视模式下将不同的列数据显示为工具提示?

认识3d max 透视图

Mosha Pasumansky 的 XAML 数据透视表

如何刷新数据透视图

Excel数据透视表、切片器如何做?

Excel数据透视表制作 这6个技巧超好用