命中测试伪 3d 空间

发布于 2024-09-27 04:46:06 字数 992 浏览 2 评论 0原文

所以我正在为 html5 中的 canvas 元素编写一个小型伪 3d 引擎。在下面的代码中,我绘制了一堆位置和旋转不同的正方形(绕 z 轴旋转,因此没有变形)

现在我希望能够知道用户单击了哪个正方形。在对象数组中,项目由 z 位置支持,从距相机最远的方块开始(以便它们正确绘制)。那么,给定一个相对于画布左上角的 3d 点,我怎样才能知道哪个方块被点击了呢?

//Draw objects
for (var i = 0; i < objects.length; i++) {
    var object = objects[i];
    var cz = object.position.z - camera.position.z;

    if (cz > 0) {
        cz = 1 / ((cz - 1) * 0.75 + 1);

        context.save();

        context.translate(halfWidth, halfHeight); //viewport transform
        context.scale(1, -1); //invert y axis
        context.scale(cz, cz); //perspective
        context.translate(-camera.position.x, -camera.position.y); //camera transform
        context.translate(object.position.x, object.position.y); //world transform
        context.rotate(object.rotation);

        context.fillStyle = object.color;
        context.fillRect(-40, -40, 80, 80);

        context.restore();
    }
}

PS如果我做了任何奇怪或倒退的事情,而你知道改进的方法,我很乐意听到建议

So I am writing a little mini pseudo 3d engine for the canvas element in html5. In the code below I am drawing a bunch of squares with varying positions and rotations (rotation around the z axis, so no deformation)

Now I want to be able to tell which square the user clicks on. In the objects array the items are supported by the z position starting with the squares the furthest away from the camera (so that they draw properly). So given a 3d point relative to the top left of the corner of the canvas how can I tell which square was clicked?

//Draw objects
for (var i = 0; i < objects.length; i++) {
    var object = objects[i];
    var cz = object.position.z - camera.position.z;

    if (cz > 0) {
        cz = 1 / ((cz - 1) * 0.75 + 1);

        context.save();

        context.translate(halfWidth, halfHeight); //viewport transform
        context.scale(1, -1); //invert y axis
        context.scale(cz, cz); //perspective
        context.translate(-camera.position.x, -camera.position.y); //camera transform
        context.translate(object.position.x, object.position.y); //world transform
        context.rotate(object.rotation);

        context.fillStyle = object.color;
        context.fillRect(-40, -40, 80, 80);

        context.restore();
    }
}

P.S. If I am doing anything weird or backwards and you know of a way to improve, I would love to hear suggestions

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

魔法少女 2024-10-04 04:46:06

我建议您将具有相同转换的对象绘制到相同大小的隐藏画布上,但为每个方块赋予唯一的颜色(可能源自索引i)。

您可以这样做:

var col = index.toString(16);                 // convert to hex
while (col.length < 6) col = "0"+col;     // pad leading 0s
ctx.fillStyle = "#"+col;
ctx.fillRect(-40,-40,80,80);

然后,当您在可见画布上收到鼠标单击事件时,查看隐藏画布中的该位置以获取所选对象的颜色(索引):

var colData = ctx.getImageData(clickX, clickY, 1, 1).data;
var index = (colData[2]<<16) | (colData[1]<<8) | colData[0];

这将适用于最多 16M 对象,并且相当不错简单的。

I would suggest that you draw the objects with the same transformations to a hidden canvas of the same size, but give each square a unique color (maybe derived from the index i).

You would do that like this:

var col = index.toString(16);                 // convert to hex
while (col.length < 6) col = "0"+col;     // pad leading 0s
ctx.fillStyle = "#"+col;
ctx.fillRect(-40,-40,80,80);

Then when you get a mouseclick event on the visible canvas, look at that location in your hidden one to get the color (index) of the selected object:

var colData = ctx.getImageData(clickX, clickY, 1, 1).data;
var index = (colData[2]<<16) | (colData[1]<<8) | colData[0];

This will work for up to 16M objects and is fairly simple.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文