Follow-up to #1515, which shipped the blob shadow itself. Three related gaps surfaced while building a chase-camera 3D scene; parking them together to revisit.
Today Mesh._drawGroundShadow places the quad at the caster's own x/z:
out[12] = originX;
out[13] = groundY - extent * SHADOW_LIFT;
out[14] = originZ;
with an ellipse sized to the caster's footprint times a module-level SHADOW_SPREAD (1.2). So a blob is always centred under its caster, always the same relative size, and never influenced by where the light is.
1. Per-object shadow scale
shadowOpacity is per mesh; size is not — it comes from the footprint and a constant. There is no way to say "this character's shadow should read a little larger" or "this pickup's a little tighter".
This is the one with the best cost/benefit. A wide, flat-bottomed prop resting on the ground hides its own blob completely from a camera looking down at it — nothing is visibly wrong, there is simply no shadow — and a slightly larger blob resolves it with no lifting and no physical claims. Suggested shape: shadowScale (default 1), sitting next to shadowOpacity.
2. Author-supplied offset
shadowOffset as a world-space x/z the game sets, giving the sun-angle look without the engine inferring anything, and without needing to decide which light wins.
3. Offset derived from the light direction
The automatic version of (2): take the scene's dominant directional Light3d, project onto the ground plane, offset the blob and stretch its major axis along that vector.
Recorded with the reasons it was not done first, so it is not re-proposed without them being addressed:
- the blob is a flat quad on one named plane, with no occlusion and no contact with terrain. An offset blob slides off the slope it is supposed to be lying on as soon as the ground is not flat.
- a low sun should lengthen a shadow, which a footprint-sized ellipse cannot express — so the offset alone looks more wrong, not less.
- it needs an arbitrary "which light wins" rule for a scene with several, plus a defined fallback when there is no directional light.
- coupling it to a real light makes the blob look like it is modelling something, which invites scrutiny the model cannot survive. Direction-correct shadows want a shadow map, which is past the scope of this tier.
Also considered and rejected
Clamping or warning when shadowGroundY is lifted above the caster's base. It looks like a guard against a real trap — lifting the plane does not slide the blob out from under an object, it floats it up, and past a few units it projects over the top as a dark ring. But the same setting is legitimately used for a jumping or flying object whose shadow must stay on the floor and shrink with height, so a clamp would break the case the setting exists for. Documented in the melonjs-3d and melonjs-3d-assets skills instead (#1630).
All three default to current behaviour, so none is breaking.
Follow-up to #1515, which shipped the blob shadow itself. Three related gaps surfaced while building a chase-camera 3D scene; parking them together to revisit.
Today
Mesh._drawGroundShadowplaces the quad at the caster's own x/z:with an ellipse sized to the caster's footprint times a module-level
SHADOW_SPREAD(1.2). So a blob is always centred under its caster, always the same relative size, and never influenced by where the light is.1. Per-object shadow scale
shadowOpacityis per mesh; size is not — it comes from the footprint and a constant. There is no way to say "this character's shadow should read a little larger" or "this pickup's a little tighter".This is the one with the best cost/benefit. A wide, flat-bottomed prop resting on the ground hides its own blob completely from a camera looking down at it — nothing is visibly wrong, there is simply no shadow — and a slightly larger blob resolves it with no lifting and no physical claims. Suggested shape:
shadowScale(default1), sitting next toshadowOpacity.2. Author-supplied offset
shadowOffsetas a world-space x/z the game sets, giving the sun-angle look without the engine inferring anything, and without needing to decide which light wins.3. Offset derived from the light direction
The automatic version of (2): take the scene's dominant directional
Light3d, project onto the ground plane, offset the blob and stretch its major axis along that vector.Recorded with the reasons it was not done first, so it is not re-proposed without them being addressed:
Also considered and rejected
Clamping or warning when
shadowGroundYis lifted above the caster's base. It looks like a guard against a real trap — lifting the plane does not slide the blob out from under an object, it floats it up, and past a few units it projects over the top as a dark ring. But the same setting is legitimately used for a jumping or flying object whose shadow must stay on the floor and shrink with height, so a clamp would break the case the setting exists for. Documented in themelonjs-3dandmelonjs-3d-assetsskills instead (#1630).All three default to current behaviour, so none is breaking.