Godot Version
4.8
Question
The Color type in Godot 4.x is backed by 4 32-bit floats, so it can store 4 billion odd levels of intensity per channel, most of which fall outside the range 0 to 1.
My project is generating very large ArrayMeshes with ARRAY_COLOR. They’re displayed with unshaded materials in SDR, so 4 8-bit bytes per entry (256 levels of intensity, clamped between 0 and 1) would be sufficient and would save a lot of memory.
Godot 3.x had an ARRAY_COMPRESS_COLOR flag to specify that this format was to be used.
I can’t find an equivalent to this flag in 4.x. I’ve reviewed the source to try to determine what format is used for storage and it seems to differ from context to context:
Appear to use float:
Appear to use bytes:
(there were many more examples of both but Discourse limits how many links I can include)
I’m unsure whether I’m misunderstanding or if there isn’t a consistent format in use.
It appears to only support 4 byte RGBA colors, using unsigned normalized integers. This is much more common and does save on memory, I don’t think there is a way to increase vertex colors data width in Godot, and I don’t think it will represent values outside of the normal range zero to one.
Godot 3.x would default to compressed colors, I assume it was such a good default it became the only path when writing 4.x; if you wanted higher range colors you typically are not using vertex colors, instead EXR textures.
Your apparent use of floats link is for bone weights, not color.
My understanding of the snippet is that all 5 color channels are considered to be DATA_FORMAT_S32G32B32A32_SFLOAT due to switch/case fall-through:
Oops yeah, I’m guessing the flags bitfield as the last argument of ArrayMesh.add_surface_from_arrays determines the p_surface_format mask, if the bit is set for the mask/array then it uses 32-bit values. There is ARRAY_FLAG_COMPRESS_ATTRIBUTES thrown around but it doesn’t affect vertex colors.
More on ARRAY_FLAG_COMPRESS_ATTRIBUTES
ArrayFormat ARRAY_FLAG_COMPRESS_ATTRIBUTES = 536870912
Flag used to mark that a mesh is using compressed attributes (vertices, normals, tangents, UVs). When this form of compression is enabled, vertex positions will be packed into an RGBA16UNORM attribute and scaled in the vertex shader. The normal and tangent will be packed into an RG16UNORM representing an axis, and a 16-bit float stored in the A-channel of the vertex. UVs will use 16-bit normalized floats instead of full 32-bit signed floats. When using this compression mode you must use either vertices, normals, and tangents or only vertices. You cannot use normals without tangents. Importers will automatically enable this compression if they can.
Mesh — Godot Engine (4.7) documentation in English
So long as you do not modify that flags argument your vertex colors will be 4 byte RGBA
My guess was that it was a special case for only having one of the array types:

I think the idea is that if no bits are set other than the current array type.
But I’m not sure why that would switch it from 32 bit to 128 bit.
Thanks for having a look at this.
In the for loop this will check each bit in the p_surface_format mask, it could apply to any or all of the supplied arrays. I’m not sure why you would want to extend the data for most of these array types, I’m sure it’s a low level feature for very low level needs, or mostly used for those custom data arrays.
And if memory is still an issue for your large generated meshes you could try that compress attributes flag which does affect the most common array types and may half the memory usage.
arr_mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, arrays, [], {}, Mesh.ARRAY_FLAG_COMPRESS_ATTRIBUTES)
I’ve just remembered that RenderDoc exists after many years and confirmed that yes, it does use bytes. Thanks for knocking some sense into me 