PLYloader error in loading little_endian geometry
See original GitHub issueGreetings
Description of the problem
I am using your library to render some PLY files generated from third party cameras. As such, I have little control upon the generated file.
The generated PLY is encoded in binary_little_endian format, and is a correctly generated PLY file (I can load it via MeshLab, or I can translate to a similar format such as Nexus without problems).
Yet, I cannot correctly load this file via the PLYloader
.
More precisely: I am able to render the ‘ascii’-ized version of the file (loaded into MeshLab, and saved in ascii format) with little problem, yet the binary file simply won’t load.
This seems due to an error in the windowing of the underlying array buffer, for I get this error:
RangeError: offset is outside the bounds of the DataView
I tried to alter the loader so that the offset cannot exceed the DataView boundary, but as expected this causes other errors downstream
THREE.BufferGeometry.computeBoundingSphere(): Computed radius is NaN. The "position" attribute is likely to have NaN values.
I’d like to ask for some informations on this case: is it an error of the loader, of the file, of the parameters I set in the program (an example of which is created in a JSFiddle)?
The fiddle has a reference to the PLY files, and I’ll be happy to add any missing information.
Thanks for your product, and for the time spent in reading this.
Three.js version
- Dev
- r96
- Possibly older ones, but I cannot find the version number
Browser
- All of them
- Chrome
- Firefox
- Internet Explorer
OS
- All of them
- Windows
- macOS
- Linux
- Android
- iOS
Hardware Requirements (graphics card, VR Device, …)
None
Issue Analytics
- State:
- Created 5 years ago
- Comments:12 (3 by maintainers)
Top GitHub Comments
The binary file in the fiddle appears to be slightly truncated at the very end. The header lists 432486 faces, but the file ends after face 432443. PLYloader is throwing a RangeError trying to read the last few faces, since there’s no more data to be had, and the postProcess function where it writes the data into the geometry never gets called, which is why the geometry looks empty.
It appears that MeshLab is sensibly taking as many faces as it can get and not worrying about the file not having quite as many as the header promised.
Fundamentally, the bug is with whatever is writing this file. I’d suspect that what’s happening is that a few of the faces are invalid (by whatever definition the program that’s doing the writing uses; maybe it’s skipping faces that reference missing vertices, maybe it’s skipping faces that have one vertex referenced twice; who knows…) and as it writes it’s skipping the problematic faces. Thus at the beginning when it writes the header it thinks it’s going to have 432486 faces, but a few don’t get written along the way and it doesn’t go back and update the header to reflect the 432443 faces it actually wrote. It’s not an uncommon failure mode for PLY writers. Not a huge problem if it happens on the last element in the file, but if it happens on one of the earlier elements, then it corrupts the data in the following element (e.g. if you have a couple of missing vertices, then the first few faces will be incorrectly interpreted as vertices – with an ascii ply you can usually detect that, but with a binary ply you just get a couple of garbage verts).
If desired behavior is silently supporting slightly malformed files like this, the way MeshLab does, it should be easy enough to wrap the call to binaryReadElement in parseBinary to catch the RangeError and ignore it.
As a side note, if you’re looking to validate a ply implementation, RPLY is probably the canonical C implementation and the code is fairly straightforward.
Interesting – so it turns out that the issue was actually an off-by-one error having to do with whitespace in the ascii header… Fix is https://github.com/mrdoob/three.js/pull/15099 I’m still puzzling over why that problem was causing the data to appear truncated, since if anything there should have been one extra byte left over after everything was read.