ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

javascript – HTML5透视网格

2019-07-16 13:37:14  阅读:151  来源: 互联网

标签:javascript html5 math canvas


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

    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方法之外,遗憾的是没有正确的方法.但幸运的是,它并没有那么复杂.

下面将生成一个可以通过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

要调整网格,我们不调整循环(见下文),但改变fov和viewDist以及修改网格以增加或减少单元格数.

让我们说你想要一个更极端的视图 – 通过将fov设置为128并将viewDist设置为5,您将使用相同的网格和角度获得此结果:

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

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可以帮助看看发生了什么.

标签:javascript,html5,math,canvas
来源: https://codeday.me/bug/20190716/1478623.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有