FreeD Link
FreeD Link is a Blender add-on that drives Blender cameras from live FreeD D1 camera tracking over UDP. It maps position, rotation, zoom and focus, records keyframes while the timeline plays, and has a built-in simulator so you can test without hardware. FreeD Out sends a Blender camera as FreeD the other way.
Requires Blender 4.2 or newer, including 5.x.
Supported sources
Any device or software that sends FreeD D1 packets over UDP, for example:
- Mo-Sys, Stype, Ncam and EZtrack trackers
- Vinten and Camera Corps robotic heads
- Panasonic AW-UE PTZ cameras
- Sony and Canon PTZ cameras with FreeD output
- Other virtual-production trackers with a FreeD D1 output
FreeD Link reads only the D1 message. It does not support proprietary tracking protocols.
Install
- In Blender, open Edit > Preferences > Get Extensions.
- Open the drop-down menu at the top right and choose Install from Disk.
- Select the FreeD Link
.zip.
The panel is in the 3D Viewport sidebar (press N), on the FreeD tab.
Quick start
- Click Start. If the Cameras list is empty, FreeD Link adds a mapping from FreeD ID 1 to the scene camera.
- Open Test Signal and click Start Simulator. The scene camera orbits the origin at 4 m radius and 1.6 m height, looking at the origin.
- Click Stop Simulator, point your tracker at this computer's IP on port 20000, and check the status box for a line such as
ID 1: 50 packets/s. - In Cameras, set each row's ID to the FreeD ID your tracker sends and pick the Blender camera. Use + to add a row per tracked camera; with a camera selected in the viewport, + maps it.
The status box shows the listen address, one line per camera ID with its packets per second, and counts of bad checksums and non-D1 packets. A camera ID with no packets for Stale After seconds shows as lost, and its camera stops moving until packets return.
Changes to Interface and Port apply on the next Start.
Axes
Open Axes and move the real camera to check each direction.
| Setting | Use |
|---|---|
| Position Scale | Blender units per FreeD millimetre. Default 0.001 gives metres. |
| Pan 0 Faces | The Blender axis the camera looks along at pan 0. Default +Y. |
| -X, -Y, -Z | Invert a position axis. |
| X/Y | Swap the X and Y position axes. |
| -Pan, -Tilt, -Roll | Invert a rotation. |
| Smoothing | 0 is raw. Higher values remove jitter and add lag. Maximum 0.95. |
| Delay (ms) | Holds tracking back to match delayed video. Maximum 2000 ms. |
| Stale After (s) | A camera ID with no packets for this long shows as lost. Default 1 s. |
| Ignore Checksum | On by default. Applies packets with a wrong checksum byte; some devices send 0. |
| Raw Values as Custom Properties | Writes freed_pan, freed_tilt, freed_roll (degrees) and freed_zoom, freed_focus (raw encoder) to the camera object for drivers. |
Tracker origin
FreeD Link writes the tracker's pose into the camera's own location and rotation. An unparented camera therefore sits at the tracker's pose in world space. To move or rotate the tracking origin, parent the camera to an Empty: the Empty is the tracker origin and the camera follows it (the parent inverse is reset to identity when tracking starts).
PTZ cameras usually send position 0, so the camera sits at its parent Empty, or at the Blender origin without one. Place the Empty where the PTZ head is.
Lens calibration
Zoom and focus arrive as raw encoder values. Calibration tables convert them to focal length (mm) and focus distance (m), with linear interpolation between rows. Each camera in Cameras has its own tables, because each lens has its own encoder range. Rows are sorted by raw value automatically. Outside the table, the nearest row's value is used.
- Click Start and make sure tracking is arriving.
- Select the camera's row in Cameras. Lens shows that camera's tables and reads live values from its FreeD ID.
- Open Lens and enable Drive Focal Length.
- Zoom the real lens fully wide. Click + to add a row. It takes the live raw value. Type the focal length.
- Zoom fully tight. Click + and type the focal length.
- Repeat at 1 to 3 points in between, so you have 3 to 5 rows.
Repeat for each tracked camera.
To re-read the live encoder into the selected row, click the eyedropper (Capture Raw).
Type the focal length that makes the Blender view match the real picture, with the Blender camera's sensor size set to the real camera's sensor.
Focus works the same way: enable Drive Focus Distance, rack focus to marks at known distances, and type each distance in metres. Enable Enable Depth of Field to switch on depth of field on the camera.
Recording
- Click Start.
- Click Record. It changes to Recording.
- Press Play on the timeline.
On every frame, FreeD Link applies the newest packet and writes keyframes for each camera that received packets. Transform keys location and rotation. Lens keys focal length and focus distance, when they are driven. Click Recording again, or Stop, to end the take.
With Stop at Frame End on (the default), the take ends and playback stops at the scene's end frame, or at the preview range end when a preview range is set. A take also ends whenever the frame moves backwards, so a looping timeline never overwrites the keys it just wrote. Turn the option off only to record past the end frame on an extended timeline.
Ending a take pauses live tracking, so you can play back and review the recorded keys. FreeD Link keeps listening. Click Go Live to drive the cameras again.
While recording, any frame change writes keys, including scrubbing. Turn recording off before scrubbing.
FreeD Out
FreeD Out sends a Blender camera's pose as FreeD D1 packets over UDP, so an animated or hand-moved Blender camera can drive Unreal Engine, Aximmetry, Vizrt or another FreeD Link.
| Setting | Use |
|---|---|
| Host, Port | Destination IP or host name and UDP port. Default 127.0.0.1:20001. |
| Rate (Hz) | Packets per second. Default 50. |
| FreeD ID | Camera id byte in each packet. |
| Camera | Camera to send. Empty sends the scene camera. |
| Zoom/Focus From Lens Tables | Converts focal length and focus distance back to raw values through that camera's tables in Lens. Without a table, or with this off, it sends the camera's freed_zoom and freed_focus custom properties, or 0. |
Click Start Sending. The status box shows Sending to host:port and Sent 50/s. A background thread sends at the set rate even while the viewport is busy, repeating the latest pose when the camera is still, as trackers do. The pose is updated on every frame change, so playback and scrubbing reach the receiver at once.
Packets use the Axes settings in reverse, so a receiver with the same settings reproduces the camera exactly. A parented camera is sent relative to its parent, the tracker origin. Changes to Host and Port apply on the next Start Sending.
FreeD Link refuses to send to 127.0.0.1 on the port its own receiver listens on, to avoid a feedback loop.
To test with the built-in receiver, open a second Blender, set Port to 20001 and click Start. In the first Blender, open FreeD Out, keep 127.0.0.1:20001 and click Start Sending. The second Blender shows ID 1: 50 packets/s and its camera follows the first one's.
Networking
- Default port is UDP 20000. Set the same port on the tracker.
- Allow inbound UDP on that port for Blender in your firewall. On Windows, accept the prompt on first Start.
- Interface
0.0.0.0listens on all network interfaces. Enter one of this computer's IP addresses to listen only on that network, for example a dedicated tracking network. - The simulator sends to
127.0.0.1. It reaches FreeD Link only when Interface is0.0.0.0or127.0.0.1. - Send to this computer's unicast IP. Multicast is not supported.
- Datagrams holding several D1 packets are supported. Each camera ID is handled separately.
- Only one program can receive a given port. Close other software listening on the same port.
Command-line test sender
freed_sender.py in the extension folder sends test packets from any computer with Python 3, without Blender. Copy the whole freed_link folder to use it elsewhere:
python3 -I freed_link/freed_sender.py --host 192.168.1.20 --port 20000 --rate 50 --id 1 --seconds 30
python3 -I freed_link/freed_sender.py --static --pan 45 --tilt -10 --z 1600 --zoom 524288
Without --static it sends the orbiting camera. --seconds 0 runs until Ctrl+C. Static pose units are degrees, millimetres and raw encoder values.
Troubleshooting
| Symptom | Fix |
|---|---|
No packets yet or lost | Check the tracker's destination IP and port, the firewall, and Interface. |
Cannot listen on ... when starting | The port is in use, or Interface is not an address of this computer. |
| Packets arrive but the camera does not move | If the button reads Go Live, click it. In Cameras, check the row is enabled, its ID has a line in the status box, and a camera is set. |
Bad checksum rises and the camera does not move | Enable Ignore Checksum. |
Ignored non-D1 rises | Set the device to output FreeD D1. |
| Simulator does not move the camera | Click Start as well, and set Interface to 0.0.0.0. |
| Camera pans the wrong way | Toggle -Pan. |
| Camera faces the wrong way at pan 0 | Change Pan 0 Faces. |
| Camera moves along the wrong axis | Use X/Y, -X, -Y, -Z. |
| Movement is 1000 times too big or small | Set Position Scale to 0.001 (FreeD millimetres to metres). |
| Jitter | Raise Smoothing, starting at 0.3. |
| Graphics move before the video | Raise Delay (ms) until they line up. |
| Focal length does not change | Select the camera's row in Cameras, then in Lens enable Drive Focal Length and add at least one row. |
| Recording writes no keys | Check the button reads Recording, the camera's ID is receiving packets, then press Play. |
| Recording stops at the last frame | Stop at Frame End is on. Extend the frame range or turn it off. |
| Gaps between recorded keys | Playback dropped frames. Those frames are interpolated. |
License
GPL-3.0-or-later. See LICENSE. The extension zip includes the license text.
Copyright 2026 Bjorn Schobben.