Using the Tangible Tracking Camera

The Tilt Five glasses have a IR camera that can be used for image recognition tasks. This could be used to recognize physical game pieces like cards or figures.

This camera can be accessed by adding a T5ImageCapture node to the T5XRRig as a child of the T5Origin node. You will need to create a custom version of T5XRRig and set it as the default rig in the T5Manager. See Tilt Five Godot 4 for more information about customizing the XRRig. Also the default projects from the github pagehave examples.

Here is a T5XRRig with the image capture setup.
T5ImageCaptureScene.png

T5ImageCapture API

  • bool start_capture() Turns the camera on and begins capturing frames. Returns true if the camera was successfully enabled.
  • void stop_capture() Turns the camera off and stops capturing frames.
  • bool acquire_buffer() Returns true if there an image ready to be read. Note that if true is returned release_buffer() must be called when done reading the data.
  • void release_buffer() Call this when finished reading the image frame data. Failure to call this function will cause the system to run out of image buffers and stop receiving camera data. 
  • Vector2i get_image_size() the height and width of the image in pixels.
  • PackedByteArray get_image_data() get the byte array containing the image data. The image is a 8 bit per pixel gray scale image. The size of the buffer should be height X width bytes.
  • Transform3D get_camera_transform() This is the pose of the camera when the image was captured. The pose is relative to the T5Origin node. To obtain the pose in world coordinates use the global_transform of the T5ImageCapture node.

Example

Here is example code using the API. Notice that it's using Image.FORMAT_R8 because the image is single channel.

extends Node3D

var image_capture: T5ImageCapture
var is_capturing := false
var image_size: Vector2i
var camera_image: Image
@onready var camera_view: TextureRect = $ScreenUI/CameraView

# Grab the T5ImageCapture out of the xr rig
func _on_t_5_manager_xr_rig_was_added(xr_rig: T5XRRig):
	var new_image_capture = xr_rig.get_image_capture()
	if not image_capture and new_image_capture:
		image_capture = new_image_capture
	
func _on_t_5_manager_xr_rig_will_be_removed(xr_rig):
	var old_image_capture = xr_rig.get_image_capture()
	if image_capture and image_capture == old_image_capture:
		if is_capturing:
			image_capture.stop_capture()
			is_capturing = false
		camera_view.visible = false
		image_capture = null

# Toggle the camera on and off
func _input(event):
	if image_capture == null:
		return
	if not event.is_action_pressed("toggle_camera"):
		return
	if not is_capturing and image_capture.start_capture():
		is_capturing = true
		camera_view.visible = true
	else:
		image_capture.stop_capture()
		is_capturing = false
		camera_view.visible = false

func _process(_delta):
	if not is_capturing:
		return
	# Test to see if a image buffer is available
	if image_capture.acquire_buffer():
		# get the image data
		var buffer := image_capture.get_image_data()
		# Get the size
		var new_size = image_capture.get_image_size()
		# If is the first time or the size has changed
		if camera_image == null or image_size != new_size:
			image_size = new_size
			camera_image = Image.create_from_data(image_size.x, image_size.y, false, Image.FORMAT_R8, buffer)
			camera_view.texture = ImageTexture.create_from_image(camera_image)
		else:
			camera_image.set_data(image_size.x, image_size.y, false, Image.FORMAT_R8, buffer)
			camera_view.texture.update(camera_image)
		image_capture.release_buffer()