Hi all,
This literally broke overnight - it worked all day yesterday. Update to the latest chrome and this example will be pitch black (because geometry itself is black on the black background):
https://threejs.org/examples/webgl_materials_envmaps_exr.html
The recurring error pattern in the dev console is:
[.WebGL-000001B8882DE700] GL_INVALID_FRAMEBUFFER_OPERATION: Framebuffer is incomplete.
webgl_materials_envmaps_exr.html:1 [.WebGL-000001B8882DE700] GL_INVALID_FRAMEBUFFER_OPERATION: Draw framebuffer is incomplete
If you switch to the PNG in the above example - all looks good, so it's just EXR.
HDR example works too
https://threejs.org/examples/webgl_materials_envmaps_hdr.html
so it's an issue for just EXR one.
NOTE: this seems to be a Windows-only issue, as the latest Chrome on iOS works.
This may be related to https://github.com/mrdoob/three.js/issues/15343
NOTE: this seems to be a Windows-only issue, as the latest Chrome on iOS works.
True. I'm unable to reproduce on macOS with Chrome 73.0.3683.75.
Can you please check out if the workaround shared by @silvainSayduck does help?
https://github.com/mrdoob/three.js/issues/15343#issuecomment-457528822
What seems to work for us is changing the type in line
let cubemapGenerator = new THREE.EquirectangularToCubeGenerator(texture, { resolution: 512, type: THREE.HalfFloatType });
from
THREE.HalfFloatType to THREE.FloatType
EXR lighting does look a bit different on r102 for same EXRs with the above change, but it's still better than black models.

Just tried the workaround suggested by @silvainSayduck - kept getting this error:
MYC3D.js:1639 Uncaught DOMException: Failed to construct 'ImageData': The input data length is not equal to (4 * width * height).
for the line:
const imageData = new ImageData(new Uint8ClampedArray(dataTexture.image.data.map((value) => value * 255)), dataTexture.image.width, dataTexture.image.height);
Apparently constructing ImageData requires dataTexture.image.data to be equal to 4 * width * height?
Um, the original type of the loaded EXR texture is THREE.FloatType. THREE.CubemapGenerator respects the original type of the texture whereas THREE.EquirectangularToCubeGenerator allows to overwrite it (e.g. with THREE.HalfFloatType).
@WestLangley Does it makes sense to provide this flexibility? Maybe it's best to switch to THREE.CubemapGenerator in this example...
Chrome 73/Windows regression:
https://twitter.com/BenHouston3D/status/1105923857699889152
They are working on it :)
https://bugs.chromium.org/p/chromium/issues/detail?id=941671#c9
Just tried the workaround suggested by @silvainSayduck - kept getting this error:
MYC3D.js:1639 Uncaught DOMException: Failed to construct 'ImageData': The input data length is not equal to (4 * width * height).for the line:
const imageData = new ImageData(new Uint8ClampedArray(dataTexture.image.data.map((value) => value * 255)), dataTexture.image.width, dataTexture.image.height);Apparently constructing ImageData requires
dataTexture.image.datato be equal to 4 * width * height?
I noticed that this happened for some EXR files on my end too. It's when they are in RGB format. ImageData expects data to be RGBA. Here's the updated workaround:
const originalData = dataTexture.image.data;
const imageWidth = dataTexture.image.width;
const imageHeight = dataTexture.image.height;
let data;
if (originalData.length === imageHeight * imageWidth * 3) {
// RGB format, need to insert 255 values for alpha channel
data = new Float32Array(4 * imageWidth * imageHeight);
data.fill(255);
originalData.forEach((value, ix) => {
const destinationIndex = ix + Math.floor(ix / 3);
data.fill(value * 255, destinationIndex, destinationIndex + 1);
});
} else {
data = originalData.map(value => value * 255);
}
const imageData = new ImageData(
new Uint8ClampedArray(data),
imageWidth,
imageHeight
);
texture = new THREE.Texture(imageData);
texture.needsUpdate = true;
I think you should be able to just do texture.format = THREE.RGBAFormat;.
Thanks for jumping in! However, I'm not sure I understand on which texture this should be applied?
To recreate the Texture that works on Android, I need to create the ImageData, and that expects a Float32Array of length imageWidth * imageHeight * 4. The data in originalData is of length imageWidth * imageHeight * 3 if the EXR file is RGB.
Do you mean that applying dataTexture.format = THREE.RGBAFormat would somehow update dataTexture.image.data? Or that by setting dataTexture.format = THREE.RGBAFormat, the dataTexture would then work directly on Android without having to recreate a Texture at all?
Because from what I understand, it seems that you're saying to apply texture.format = THREE.RGBAFormat on the final texture (two last lines of my snippet). But that Texture can't even be created without the new Float32Array...
Chrome 74 is out. Has this been fixed?
Yes, this is now fixed and can be closed.
Thanks everyone.