← SENSORLOVE

NDI

VIDEO and DEPTH send the camera and its depth as video on your network, as NDI® sources. NDI® is a registered trademark of Vizrt NDI AB; ndi.video has its free tools, such as Studio Monitor for a first look.

Turn them on

  1. In SENSORS, tap VIDEO or DEPTH, next to FACE TRACK and HAND TRACK. The first time, iOS asks for the camera.
  2. On the computer, open the source: an NDI In TOP in TouchDesigner, an NDI Source in OBS (with the DistroAV plugin); Resolume, vMix and others list it with their NDI sources. It is called SENSORLOVE VIDEO or SENSORLOVE DEPTH, after the phone's name on the network.
  3. NDI ↗ on the monitor opens its settings: the camera (FRONT or BACK), VIDEO's SIZE, MATTE and SOUND, DEPTH's FAR and SMOOTH, and the sources' NAME. Give each phone its own NAME when you use several.

Nothing is worked on while no one watches: the source waits, ready, and the phone stays cool. SensorLove has to stay open on the screen, as iOS gives an app no camera in the background. DARK SCREEN turns the screen down to black while the sources go on; a tap wakes it.

VIDEO

DEPTH

In TouchDesigner

  1. NDI In TOP: pick the source; Input Pixel Format Native, Input Color Space Passthrough, Bandwidth High. Native keeps DEPTH's 16 bits.
  2. Each frame's metadata: an Info DAT on the NDI In TOP shows it as XML. An XML DAT turns it into attributes, a DAT to CHOP into channels.
  3. Metres: a GLSL TOP after it, Pixel Format 32-bit float, with the code below and uniforms uNear and uFar from the metadata (step 2). Nothing measured stays 0. With FAR EQ, the code is a table instead: eq holds 33 distances, and v between two of them is even in metres: s = (1 − v) × 32, then metres = eq[⌊s⌋] + (s − ⌊s⌋) × (eq[⌊s⌋+1] − eq[⌊s⌋]). In a GLSL TOP: put the 33 values in a uniform array (a CHOP of 33 samples), and do the same.
  4. A point cloud: the Palette's depthProjection, with Focal Lengths fx / w and fy / w and Optical Center cx / w and cy / h, from the metadata. If it comes out upside down, use 1 − cy / h.
uniform float uNear, uFar;
out vec4 fragColor;
void main() {
    float v = texelFetch(sTD2DInputs[0], ivec2(gl_FragCoord.xy), 0).r;   // the grey, 0 to 1
    float m = v > 0.0003 ? 1.0 / (1.0 / uFar + v * (1.0 / uNear - 1.0 / uFar)) : 0.0;
    fragColor = TDOutputSwizzle(vec4(m, m, m, 1.0));
}

Each frame's metadata

Every frame of both sources carries one element:

<sensorlove v="3" source="DEPTH" frame="18342" t="5321.204118" w="256" h="192" fx="211.3" fy="211.3" cx="127.6" cy="96.1" near="0.62" far="3.4" code="(1/m-1/far)/(1/near-1/far)" px="0.12" py="1.43" pz="-0.37" qx="0.01" qy="0.7" qz="0.02" qw="0.71"/>

Steady and fast