diff --git a/rpcs3/Emu/Cell/Modules/cellGem.cpp b/rpcs3/Emu/Cell/Modules/cellGem.cpp
index bfa72c30c6..85b03d2a90 100644
--- a/rpcs3/Emu/Cell/Modules/cellGem.cpp
+++ b/rpcs3/Emu/Cell/Modules/cellGem.cpp
@@ -232,7 +232,7 @@ public:
 		u8 rumble = 0;                                     // Rumble intensity
 		gem_color sphere_rgb = {};                         // RGB color of the sphere LED
 		u32 hue = 0;                                       // Tracking hue of the motion controller
-		f32 distance{1500.0f};                             // Distance from the camera in mm
+		f32 distance_mm{1500.0f};                          // Distance from the camera in mm
 		f32 radius{10.0f};                                 // Radius of the sphere in camera pixels
 		bool radius_valid = true;                          // If the radius and distance of the sphere was computed.
 
@@ -817,7 +817,7 @@ public:
 					{
 						// Only set new radius and distance if the radius is valid
 						controller.radius = info.radius;
-						controller.distance = info.distance;
+						controller.distance_mm = info.distance_mm;
 					}
 				}
 			}
@@ -894,8 +894,8 @@ static inline void pos_to_gem_image_state(u32 gem_num, const gem_config::gem_con
 	gem_image_state->v = image_y;
 
 	// Projected camera coordinates in mm
-	gem_image_state->projectionx = camera_x / controller.distance;
-	gem_image_state->projectiony = camera_y / controller.distance;
+	gem_image_state->projectionx = camera_x / controller.distance_mm;
+	gem_image_state->projectiony = camera_y / controller.distance_mm;
 
 	if (g_cfg.io.show_move_cursor)
 	{
@@ -929,7 +929,7 @@ static inline void pos_to_gem_state(u32 gem_num, const gem_config::gem_controlle
 	// World coordinates in mm
 	gem_state->pos[0] = camera_x;
 	gem_state->pos[1] = camera_y;
-	gem_state->pos[2] = static_cast<f32>(controller.distance);
+	gem_state->pos[2] = controller.distance_mm;
 	gem_state->pos[3] = 0.f;
 
 	gem_state->quat[0] = 320.f - image_x;
@@ -939,7 +939,7 @@ static inline void pos_to_gem_state(u32 gem_num, const gem_config::gem_controlle
 	// TODO: calculate handle position based on our world coordinate and the angles
 	gem_state->handle_pos[0] = camera_x;
 	gem_state->handle_pos[1] = camera_y;
-	gem_state->handle_pos[2] = static_cast<f32>(controller.distance + 10);
+	gem_state->handle_pos[2] = controller.distance_mm + 10.0f;
 	gem_state->handle_pos[3] = 0.f;
 
 	if (g_cfg.io.show_move_cursor)
@@ -1800,7 +1800,7 @@ error_code cellGemGetImageState(u32 gem_num, vm::ptr<CellGemImageState> gem_imag
 		gem_image_state->frame_timestamp = shared_data.frame_timestamp_us.load();
 		gem_image_state->timestamp = gem_image_state->frame_timestamp + 10;
 		gem_image_state->r = controller.radius; // Radius in camera pixels
-		gem_image_state->distance = controller.distance; // 1.5 meters away from camera
+		gem_image_state->distance = controller.distance_mm;
 		gem_image_state->visible = gem.is_controller_ready(gem_num);
 		gem_image_state->r_valid = controller.radius_valid;
 
diff --git a/rpcs3/Input/ps_move_tracker.cpp b/rpcs3/Input/ps_move_tracker.cpp
index 2e0d22ea05..fe49501334 100644
--- a/rpcs3/Input/ps_move_tracker.cpp
+++ b/rpcs3/Input/ps_move_tracker.cpp
@@ -408,9 +408,18 @@ void ps_move_tracker<DiagnosticsEnabled>::process_contours(ps_move_info& info, u
 	if (best_index == umax)
 		return;
 
+	// Calculate distance from sphere to camera
+	const f32 sphere_radius_pixels = radii[best_index];
+	constexpr f32 focal_length_mm = 3.5f; // Based on common webcam specs
+	constexpr f32 sensor_width_mm = 3.6f; // Based on common webcam specs
+	const f32 image_width_pixels = static_cast<float>(width);
+	const f32 focal_length_pixels = (focal_length_mm * image_width_pixels) / sensor_width_mm;
+	const f32 distance_mm = (focal_length_pixels * CELL_GEM_SPHERE_RADIUS_MM) / sphere_radius_pixels;
+
+	// Set results
 	info.valid = true;
-	info.distance = 1500.0f;
-	info.radius = radii[best_index];
+	info.distance_mm = distance_mm;
+	info.radius = sphere_radius_pixels;
 	info.x_pos = std::clamp(static_cast<u32>(centers[best_index].x), 0u, width);
 	info.y_pos = std::clamp(static_cast<u32>(centers[best_index].y), 0u, height);
 
diff --git a/rpcs3/Input/ps_move_tracker.h b/rpcs3/Input/ps_move_tracker.h
index 21c592b434..be1b598852 100644
--- a/rpcs3/Input/ps_move_tracker.h
+++ b/rpcs3/Input/ps_move_tracker.h
@@ -8,13 +8,13 @@
 
 struct ps_move_info
 {
-	bool valid = false;
-	f32 radius = 0.0f;
-	f32 distance = 0.0f;
-	u32 x_pos = 0;
-	u32 y_pos = 0;
-	u32 x_max = 0;
-	u32 y_max = 0;
+	bool valid = false;     // The tracking result
+	f32 radius = 0.0f;      // Radius of the sphere in pixels
+	f32 distance_mm = 0.0f; // Distance from sphere to camera in mm
+	u32 x_pos = 0;          // X position in pixels
+	u32 y_pos = 0;          // Y position in pixels
+	u32 x_max = 0;          // Maximum X position in pixels
+	u32 y_max = 0;          // Maximum Y position in pixels
 };
 
 template <bool DiagnosticsEnabled = false>