4.6 KiB
LibreMetaverse MeshFoundry renderer
libremetaverse-rendering-mesh-foundry is the bounded native renderer for
legacy prims, sculpt maps, terrain, and Second Life LLSD mesh assets. It uses
the checked SimpleRenderer/PrimMesher path for legacy geometry and the native
StructuredData binary codec for mesh containers. It does not wrap, load, or
invoke the C# renderer or duplicate the LLSD and image codecs.
Pipelines
The mapped MeshFoundry methods cover:
- simple and face-grouped legacy prim geometry at every
DetailLevel, always retaining finite normals and UVs; - plane, cylinder, sphere, and torus sculpt maps;
- rectangular height-map terrain with generated normals and UVs;
- packed mesh-asset headers and individually zlib-compressed LLSD sections;
- requested visual LOD selection (
high_lod,medium_lod,low_lod, andlowest_lod) with deterministic highest-to-lowest fallback; - single-section simple-mesh extraction and physics convex/bounding hulls; and
- default or planar texture transforms, repeats, offsets, rotation, and prim
scale through the common
IRenderingcontract.
Mesh vertices remain in prim-local coordinates. Quantized positions use each
submesh's PositionDomain; normals and tangent components use the format's
fixed [-1, 1] domain; UV0 and optional UV1 use their independent domains.
Triangle and face order is preserved, while flattened multi-face output rebases
indices without reordering vertices. Missing normals and tangents are generated
deterministically from triangles and UVs. Degenerate UV gradients receive a
stable normal-orthogonal fallback tangent.
The mapped Face type has no tangent field. Mesh tangents are therefore kept
without changing the public C# layout in a public MeshFaceAux value stored in
Face.user_data; recover it with
face.user_data.downcast_ref::<MeshFaceAux>(). Its Vector4.w is the bitangent
handedness. UV1 remains in Face.tex_coords1.
Rigged meshes and materials
The skin section decodes bounded joint names, inverse-bind matrices,
bind-shape matrix, alternative inverse-bind matrices, pelvis offset, and the
joint-position scale lock into the shared MeshSkinData. Per-vertex weight
streams accept the protocol's sentinel form and its exactly-four-influence
form, validate every joint index, clamp protocol weights, normalize four
influences, and bind missing vertices to joint zero. The output is directly
consumable by RiggedSkinMath and AnimeshSkinning.
Each submesh retains its original face ID and the effective inherited
PrimitiveTextureEntryFace, including texture, legacy material, and render
material overrides. NormalizedScale, face bounds, centers, optional UV1,
weights, normals, tangents, and winding are kept together. Mesh sculpt mirror
and invert flags apply the viewer-compatible reflection, normal inversion, and
XOR winding rule to every face and tangent domain.
Bounds and failure contract
Assets and compressed/decompressed sections are capped at 64 MiB. Header sections and submeshes are capped at 256, each face remains within the 16-bit 65,536-vertex index domain, aggregate visual geometry is capped at 1,000,000 vertices and 6,000,000 indices, skins at 512 joints, and convex data at 65,536 hulls and 1,000,000 vertices. All sizes, offsets, index rebasing, buffer strides, and allocation products use checked arithmetic before slicing or allocation.
Malformed LLSD, zlib data, domains, parallel buffers, matrices, weights,
offsets, and indices return Error::Rendering with the source primitive UUID
and a stable operation context. UnpackMesh has no primitive parameter and
uses the zero UUID. This crate performs no asset download, scene traversal,
world transform, GPU upload, material shading, texture fetch, or drawing.
Reproducible gates and benchmark
python3 tools/check_milestone_10_issue_77.py
CARGO_BUILD_JOBS=1 cargo test -p libremetaverse-compat-tests --test imaging_meshing_semantics --locked -j1
CARGO_BUILD_JOBS=1 cargo test -p libremetaverse-rendering-mesh-foundry --locked -j1
CARGO_BUILD_JOBS=1 cargo bench -p libremetaverse-rendering-mesh-foundry --bench mesh_decode --profile benchmark --locked -j1
The named benchmark profile uses bounded-memory moderate optimization because
full release optimization of the generated core surface can exceed small
Gitea-worker memory before the fixture runs. The non-statistical benchmark
builds and decodes a deterministic 57,600-vertex,
342,726-index mesh asset and reports elapsed time plus allocation counts. It is
diagnostic evidence for regressions; correctness and malformed-input tests
remain the release gates.