BufferAttribute type / precision conversion API
#32614
Open
+54
−10
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.

BufferAttribute.convert()e0ae5b1 introduces a
.convert()function inBufferAttributeto allow for precision conversion and buffer quantization of attributes likeposition,uvetc.This allows one to drop any BufferAttribute to a lower precision like
HalfFloatorInt8to save on VRAM (and RAM).Thanks to already existing data conversion like
three.js/src/extras/DataUtils.js
Line 150 in 69a97bf
three.js/src/core/BufferAttribute.js
Line 876 in 69a97bf
ThreeJS already has the ability to convert to and from various types for values, but not for buffers as a whole yet. This commit creates a conversion function which makes use of these preexisting data conversions to do exactly that.
The idea is to allow all the various Geometry generation functions like SphereGeometry.js to output with lower precision, without introducing a bunch of per-geometry generator custom code.
I see some potentially strong VRAM savings for this like dynamically imported 3D Satellite maps.
SphereGeometry( ... , precision = { ... } )To showcase this, in dd01e63 I extended SphereGeometry.js to (optionally) allow to set precisions for each
BufferAttributeor entirely remove said attribute. It also clarifies which precisions were used previously by default, which wasFloat32. Default case remains as is, nothing changes here, no API break.E.g. this allows the creation of a sphere with no normals, Half-Float Positions and 8-bit UVs.:
Motivation and VRAM savings in
GroundedSkyboxCommit 0ecfbb9 uses these new parameters to get a 50% VRAM and RAM size reduction of
GroundedSkyboxgeometry on default settings with no visual impact.In #27422 & #27448 @elalish changed the previous shader based
GroundProjectedSkyboxto the new geometryGroundedSkybox. To get the newly introduced rounded curve from floor to dome,GroundedSkyboxgenerates 65,024 triangles on defaultresolutionand deforms it, with full precision BufferAttributes and unused normals.GroundedSkyboxwith defaultresolutionGroundedSkyboxwith defaultresolutionDue to how SphereGeometry.js works, it produces very dense mesh on the flat floor. The 65,024 triangles default chosen by @elalish is the only way to get enough geometry and avoid distortions of the spherical texture on the curved transition.
The VRAM and RAM usage of the default
GroundedSkyboxis as follows:0ecfbb9 now requests a Sphere with the following
precisionproperties:This results in no visual change and the following RAM and VRAM usage:
The 50%
GroundedSkyboxVRAM savings aren't that important in the grand scheme of things, but this shows how I think a Three.JS user might want use such a attribute precision api to get VRAM savings on dynamically generated geometry and avoid hard crashes due to strict VRAM limits that some iPhones impose in WebGL.0ecfbb9 also adds a material name in

GroundedSkybox, so it doesn't show up as blank in Debuggers like https://github.com/utsuboco/r3f-perfStuff to decide
If we wanna merge this, I'll properly write the docs and stuff, but some things need to be clarified first:
precision = { ... }to all the geometry constructors in src/geometries or this this out of scope? Rename it toattributes = { ... }?fromArraycreate all the types yet, so this leads to the bit awkward expression ofthis.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ).convert( precision.position ) );which creates a Float32 Buffer to immediately convert it. Is this fine or do we need to do something about this?toJSON()stuff, something I ignored so far in this PR. So we would need to switch outTHREE.Float16BufferAttributefor constant likefloat16. But the already existing constants likeHalfFloatTypeare texture related and there is no 8bit vs 16bit int constant in the first place, so what to do? Create a new set of Geometry constants and correctBufferAttribute.gpuTypewhich has been using Texture constants for Geometry Attributes?