Threejs 2000 纹理瓶颈
Threejs 2000 textures bottleneck
我已经使用 three.js 几个月了。最近我们启动了一个 three.js 应用程序项目,它是一个 3d webgl 产品目录(将产品图像想象为纹理 512x512 的平面),将 base64 图像存储到浏览器 indexeddb 中,并在应用程序加载时创建产品目录。
但是我们遇到了性能问题,假设一个产品类别可能有 100 个产品甚至更多,并且产品总数可能高达 10000。
在每个类别中,我们以特定方式展示我们的模型(平面)。因为应用程序应该提供良好的用户体验,所以所有内容都被预加载,纹理在应用程序启动之前生成并保存在内存中。这是问题开始的地方......
目前在具有 4gb 内存和板载 GPU 的硬件上与 cpu 共享内存导致 chrome 崩溃。此外,每个模型都可以由用户通过触摸事件拖动。
另一方面,我们尝试按需加载纹理,但这对用户体验影响很大,它可能会冻结应用程序 1-2 秒。
目前正在为每个产品创建没有任何纹理的材料。纹理根据产品 ID 存储在不同的对象上,当加载每个类别时,我们将纹理分配给每个模型。我们还处理不再可见的材质的纹理。
我的问题是必须存储 2000 个纹理内存效率不高,导致 chrome 在低 badget 硬件上崩溃。另一方面,如果我按需加载纹理,用户体验会冻结几秒钟...
请记住,每个模型都可以通过用户触摸进行拖动。
我没有遇到任何编码问题,因此没有必要显示任何代码,除非您想看到一些东西。我主要关心的是建筑。
如果有更高效的方法来实现这样的应用程序...我考虑过粒子系统,但每个粒子具有不同的纹理会导致相同的结果吗?
您需要调查为什么您的加载过程会冻结应用几秒钟,这听起来太长了。
内存
考虑您的数据大小,假设您的 512x512 纹理每个 仅 大小约为 256kb,对于 2000 个纹理,您仍在尝试存储 500MB(+ ~33 % base64 开销)indexedDB 中的数据,目前限制为 5MB。因此,无论哪种方式,您都必须按需加载纹理。
纹理图集/巨型纹理:
使用megatextures/a纹理图集在这里不是一个可行的方法。 WebGL 不支持以内存高效方式实现这一点所必需的功能。您需要分配最大纹理大小(8k 到 16k 之间)的纹理,然后将纹理平铺到其中,跟踪当前使用的纹理,以便您可以使用新的所需纹理更新图集的任意部分。一旦 运行 没有图集图块,您需要分配一个最大尺寸的新图集纹理,这就是您将遇到真正的问题和崩溃的地方,因为您无法查询有多少 GPU 内存可用。
实现自适应加载队列:
var textureQueue = [];
// on visible
if (loadedTextures[textureID])
return object.texture = loadedTextures[textureID];
textureQueue.push(textureID);
object.texture = loadingTexture;
// each update
var
startLoading = window.performance.now(),
currentTime = startLoading,
loadID
;
while(
currentTime - startLoading < 10/*ms*/ &&
loadID = textureQueue.shift()
) {
/** load and assign texture here **/
currentTime = window.performance.now();
}
我已经使用 three.js 几个月了。最近我们启动了一个 three.js 应用程序项目,它是一个 3d webgl 产品目录(将产品图像想象为纹理 512x512 的平面),将 base64 图像存储到浏览器 indexeddb 中,并在应用程序加载时创建产品目录。
但是我们遇到了性能问题,假设一个产品类别可能有 100 个产品甚至更多,并且产品总数可能高达 10000。
在每个类别中,我们以特定方式展示我们的模型(平面)。因为应用程序应该提供良好的用户体验,所以所有内容都被预加载,纹理在应用程序启动之前生成并保存在内存中。这是问题开始的地方......
目前在具有 4gb 内存和板载 GPU 的硬件上与 cpu 共享内存导致 chrome 崩溃。此外,每个模型都可以由用户通过触摸事件拖动。
另一方面,我们尝试按需加载纹理,但这对用户体验影响很大,它可能会冻结应用程序 1-2 秒。
目前正在为每个产品创建没有任何纹理的材料。纹理根据产品 ID 存储在不同的对象上,当加载每个类别时,我们将纹理分配给每个模型。我们还处理不再可见的材质的纹理。
我的问题是必须存储 2000 个纹理内存效率不高,导致 chrome 在低 badget 硬件上崩溃。另一方面,如果我按需加载纹理,用户体验会冻结几秒钟...
请记住,每个模型都可以通过用户触摸进行拖动。
我没有遇到任何编码问题,因此没有必要显示任何代码,除非您想看到一些东西。我主要关心的是建筑。
如果有更高效的方法来实现这样的应用程序...我考虑过粒子系统,但每个粒子具有不同的纹理会导致相同的结果吗?
您需要调查为什么您的加载过程会冻结应用几秒钟,这听起来太长了。
内存
考虑您的数据大小,假设您的 512x512 纹理每个 仅 大小约为 256kb,对于 2000 个纹理,您仍在尝试存储 500MB(+ ~33 % base64 开销)indexedDB 中的数据,目前限制为 5MB。因此,无论哪种方式,您都必须按需加载纹理。
纹理图集/巨型纹理:
使用megatextures/a纹理图集在这里不是一个可行的方法。 WebGL 不支持以内存高效方式实现这一点所必需的功能。您需要分配最大纹理大小(8k 到 16k 之间)的纹理,然后将纹理平铺到其中,跟踪当前使用的纹理,以便您可以使用新的所需纹理更新图集的任意部分。一旦 运行 没有图集图块,您需要分配一个最大尺寸的新图集纹理,这就是您将遇到真正的问题和崩溃的地方,因为您无法查询有多少 GPU 内存可用。
实现自适应加载队列:
var textureQueue = [];
// on visible
if (loadedTextures[textureID])
return object.texture = loadedTextures[textureID];
textureQueue.push(textureID);
object.texture = loadingTexture;
// each update
var
startLoading = window.performance.now(),
currentTime = startLoading,
loadID
;
while(
currentTime - startLoading < 10/*ms*/ &&
loadID = textureQueue.shift()
) {
/** load and assign texture here **/
currentTime = window.performance.now();
}