【问题标题】:opengl: adding higher resolution mipmaps to a textureopengl:向纹理添加更高分辨率的 mipmap
【发布时间】:2014-12-08 00:26:47
【问题描述】:

每当我想在 opengl 中使用 mipmap 时,我需要将最高分辨率的位图上传为 mipmap 级别 0,然后在更高的 mipmap 级别上传较低分辨率的位图。

我希望能够添加更高分辨率的 mipmap 以及更低分辨率的 mipmap。目前我知道的唯一硬件方法是启动一个新的 mipmap-ed 纹理并重新上传所有以前上传的位图。

还有其他硬件方法可以做到这一点吗?

编辑:
看起来 GL_TEXTURE_BASE_LEVEL 和 GL_TEXTURE_MAX_LEVEL 并没有改变 opengl 将在纹理创建时为所有纹理 mipmap 级别分配内存的事实,因此它不能在这种情况下使用,因为不可能知道哪些纹理需要更高分辨率的 mipmap,哪些不需要t,所以会导致极大的内存浪费。

看来,在硬件中执行此操作的唯一方法是在 mipmap 级别 0 使用新生成的更高分辨率 mipmap 重新创建新纹理,然后在较低 mipmap 级别复制所有先前的较低分辨率 mipmap。

据我所知,唯一的方法是将所有先前生成的 mipmap 级别保留在内存中,以防我需要重新上传它们(不想浪费这么多内存),重新生成所有 mipmap 级别(不会这样做,太慢了),使用 gltexsubimage2d 将以前的纹理 mipmap 级别复制到系统内存,然后将它们上传到新纹理(这一定很慢),或者将它们直接从以前的纹理复制到新纹理。

那么,有没有办法将纹理的选定mipmap复制到不同纹理的mipmap,例如“glcopytexture(texture_id_1,texture_mipmap_1,texture_id_2,texture_mipmap_2);”

编辑2:
似乎最近有一个扩展(扩展 ~2009 在 ~2012 成为核心)正是这样做的(https://www.opengl.org/wiki/Texture_Storage#Texture_copy),但该合同的要求之一是支持长达 10 年的计算机。

【问题讨论】:

  • 这通常意味着驱动需要重新分配整个纹理,因为它在创建低分辨率mipmap时没有考虑更高的分辨率
  • 此时看来,之前的评论可能是唯一不浪费纹理内存的硬件答案。我正在使用找到的信息在我最初的问题中添加一个后续问题。
  • @Marladu:实际上,对于真正现代的 GPU,还有其他可能性,尤其是 GL_ARB_sparse_texture。这当然不是你想要的 10 年老系统。
  • 您好,感谢您的评论。我试图阅读您链接的文章,但老实说,它不仅不适用于我目前的合同,而且大多数情况下我能理解的内容太多了,我认为我无法使用它没有明确的指示,我能找到的还不足以满足我目前的能力。如果这确实与这个问题有关,并且您有时间和兴趣,也许您可​​以在此 ARB/EXT 中添加一个非常简短的入门知识,以使每个人都受益?

标签: opengl


【解决方案1】:

无需上传完整的 mipmap 链即可使用纹理。您可以通过设置GL_TEXTURE_BASE_LEVELGL_TEXTURE_MAX_LEVEL 来控制使用的级别范围。

您必须在最初创建纹理时确定基本级别的大小 [1]。但是您可以推迟加载最低级别的数据,或者根本不加载它们。

例如,假设您想要一个在全分辨率下最多为 1024x1024 大小的纹理,但您知道不需要级别 0 和 1,因为它用于的对象离相机很远。您可以从级别 2 开始创建纹理:

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 2);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_LOD, 2);
glTexImage2D(GL_TEXTURE_2D, 2, GL_RGBA8, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);

那么,如果你后来决定现在需要一直到 0 级的纹理:

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_LOD, 0);
glTexImage2D(GL_TEXTURE_2D, 2, GL_RGBA8, 1024, 1024, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);

我不认为设置GL_TEXTURE_MIN_LOD 是必要的,但它不会受到伤害。在这两个代码序列中,您当然可以一一提供自己的mipmap,而不是调用glGenerateMipmap()

主要需要注意的是,您需要能够指定大于 0 的级别的数据。因此,您要么需要在运行时生成自己的 mipmap,要么拥有包含 mipmap 的预烘焙资源。

此外,即使您没有为这些级别指定数据,实现也可能决定将完整纹理分配到级别 0。因此,您可能会也可能不会以这种方式节省内存。您唯一可以依靠的是它加速了初始纹理上传。

[1] 严格来说这并不正确,因为对于更高级别的给定大小,基本级别有多个有效大小。例如,如果级别 2 的尺寸为 16,则级别 1 的尺寸可以是 32 或 33,而级别 0 的尺寸可以是 64、65、66 或 67。

【讨论】:

  • 这太有趣了,我不知道这个,谢谢!但是,仍然为未使用的 mipmap 分配内存的可能性有多大?问题是我无法提前知道哪个纹理需要哪些 mipmap 级别,并且有很多纹理需要改进(纹理 mipmap 是即时生成的) .我正在处理的应用程序中的一个示例是 32x32 或更低的 1000 个纹理,以及 64x64 或更高的大约 100 个纹理,但在分配时不知道哪个需要超过 32x32,所以必须做你描述的这件事全部。
  • 阅读:khronos.org/opengles/sdk/docs/man3/docbook4/xhtml/… 我被认为没有必要使用 GL_TEXTURE_MIN_LOD。
  • 在我的 2 台家用计算机上,使用 gDEBugger 我可以确认 OpenGL 不会为使用此答案中提出的方法准备的纹理分配未使用的 mipmap 级别的内存。我添加了一个问题stackoverflow.com/questions/27352305 来帮助我弄清楚如何在没有 gDEBugger 的情况下找到它,这样我就可以更广泛地分发这个测试并获得结果来确认/否认这个答案的方法是我正在寻找的答案。
  • 这是一项很好的研究。我有一种感觉,它将非常依赖于平台和供应商。它也可能不一定是二元答案。纹理可以有多个分配(例如系统内存和 VRAM 分配),它们的行为可能不同。
  • 使用一个名为 GPU-Z 的程序,它能够找到总分配的内存大小,并在大约 12 个不同的视频卡上测试这个答案的方法之前和之后有所不同,我现在可以说所有测试用例,无论 GL_TEXTURE_BASE_LEVEL 和 GL_TEXTURE_MAX_LEVEL 是什么,都会分配所有纹理 mipmap 级别的全部内存。可悲的是,这意味着在我的情况下,不能使用此答案的方法而不会造成极大的内存浪费,事实上,只有在提前知道所有纹理 mipmap 级别都将在短时间内使用时才应该使用。
猜你喜欢
  • 2018-08-05
  • 1970-01-01
  • 2018-03-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多