three.js - Three.js PMREMGenerator 有不正确的纹理过滤
问题描述
我在三个场景(使用 AFrame)中需要环境映射来进行照明。使用标准 HDR 立方体贴图,我得到以下结果:
就基于粗糙度的模糊而言,这是正确的,因为我生成了 mipmap,并且 minFilter 设置为 LinearMipmapLinearFilter。这种方法的问题是没有应用环境照明——场景中的光,定向光,是唯一向场景提供任何照明信息的东西。不幸的是,无论 HDRI 有多亮,这都会导致完全黑色的阴影。
但是,如果除了上述之外,我还使用 Three 的 PMREMGenerator,环境照明问题就解决了。不幸的是,结果是这样的:
如此处所示,纹理过滤现在不正常了。根据 PMREMGen 脚本本身留下的评论。
此类从 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),但如果发现解决方案,我会保留它。
解决方案
我相信问题出在你在fromCubemap()
. 现在您的代码没有使用tex
传递给加载回调的 cubetexture 变量。尝试这个:
const hdrSky = ctl.load(hdrUrl, tex => {
// use tex instead of hdrSky
const hdrRenderTarget = pmremGen.fromCubemap(tex);
this.skies[src] = hdrRenderTarget.texture;
});
推荐阅读
- python - 如何在 Flask-SocketIO 中打印 HTML 字符而不进行迭代(追加)?
- laravel - Laravel:从数据库设置配置文件的值
- stata - 如何在Stata中的广义估计方程后检查自相关?
- python - 制作和打印包含输入值的字典的代码输出不完整的字典;为什么?
- postgresql - Ecto - 在单个查询中返回按日期分组的时间戳记录
- cloudify - 如何在不使用 cloudify 更改 OS 中子网 UUID 的情况下使用 execute_operation 更新子网名称
- docker - 在 Docker 上运行时出现 Redis 错误“无法打开 RDB 文件 dump.rdb”
- awk - sed:-e 表达式#1,字符 2:命令后的额外字符
- node.js - Node JS - 排队 MySQL 插入查询
- json - 解析json postgresql查询