luvcraft/agent/shaders.lisp
--------------------------------------------------------------------- The gnome's proportions, as knobs
Every number below stands in the shader source by name and folds to a literal when the source is parsed, so turning one rebuilds his pipeline rather than writing a uniform (LUVCRAFT/KNOBS.LISP). For a figure that is drawn once in the frame that is the right trade: the knobs pay for themselves in how fast a proportion can be tried, and nothing pays per pixel. What is here is what an argument about how a gnome should look actually turns out to be about -- the hat, the nose, the beard, the belly, and how far apart his eyes are set.
The whole figure's scale, in world cells per figure unit.
The marcher works in figure units and this is the only place the world's scale enters, so his bounding sphere follows from it too. At four fifths he stands about a cell and a quarter: shorter than a player, which is rather the point of him.
How strongly the beard's strands, the robe's weave and the hat's felt show. Zero is flawless vinyl.
--------------------------------------------------------------------- Distance-field vocabulary
The polynomial smooth minimum: a union with a fillet of RADIUS.
This is what makes a nose grow out of a face instead of intersecting it.
The usual bounded approximation to an ellipsoid's signed distance.
Exact would need a quartic root; this under-estimates, which is all sphere tracing asks of it.
A cone capped by a sphere at each end: the shape of a robe, and of a hat.
The lateral surface is tangent to both caps, so the silhouette has no crease where the cone meets its rounding.
--------------------------------------------------------------------- The parts of a gnome
Five functions, each answering for one material. They are called by the marcher to find the surface and again at the hit point to decide which material owns it, so shape and colour can never drift apart.
The hat's own frame: a domain warp that leans the cone's tip forward.
A straight cone is a traffic cone. The lean is what makes it a hat someone is wearing, and it costs one smoothstep.
The tall cone and the brim it sits on.
The brim rides high, near the crown rather than at eye level. A brim low enough to be practical would put his whole face in shadow, and a gnome whose eyes you cannot find is not a friendly little fellow but a bollard.
Head and nose.
Most of the head is under the hat or behind the beard; the nose is the part of him you actually see, so it is a frank sphere.
The nose rides on whatever head it was given, so resizing the head does not leave it hanging in front of his face.
A broad beard with a blunt point: the mass that gives him his gravity.
Its top edge is the lower bound of his face, so it sits just under the nose: enough beard to be venerable, not so much that there is nobody behind it.
The robe, flaring to a hem that rests on the ground, and two mitten hands.
The hem stops just above his boots. An earlier version ran the cone's lower cap down past the feet, and the terrain cut it off in a dead straight line: he looked less like he was standing on the world than pasted onto it.
The whole fellow: five parts welded with fillets of different sizes.
The robe-to-head weld is generous because a gnome has no neck to speak of; the hat sits on the brim with almost no fillet at all, because a hat is worn rather than grown.
--------------------------------------------------------------------- What he is made of
Eyes, brows and a little colour in the cheeks, painted on the skin only.
The features are placed by *direction* from the centre of the head rather
than by distance to a point in space. Placing them by point failed: the
welded surface stands a fillet's width outside the head sphere the markers
were measured against, so every feature sat just under the skin and the
gnome came out blank-faced. A direction does not care how far out the
surface ended up.
The eyes are small and dark and the brows are heavy. Resisting the urge to enlarge the eyes is the whole difference between a friendly little fellow and a cartoon: he should look like he is thinking about you, not begging for something.
Glint and brow are stated relative to the eye, so moving the eyes moves the whole expression rather than taking it apart.
The brow is measured in a squashed metric: wide, low and shallow, which is a brow, where an unsquashed disc would be a wart.
The nearest part decides the colour.
A muted, slightly earthy palette on purpose: a scarlet hat over a slate robe reads as someone who has been standing in a garden for a long time, where saturated primaries would read as a toy.
Three grains, each sampled in a domain stretched along the way that material actually runs: the beard downward in strands, the robe in a coarse weave, the hat in fine felt. Without them everything the sphere tracer returns is the same flawless vinyl, and a gnome who has stood in a garden for two hundred years should not look like he came out of a mould this morning.
A running nearest-so-far, folded by hand: step answers one when
the candidate is at least as near, and mix takes it.
How much of this point is face, for the details painted on it.
Shade one confirmed gnome surface hit.
Keeping the expensive normal and material field evaluations behind the fragment statement's hit guard means conservative billboard misses pay only for the march, not another five whole-body field evaluations.
--------------------------------------------------------------------- The pipeline stages
The figure's own upright frame: world up stays up and +z is the body's retained forward direction. RIGHT is the cross product of world up with FACING, written out by hand.
The whole march happens in figure units, where the gnome is one and three quarters tall whatever his stature: dividing the camera by the stature once here is the entire cost of the scale knob, and every proportion below can be written as itself. He stands with his feet at figure y zero; the instance centre is the middle of his bounding sphere, 0.85 above them.
Enter and leave through the bounding sphere analytically, so the fixed step count is spent on the body rather than on the approach.
Carry distance and termination explicitly. COUNTED-FOLD lowers :UNTIL to a real loop break on every backend, so hits and sphere exits no longer spend the rest of the fixed budget re-evaluating the whole body field.
The hat's domain warp makes the field slightly non-metric; a shortened step keeps the march honest.
The scene target uses premultiplied alpha. Misses leave no rectangular trace of the conservative billboard. Set the cheap miss first; the structured WHEN keeps normal and albedo evaluation inside the hit arm.
The whole figure's scale, in world cells per figure unit. The marcher works in figure units and this is the only place the world's scale enters, so his bounding sphere follows from it too. At four fifths he stands about a cell and a quarter: shorter than a player, which is rather the point of him.
How high the hat's tip stands above his feet.
The radius of the hat's cone where it meets the brim.
How far forward the hat's tip leans. Zero is a traffic cone.
The brim's radius. Wider than about four tenths and it eats his face.
The radius of the head the face is laid out on.
The radius of the nose, the one feature of him nothing hides.
How broad the beard hangs at the cheeks.
The height of the beard's blunt point above his feet: lower is longer.
The robe's radius at the hem.
The robe's radius at the shoulders.
How far out from the body his mitten hands rest.
How far to the side the eyes sit on the head, as a direction component.
How high the eyes sit on the head. Too high and the brim hides them.
The angular radius of a pupil on the head.
How much colour there is in his cheeks.
How strongly the beard's strands, the robe's weave and the hat's felt show. Zero is flawless vinyl.
The warm outline that separates him from whatever he stands in front of.
Construct a meaningful literal.
Compare compatible quantities and produce dimensionless values.
((name symbol) (type (eql 'arithmetic-operator)))(name (&key label (group :grading) documentation
(class ''scalar-knob)
quantity (type 'single-float)
unit-label minimum maximum step)
place)Define NAME as a knob of CLASS over the setf-able PLACE. PLACE may refer to SESSION, so a knob can live on the session -- its sky clock, its player -- as well as in a special. QUANTITY is a quantity plist as DEFINE-QUANTITY-CONSTANT takes, (:quantity ... :unit ...); it and TYPE make the knob's declaration, which…
(name parameters &body body)Define a reusable typed shader expression with ordinary source syntax. The body is parsed at each call site, so argument types and quantity meanings flow through the same operator protocol as handwritten shader expressions. LET* is lexical inside the function. The definition macro records source; its body does not…
The componentwise square root of a raw value.
The maximum of compatible quantities.
The inner product of two vectors.
The polynomial smooth minimum: a union with a fillet of RADIUS. This is what makes a nose grow out of a face instead of intersecting it.
Constrain a quantity between compatible bounds.
Addition over compatible quantities.
Multiplication and scalar scaling.
Division of two represented quantities.
Subtraction or unary negation.
Interpolate compatible quantities by a scalar amount.
The usual bounded approximation to an ellipsoid's signed distance. Exact would need a quartic root; this under-estimates, which is all sphere tracing asks of it.
A cone capped by a sphere at each end: the shape of a robe, and of a hat. The lateral surface is tangent to both caps, so the silhouette has no crease where the cone meets its rounding.
Select and reorder vector components by a designator such as :XYZ or :RGB.
(arguments)Test whether one compatible scalar is less than another.
Test whether one compatible scalar is greater than another.
The hat's own frame: a domain warp that leans the cone's tip forward. A straight cone is a traffic cone. The lean is what makes it a hat someone is wearing, and it costs one smoothstep.
Produce dimensionless progress across compatible edges.
The tall cone and the brim it sits on. The brim rides high, near the crown rather than at eye level. A brim low enough to be practical would put his whole face in shadow, and a gnome whose eyes you cannot find is not a friendly little fellow but a bollard.
Head and nose. Most of the head is under the hat or behind the beard; the nose is the part of him you actually see, so it is a frank sphere.
A broad beard with a blunt point: the mass that gives him his gravity. Its top edge is the lower bound of his face, so it sits just under the nose: enough beard to be venerable, not so much that there is nobody behind it.
The robe, flaring to a hem that rests on the ground, and two mitten hands. The hem stops just above his boots. An earlier version ran the cone's lower cap down past the feet, and the terrain cut it off in a dead straight line: he looked less like he was standing on the world than pasted onto it.
The componentwise absolute value of a raw value.
The whole fellow: five parts welded with fillets of different sizes. The robe-to-head weld is generous because a gnome has no neck to speak of; the hat sits on the brim with almost no fillet at all, because a hat is worn rather than grown.
Normalize a dimensionless vector.
Eyes, brows and a little colour in the cheeks, painted on the skin only. The features are placed by *direction* from the centre of the head rather than by distance to a point in space. Placing them by point failed: the welded surface stands a fillet's width outside the head sphere the markers were measured against,…
The nearest part decides the colour. A muted, slightly earthy palette on purpose: a scarlet hat over a slate robe reads as someone who has been standing in a garden for a long time, where saturated primaries would read as a toy.
The minimum of compatible quantities.
Shade one confirmed gnome surface hit. Keeping the expensive normal and material field evaluations behind the fragment statement's hit guard means conservative billboard misses pay only for the march, not another five whole-body field evaluations.
Raise a dimensionless value to a dimensionless power.
(generic-function name specialized-lambda-list options &body body)Define a shader-producing method with ordinary DEFMETHOD identity. Calling the method reparses its small source form so changes to source-level abstractions participate in live rebuilding. Method replacement remains the role/stage identity watched by the MOP; abstraction revisions are tracked separately by live…
(role stage)Return the current durable shader specification for ROLE and STAGE.
Expose a quantity's raw representation.
The first genuinely volumetric body for an embodied agent: a little fellow assembled out of signed distance fields.
A camera-facing square is only the conservative rasterization proxy. Each fragment sends its world-space camera ray through the signed distance field and shades the point where sphere tracing converges. The proxy's depth remains an approximation for now; the shape and its lighting are genuinely three-dimensional.
The figure is built in its own upright frame: feet at local y zero, +y up, +z along the embodied agent's retained heading. The proxy still faces the camera for conservative rasterization, but the gnome inside it looks where he is actually going. Every part is a small closed form -- a round cone for the robe and the hat, ellipsoids for the beard and the brim, spheres for head, nose, mittens and boots -- and the parts are welded with a polynomial smooth minimum so the joins read as one body rather than as a pile of primitives. The same five part functions answer twice: once for the surface the ray finds, once for the colour it wears.