Skip to content

World to screen tracking

A screen primitive can be placed on a moving point rather than at a fixed position. The point is re-read every frame, so a label stays on the object, or on the pixel, it names.

The point lives in one of three spaces: the 3D scene, the world space of a shader, or the screen.

A point of the 3D scene

You can force a 2D object, for instance a label, to follow a 3D object of the scene using the screenprimitiveptr->track method.

track(const std::function<vec()>& placer,vec2 offset)

  • const std::function<vec()>& placer should return the 3D position to follow, the lambda is intended to capture the element to follow, see Example.
  • vec2 offset displacement on the screen from the projected 3D position, expressed in relative coordinates (i.e. vec2(0.1,0.2) means an offset of 10% of the screen width and 20% of the screen height)

Example

    auto particle = Point::Add([] (TimeObject t) -> vec {
        float angle = t.inner_time;
        return vec(cos(angle), sin(angle), 0);
    });

    show << particle;

    show << Formula::Add("x")->track([particle] () {return particle->getCurrentPos();}, vec2(0.03,0.03));

A fixed point in the 3D scene can also be followed:

at(const vec& pos,vec2 offset)

Following a point of a shader

A shader given a view: draws a known region of the plane, so its world points can be followed. tracker turns one into a placer:

fx->setView(vec2(0, 0), 3.2);                   // 3.2 world units above the middle
show << eq->at(fx->tracker(vec2(1, 0)));        // sits on the point z = 1
show << lbl->at(fx->tracker([]{ return Snippet::get("center").v2(); }, vec2(0.025, -0.03)));

tracker(const vec2& world, vec2 offset), also taking a std::function<vec2()>

The point is read through the view and rect the shader was last drawn with, so the label agrees with the pixels under it whatever its placement and resolution:. The view itself can move (bindView), and the label follows.

Deck format

follow: is the deck form of both: an item placed on a moving value rather than at a position.

- latex: here
  follow: query_point     # a 3D point of the scene, projected every frame
- formula: p
  follow: fx.center       # "center", read in the world space of the shader "fx"
  offset: [0.025, -0.03]  # shifted from that point, in screen units

The name is a snippet variable, a tunable parameter, or a placer registered with registerPlacer. Its width says which space it is in:

Components Meaning
3 a point of the 3D scene, projected to the screen, like track above
2 a screen position, 0..1 with y up
2, with an <item>. prefix a point of the world space of that shader

Nothing is inferred: a prefix naming something that is not a shader, a shader with no view:, a 3D value asked for in a shader's space, or a name resolving to nothing, each says so. A prefix is only read as one when it really names an item, so a parameter with a dot in its name is read whole.

follow: takes no at:

The item follows a moving point, so it has no position of its own to place. Use offset: to shift it from that point.