【问题标题】:Three.js PMREMGenerator has incorrect texture filteringThree.js PMREMGenerator 有不正确的纹理过滤
【发布时间】:2021-03-03 04:24:08
【问题描述】:

我在三个场景(使用 AFrame)中需要环境映射来进行照明。使用标准 HDR 立方体贴图,我得到以下结果:

就基于粗糙度的模糊而言,这是正确的,因为我生成了 mipmap,并且 minFilter 设置为 LinearMipmapLinearFilter。这种方法的问题是没有应用环境照明——场景中的光,定向光,是唯一向场景提供任何照明信息的东西。不幸的是,无论 HDRI 有多亮,这都会导致完全黑色的阴影。

但是,如果除了上述之外,我还使用 Three 的 PMREMGenerator,环境照明问题就解决了。不幸的是,结果就是这样:

如图所示,纹理过滤现在已经不正常了。根据 PMREMGen 脚本本身留下的 cmets。

这个类从 cubeMap 环境纹理生成一个预过滤的 Mipmapped Radiance Environment Map (PMREM)。这允许根据材料粗糙度快速访问不同级别的模糊。它被打包成一种特殊的 CubeUV 格式,允许我们执行自定义插值,以便我们可以支持非线性格式,例如 RGBE。与传统的 mipmap 链不同,它只会在相同 LOD_MIN 分辨率下下降更多过滤的“mips”,并与更高的粗糙度级别相关联。通过这种方式,我们可以在限制采样计算的同时保持分辨率以平滑地插入漫反射光照。

...这让我相信输出应该被平滑,就像我的第一个例子一样。

这是第一个示例的代码:

const ctl = new HDRCubeTextureLoader();
ctl.setPath(hdrPath);
ctl.setDataType(THREE.UnsignedByteType);

const hdrUrl = [
  `${src}/px.hdr`,
  `${src}/nx.hdr`,
  `${src}/py.hdr`,
  `${src}/ny.hdr`,
  `${src}/pz.hdr`,
  `${src}/nz.hdr`
];
const hdrSky = ctl.load(hdrUrl, tex => this.skies[src] = hdrSky );

// Then later...

obj.material.envMap = this.skies[this.skySources[index]];
obj.material.needsUpdate = true;

这是第二个示例的代码:

const ctl = new HDRCubeTextureLoader();
ctl.setPath(hdrPath);
ctl.setDataType(THREE.UnsignedByteType);

const hdrUrl = [
  `${src}/px.hdr`,
  `${src}/nx.hdr`,
  `${src}/py.hdr`,
  `${src}/ny.hdr`,
  `${src}/pz.hdr`,
  `${src}/nz.hdr`
];

const pmremGen = new PMREMGenerator(this.el.sceneEl.renderer);
pmremGen.compileCubemapShader();

const hdrSky = ctl.load(hdrUrl, tex => {
    const hdrRenderTarget = pmremGen.fromCubemap(hdrSky);
    this.skies[src] = hdrRenderTarget.texture;
});

// Then later...

obj.material.envMap = this.skies[this.skySources[index]];
obj.material.needsUpdate = true;

我似乎在过滤方面碰壁了。即使我在 PMREMGenerator.js 中显式更改过滤类型并打开 mipmap 生成,结果似乎也是一样的。这是一个使用 PMREMGenerator 没有任何问题的官方示例:https://threejs.org/examples/webgl_materials_envmaps_hdr.html

作为结束语,我会注意到我们正在使用 Three.js r111(并且有一些原因我们无法完全将其关闭),所以我从最新版本的 Three 中引入了当前版本的 PMREMGenerator在撰写本文时(r122 - 需要更高版本,因为 r111 的编写方式完全不同)。因此,如果这一切都是由版本之间的某些冲突引起的,我不会感到惊讶。

编辑:只需将生成的 envmap 作为标准地图放在某些平面上,令我惊讶的是,甚至没有一个模糊的 LODS 出现。这是我的样子:

它应该是这样的(不要介意圆环结):

编辑:我现在找到了一种解决方法(基本上,不使用 PMREMGenerator),但如果发现解决方案,我会保留它。

【问题讨论】:

  • 你能上传它吗?我无法使用 Threejs 示例 hdrs 复制它(我尝试过 here
  • 遗憾的是,这个项目太大而无法上传到故障(它使用 Mozilla Hubs:github.com/mozilla/hubs)。我怀疑这个问题与多个脚本中的各种不匹配的三个版本有关是原因。完全复制问题可能需要复制整个环境(我意识到这对于在线请求帮助并不是特别好——但无论如何我还是这样做了,以防我遗漏了一些明显的东西)。目前,我通过不使用 PMREMGenerator 并直接应用我的立方体贴图来解决这个问题。

标签: three.js 3d aframe


【解决方案1】:

我认为问题在于您在 fromCubemap() 中使用的参数。现在您的代码没有使用传递给加载回调的tex cubetexture 变量。试试这个:

const hdrSky = ctl.load(hdrUrl, tex => {
    // use tex instead of hdrSky
    const hdrRenderTarget = pmremGen.fromCubemap(tex);
    this.skies[src] = hdrRenderTarget.texture;
});

【讨论】:

  • 似乎双向工作stack-64917851.glitch.me
  • 正如@PiotrAdamMilewski 所说,它可以双向工作,因为.load 函数在纹理加载后运行,这意味着hdrSky 已在此时定义。
  • 是的,你是对的。这是我唯一认为可能是问题所在。或者,您可以尝试copying the latest PMREMGenerator file 并粘贴到您的应用中。也许最新版本的文件有一些 r111 缺失的修复。
  • @Marquizzo 遗憾的是,这就是我已经在做的事情。 PMREMGenerator 在 r111 和当前版本之间发生了巨大变化。当前版本具有我需要的功能,但当然 PMREMGenerator 使用的任何依赖项我不能保证也没有改变。这是我怀疑问题所在,但很难调试,因为它运行良好 - 没有错误或警告。我可以检查 r111 中 PMREMGenerator 的每个依赖项与其最新的对应项,但这甚至不能保证解决(并且会花费大量时间)。现在,我只是直接应用立方体贴图。
猜你喜欢
  • 2020-07-23
  • 1970-01-01
  • 2020-10-05
  • 2012-12-16
  • 2022-01-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-26
相关资源
最近更新 更多