【问题标题】:Three.JS: render a large map based on different tilesets (Texture Atlas)三.JS:根据不同的tileset渲染一张大图(Texture Atlas)
【发布时间】:2019-02-11 15:32:52
【问题描述】:

简介:

我使用 Three.JS (v95, WebGL Renderer) 渲染等轴测图。该地图包括许多不同的图形图块集。我通过 TextureAtlasLoader 获取特定的图块,它的位置来自 JSON。它看起来像这样:

问题在于,我渲染的图块越多,它的执行速度就越慢(我需要在一张地图上渲染大约 120,000 个图块)。那时我几乎不能移动相机。我知道有几种比将每个图块作为精灵添加到场景中更好的方法。但不知怎的,我被困住了。

当前从代码中提取以创建图块(它在循环中):

var ts_tile = Map.Imagesets[ims].Map.getTexture((bg_left / tw), (bg_top / th));
var material = new THREE.SpriteMaterial({ map: ts_tile, color: 0xffffff, fog: false });
var sprite = new THREE.Sprite(material);
sprite.position.set(pos_left, -top, 0);
sprite.scale.set(tw, th, 1);

scene.add(sprite)

我也尝试过渲染成Mesh,也可以,但是性能是一样的(当然):

var material = new THREE.MeshBasicMaterial({ map: ts_tile, color: 0xffffff, transparent: true, depthWrite: false });
var geo = new THREE.PlaneGeometry(1, 1, 1);
var sprite = new THREE.Mesh(new THREE.BufferGeometry().fromGeometry(geo), material);

网络中可能的解决方案:

我知道我不能在一个场景中添加这么多精灵或网格,我尝试了不同的方法并查看了一些示例,它们完美无缺,但我无法将他们的方法调整到我的代码中。我地图上的每个图块都有不同的纹理并有自己的位置。

官方的three.js 文档中有一个示例:它们使用PointsMaterial 和Points。最后他们只为场景添加了 5 个点,其中包括大约 10000 个“顶点/图像”。文档:https://threejs.org/examples/#webgl_points_sprites

另一种方法可以在 github 上找到:https://github.com/YaleDHLab/pix-plot 他们创建了 5 个网格,每个网格包含大约 4096 个“瓦片”,它们由面、顶点等组成。

最后一个问题:

我的问题是,我怎样才能使我的地图更高效?将我的代码更改为可能的解决方案之一,这让我感到很受挑战。

【问题讨论】:

  • 这张地图一定要这样渲染吗?您不能对数据进行预处理并生成 2D 瓦片集(例如 Google 地图),然后显示这些数据的矩阵吗?
  • 如果我理解正确:我认为他们在可能的解决方案中对数据进行了预处理并将其渲染为瓦片集(在网格中?)?即使是现在,我也只在 requsetAnimationFrame 中更改相机的位置,而不访问数据。但这就是缓慢的部分出现的地方,因为场景中添加了很多瓷砖。
  • 是的,就是这样。您无需渲染许多较小的图块,而是将它们组合/预渲染为更大的图块。它实际上可能是您移动的单个大图像,但当然您最终会得到一个巨大的图像,因此您可以将其拆分为更小的切片。如果缩放是您需要的一项功能,您还需要为每个缩放级别生成不同的图块集。例如,如果您需要渲染“交互式”元素,您可以像现在一样在这些 2D 瓦片上执行此操作。以树为例,如果它们足够稀疏的话。
  • 这正是我失败的地方,我不知道如何做到这一点。我可以用一个简单的 2d 画布来实现它(无论如何这太慢了),但我真的很喜欢将 WebGL 的优势与 Three.JS 结合使用。
  • 你的问题是你的场景有太多的精灵,每个精灵都有自己的材质。唯一的解决方案是减少精灵的数量。但是您的实现受到精灵材质本身的限制,它们是每个图块的一个图像。我的建议是编写代码,将平铺图像集组合成更大的“预渲染”图像,例如覆盖 10 x 10 平铺,这样你就可以拥有原始精灵数量的 10%。如何生成这些组合的 10 x 10 精灵取决于您,但您不需要即时执行,因此是“预渲染”。

标签: javascript performance three.js


【解决方案1】:

我认为 Sergiu Paraschiv 走在了正确的轨道上。尝试将您的渲染分成块。此处概述了此策略和其他策略:Tilemap Performance。根据地形的动态程度,这些块可能更大或更小。这样,您只需重新渲染已更改的块。假设您的地形没有改变,您可以将整个地形渲染为一个纹理,然后您只需每帧渲染一个纹理,而不是一大堆纹理。看看rendering to a texture 上的这个教程,它应该让你知道从哪里开始渲染你的块。

【讨论】:

  • 是的,我曾经做过这种方法,当时我将整个地图渲染到二维画布上。我会尽量减少底层地面的瓷砖数量。我需要单独渲染更多的瓷砖(建筑物,树木等)。我稍后会发布我的尝试!
  • 嘿@Bluesight,只是想跟进。你最终采取了什么方法?
  • 感谢您的提问,老实说,我尝试将它们渲染成 langer 块,并且在性能上有一些改进。不幸的是,我不会继续采用这种方法,因为我们现在决定切换到 Unity 并在 3d 中进行游戏(我们所有渲染的图形实际上都是在 Blender 中制作的模型)。无论如何感谢您的支持。
  • 别担心!抱歉,我无法提供更多帮助。我可以在任何地方关注这方面的发展吗?它看起来像一个整洁的项目!
  • 没问题 :) 看看nemos-inis.de/suite/index.php?nemos。我们也在脸书上。不幸的是,大多数帖子都是德语的,但我们会用英语和德语发布游戏。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-17
  • 1970-01-01
  • 2018-11-02
  • 2012-08-10
相关资源
最近更新 更多