← Paracosm·Docs/Handbook
Contents · Meshes

Meshes

WorldBridge spawn_mesh encodes an SL mesh asset on the server from a JSON geometry file and rezzes it. No viewer upload, no COLLADA. Most things on the island (stonework, trees, the boat, water ribbons, flagstones, the flash dome) are meshes built this way by Python.

The input format (*.meshdata.json)

{
  "zup": true,
  "submeshes": [
    { "rgb": [180, 150, 110],
      "verts": [[x, y, z, nx, ny, nz, u, v], ...],
      "tris":  [[a, b, c], ...] }
  ],
  "skin": { ... }            // optional: makes it a rigged animesh (animesh.md)
}

What the viewer demands of the asset

1. The UV domain key is TexCoord0Domain

The viewer dequantises TexCoord0 using the domain keyed TexCoord0Domain. With the key spelt TexCoordDomain the viewer finds no UV domain, collapses every UV to one texel, and the whole mesh renders as one flat colour while the geometry is fine (because PositionDomain was right). Planar mapping still worked, because it ignores mesh UVs.

2. No LLSD notation prefix, and a complete zlib stream

OSDParser.SerializeLLSDBinary(osd) prepends <?llsd/binary?>\n; the viewer's parser rejects the leading < ("Unrecognized character int(60)", then "Mesh header is invalid"). Serialize with SerializeLLSDBinary(osd, false) for the header and every block. Each block must also be a complete zlib stream with its Adler-32 trailer; a hand-written 0x78 0x9C plus a raw deflate stream fails the viewer's strict inflate ("Error during mesh LOD processing. Reason: 6"). Use System.IO.Compression.ZLibStream.

3. Emit Z-up yourself

The viewer's uploader rights an uploaded mesh's up axis on rez; a programmatic spawn gets no such help. Save with "zup": true in a Z-up frame (meshkit does).

Geometry that renders

4. Wind every triangle to its intended normal

The viewer back-face culls. Add each face with the normal it is meant to have and let the kit wind it; check() must return 0 before a spawn.

5. Make stored normals agree with the winding

Faces whose stored normals point against their winding light backwards.

6. Give thin surfaces two sides

A single-plane surface is invisible from behind. Give ears, leaves you can see from both sides, and similar thin parts a thin shell or a second face.

7. A face holds at most 65,535 vertices

Indices are 16-bit. Over the limit the viewer draws NONE of that face, and nothing errors.

8. Do not let an empty submesh renumber your faces

meshkit.save drops an empty submesh, and every later face renumbers.

9. A mesh made and textured in two separate bakes will not fit

The UVs and the texture atlas must come from the same bake run.

Placing meshes

10. A mesh object's position is its bounding-box centre

Not the model's origin. meshkit.save returns the bbox centre offset; spawn there. A script that places the mesh relative to something (a bird's feet on a perch) must carry that offset C and place with feet + C * rot (tools/build_gull.py).

11. Bake the placement yaw into the vertices

Rotate the geometry (Mesh.bake_yaw) and spawn with identity rotation. Then an llTargetOmega axis or a keyframed rotation means the same thing in local and region terms (the waterwheel spins true).

12. Geometry can live far from the object's centre

Because the position is the bbox centre, you can put the centre anywhere by adding a speck of invisible geometry on its own face (alpha 0) mirrored to the other side. A rainbow ring 70 m ahead has its centre at the viewer's eye this way, so a script can move it to the eye and turn it. Mind the 256 m prim size limit.

13. A new mesh can take seconds to stream into the viewer

A screenshot straight after a spawn can show bare ground where it stands. Check list and a raycast, wait, look again. A re-uploaded texture has a new UUID; wait about 10 s before judging a blank face.

Cost and reuse

14. Give big meshes real LODs

lods=[medium, low, lowest] meshdata files, normalised against the HIGH mesh's box. Keep the face count (the encoder pads missing faces with NoGeometry). Without LODs every level is the high mesh, so a tree 60 m away costs what it does under your nose.

15. Instance, do not re-upload

Store a variant's mesh once (spawn a template, keep its meshAsset, despawn it), then spawn_mesh_instance with sx,sy,sz = the high mesh's bbox extents x scale, and the object centre = root + Rz(yaw) (bbox centre x scale). The viewer fetches each variant once.

Shapes that recur

16. Tubes (limbs, pipes, ropes) that do not crack, seam or twist

17. A flat card vanishes edge-on

Bend it. A gull's wing as arm-up, hand-down (an M) always shows a shape from level.

18. Poses as faces

One mesh can carry every pose's parts on their own faces (body, flight wings, legs, head at rest, head thrown back calling); a script shows and hides them by face alpha with every face in PRIM_ALPHA_MODE_MASK (crisp, no alpha sorting, alpha 0 is simply gone). No mesh swapping.

19. Openings in stonework

20. Z-fighting

Two prims whose faces point the same way within about 2.5 mm and overlap shimmer through each other. Eyeballing each joint across a region is hopeless; measure it.

Replacing and rebuilding

21. A prim cannot be turned into a mesh by script

llSetPrimitiveParams([PRIM_TYPE, PRIM_TYPE_SCULPT, meshAsset, PRIM_SCULPT_TYPE_MESH]) compiled and was ignored (sculpt type stayed 0). Replace the object and RE-LAY its life: find the builder that generated its script, regenerate the script for the new object with the old one's parameters (colour read from list, hard-coded sizes patched to the new mesh's bbox), then despawn the old one.

22. Spawn the new thing first, then retire the old

23. Regrow only from recorded originals

A grown mesh's own bbox is bigger than the prim it replaced; regrowing from it swells the thing every run. Keep an originals.json beside each grower (assets/boulders/originals.json is one).

24. Builders are idempotent, and they own a name prefix

Builders in tools/ are seeded and re-runnable, and many find their own earlier objects by name prefix and despawn them before rebuilding. Anything else that shares the prefix is deleted with them.

25. Check the site before you build on it

Things placed by an older builder assumed an older level (props floated 16 cm over a new deck), and grown neighbours spread into new footprints (reeds grew up through a new jetty's ramp). Give every new structure a keep-out in every grower that could reach it.

Seeing a mesh before the viewer does