MeshGeometry.fromArrays constructor
- required Float32List positions,
- Float32List? normals,
- Float32List? texCoords,
- Float32List? texCoords1,
- Float32List? colors,
- Float32List? tangents,
- List<
int> ? indices, - PrimitiveType primitiveType = gpu.PrimitiveType.triangle,
- Aabb3? bounds,
- GeometryStorage storage = GeometryStorage.fixed,
- GeometryBufferArena? bufferArena,
- bool retainCpuData = true,
Builds a mesh from structure-of-arrays vertex attributes.
positions is required and holds three floats per vertex. The
optional attributes hold, per vertex, three floats for normals,
two for texCoords and texCoords1, and four for colors and tangents;
each must match the vertex count implied by positions when supplied. Absent
attributes fall back to defaults: texture coordinate (0, 0) and
color opaque white.
When normals is omitted and primitiveType is a triangle list,
area-weighted vertex normals are generated from the faces; for line
and point primitives, absent normals keep their default. indices,
when supplied, is an index list; when omitted a triangle mesh must
have a vertex count that is a multiple of three.
primitiveType selects how the vertex/index data is assembled into
primitives when drawn, and defaults to a triangle list.
storage selects whether the mesh can later be updated in place.
Pass bufferArena to share immutable GPU buffer blocks with other fixed
meshes. Set retainCpuData to false when the mesh does not need
raycasting or extractMeshData, avoiding a retained CPU copy after the
upload. Updatable geometry requires retained CPU data and cannot use an
arena.
An updatable mesh fixes its indexed-or-not state at construction:
supplying indices makes rebuild require indices thereafter, and
omitting them makes it reject them. To start empty, pass a
zero-length positions array with GeometryStorage.updatable.
bounds, when supplied, becomes the local-space culling AABB and skips
the construction-time position scan; a caller that assembled the
vertices off the UI thread (a worker isolate) can compute it there. It
must cover every position or the mesh over-culls.
Implementation
MeshGeometry.fromArrays({
required Float32List positions,
Float32List? normals,
Float32List? texCoords,
Float32List? texCoords1,
Float32List? colors,
Float32List? tangents,
List<int>? indices,
gpu.PrimitiveType primitiveType = gpu.PrimitiveType.triangle,
Aabb3? bounds,
this.storage = GeometryStorage.fixed,
GeometryBufferArena? bufferArena,
this.retainCpuData = true,
}) {
if (storage == GeometryStorage.updatable && bufferArena != null) {
throw ArgumentError('Updatable geometry cannot use a buffer arena');
}
if (storage == GeometryStorage.updatable && !retainCpuData) {
throw ArgumentError('Updatable geometry must retain CPU data');
}
if (positions.length % 3 != 0) {
throw ArgumentError(
'positions has ${positions.length} floats; expected a multiple of '
'three (one vec3 per vertex)',
);
}
final vertexCount = positions.length ~/ 3;
this.primitiveType = primitiveType;
if (bounds != null) {
final center = (bounds.min + bounds.max) * 0.5;
setLocalBounds(
bounds,
Sphere.centerRadius(center, (bounds.max - center).length),
);
}
// Normals are generated from triangle faces; line and point
// geometry has none, so absent normals are left at their default.
final resolvedNormals =
normals ??
(vertexCount > 0 && primitiveType == gpu.PrimitiveType.triangle
? InterleavedLayoutAdapter.generateNormals(
positions: positions,
vertexCount: vertexCount,
indices: indices,
)
: null);
if (storage == GeometryStorage.fixed) {
_uploadFixed(
positions,
vertexCount,
resolvedNormals,
texCoords,
texCoords1,
colors,
tangents,
indices,
bufferArena,
);
} else {
_indexed = indices != null;
_setCpuStreams(
positions,
vertexCount,
resolvedNormals,
texCoords,
texCoords1,
colors,
tangents,
);
_positionRing = _RingBufferStream(
InterleavedLayoutAdapter.positionStreamBytes,
);
_normalRing = _RingBufferStream(
InterleavedLayoutAdapter.normalStreamBytes,
);
_texCoordRing = _RingBufferStream(
InterleavedLayoutAdapter.texCoordStreamBytes,
);
_texCoord1Ring = _RingBufferStream(
InterleavedLayoutAdapter.texCoord1StreamBytes,
);
_colorRing = _RingBufferStream(InterleavedLayoutAdapter.colorStreamBytes);
_tangentRing = _RingBufferStream(
InterleavedLayoutAdapter.tangentStreamBytes,
);
_liveVertexCount = vertexCount;
// Indices first, so the attribute upload can retain them for raycasting.
if (_indexed) _uploadIndices(indices!);
_uploadAllStreams();
_recomputeBounds();
}
}