【发布时间】:2021-05-18 03:50:52
【问题描述】:
以下代码非常适用于不包含 alpha 通道的图像:
toJSON() {
let output = super.toJSON();
output["geometry"] = this.geometry;
output['imageURL'] = this.mesh.toJSON().images[0]["url"];
return output;
}
fromJSON(data) {
super.fromJSON(data);
this.geometry = data["geometry"];
this.image_path = data["imageURL"];
this.refreshImage();
}
refreshImage() {
const this_obj = this;
const image_texture = new THREE.TextureLoader().load(
//image to load
this.image_path,
//onLoad callback to create the material only once the texture is loaded and its dimensions are available,
//this will ensure aspect ratio is based on the actual texture loaded.
(texture) => {
this_obj.changeGeometry(texture.image.width / texture.image.height)
},
//not required
undefined,
//onError callback
(err) => {
alert("An error occurred while attempting to load image");
}
);
this.mesh.material.map.dispose();
this.mesh.material.dispose();
this.mesh.material = new THREE.MeshPhongMaterial({map: image_texture, side: THREE.DoubleSide,
transparent: true})
this.mesh.material.color.set(this.color);
this.mesh.material.needsUpdate = true;
}
很遗憾,它不适用于具有 Alpha 通道的图像,因为透明区域会以黑色不透明颜色呈现。
有谁知道为什么会发生这种情况以及如何最好地达到预期的结果?
编辑:
当我意识到问题来自 Mesh.toJSON 调用时,我得到了问题的答案。该方法是一种递归方法,它是一个真正的兔子洞。但是在兔子洞的底部,您会发现纹理图像通过将图像绘制到临时内部画布上而转换为 base64。这发生在 getDataURL() 函数内的 ImageUtils.js 模块中
问题是宽度或高度大于 2048 的纹理图像被转换为压缩的“jpeg”格式,而不是保留 alpha 分量的“png”格式。
这说明了一切。
您可以加载任何图像,使用 TextureLoader 将其应用到材质,但一旦您调用 toJSON 序列化您的网格,如果底层图像的宽度或长度大于 2048,则 alpha 组件会丢失。
在我的情况下,解决方案是编写自己的函数,将图像绘制到画布并将图像转换为 base64,但支持更大的图像尺寸。当然,必须警告用户执行转换可能需要一些时间。
【问题讨论】: