diff --git a/app/addons/xr-autohandtracker/auto_handtracker.gd b/app/addons/xr-autohandtracker/auto_handtracker.gd index 232a3d3..b80b1e5 100644 --- a/app/addons/xr-autohandtracker/auto_handtracker.gd +++ b/app/addons/xr-autohandtracker/auto_handtracker.gd @@ -2,39 +2,39 @@ extends Node3D # Settings that can be changed dynamically in the debugger to # see how they alter the mapping to the hand skeleton -@export var applymiddlefingerfix : bool = true -@export var applyscaling : bool = true -@export var coincidewristorknuckle : bool = true -@export var visiblehandtrackskeleton : bool = true -@export var enableautotracker : bool = true +@export var applymiddlefingerfix: bool = true +@export var applyscaling: bool = true +@export var coincidewristorknuckle: bool = true +@export var visiblehandtrackskeleton: bool = true +@export var enableautotracker: bool = true + +signal hand_active_changed(hand: int, active: bool) # Hand tracking data access object -var xr_interface : OpenXRInterface +var xr_interface: OpenXRInterface # Local origin for the hand tracking positions -var xr_origin : XROrigin3D +var xr_origin: XROrigin3D # Controller and its tracker with the aim pose that we can use when hand-tracking active -var xr_controller_node : XRController3D = null -var tracker_nhand : XRPositionalTracker.TrackerHand = XRPositionalTracker.TrackerHand.TRACKER_HAND_UNKNOWN -var xr_tracker : XRPositionalTracker = null -var xr_aimpose : XRPose = null -var xr_headtracker : XRPositionalTracker = null -var xr_camera_node : XRCamera3D = null - +var xr_controller_node: XRController3D = null +var tracker_nhand: XRPositionalTracker.TrackerHand = XRPositionalTracker.TrackerHand.TRACKER_HAND_UNKNOWN +var xr_tracker: XRPositionalTracker = null +var xr_aimpose: XRPose = null +var xr_headtracker: XRPositionalTracker = null +var xr_camera_node: XRCamera3D = null # Note the that the enumerations disagree # XRPositionalTracker.TrackerHand.TRACKER_HAND_LEFT = 1 # OpenXRInterface.Hand.HAND_LEFT = 0 -var hand : OpenXRInterface.Hand -var tracker_name : String +var hand: OpenXRInterface.Hand +var tracker_name: String var handtrackingactive = false var handnode = null var skel = null var handanimationtree = null - # values calculated from the hand skeleton itself var handtoskeltransform var wristboneindex @@ -50,23 +50,22 @@ static func basisfromA(a, v): return Basis(vx, vy, vz) static func rotationtoalignB(a, b, va, vb): - return basisfromA(b, vb)*basisfromA(a, va).inverse() + return basisfromA(b, vb) * basisfromA(a, va).inverse() static func rotationtoalignScaled(a, b): var axis = a.cross(b).normalized() - var sca = b.length()/a.length() + var sca = b.length() / a.length() if (axis.length_squared() != 0): - var dot = a.dot(b)/(a.length()*b.length()) + var dot = a.dot(b) / (a.length() * b.length()) dot = clamp(dot, -1.0, 1.0) var angle_rads = acos(dot) - return Basis(axis, angle_rads).scaled(Vector3(sca,sca,sca)) - return Basis().scaled(Vector3(sca,sca,sca)) - + return Basis(axis, angle_rads).scaled(Vector3(sca, sca, sca)) + return Basis().scaled(Vector3(sca, sca, sca)) func extractrestfingerbones(): print(handnode.name) var lr = "L" if hand == 0 else "R" - handtoskeltransform = handnode.global_transform.inverse()*skel.global_transform + handtoskeltransform = handnode.global_transform.inverse() * skel.global_transform wristboneindex = skel.find_bone("Wrist_" + lr) wristboneresttransform = skel.get_bone_rest(wristboneindex) hstw = handtoskeltransform * wristboneresttransform @@ -78,17 +77,16 @@ func extractrestfingerbones(): for b in ["Metacarpal", "Proximal", "Intermediate", "Distal", "Tip"]: var name = f + "_" + b + "_" + lr var ix = skel.find_bone(name) - if ix != -1: - fingerboneindexes[-1].push_back(ix) - fingerboneresttransforms[-1].push_back(skel.get_bone_rest(ix) if ix != -1 else null) + if ix != - 1: + fingerboneindexes[- 1].push_back(ix) + fingerboneresttransforms[- 1].push_back(skel.get_bone_rest(ix) if ix != - 1 else null) else: - assert (f == "Thumb" and b == "Intermediate") + assert(f == "Thumb" and b == "Intermediate") func _xr_controller_node_tracking_changed(tracking): var xr_pose = xr_controller_node.get_pose() print("_xr_controller_node_tracking_changed ", xr_pose.name if xr_pose else "") - func findxrnodes(): # first go up the tree to find the controller and origin var nd = self @@ -115,7 +113,7 @@ func findxrnodes(): # Finally decide if it is left or right hand and test consistency in the API var islefthand = (tracker_name == "left_hand") - assert (tracker_name == ("left_hand" if islefthand else "right_hand")) + assert(tracker_name == ("left_hand" if islefthand else "right_hand")) hand = OpenXRInterface.Hand.HAND_LEFT if islefthand else OpenXRInterface.Hand.HAND_RIGHT print("All nodes for %s detected" % tracker_name) @@ -149,18 +147,17 @@ func findxrtrackerobjects(): xr_tracker = XRServer.get_tracker(tracker_name) if xr_tracker == null: return - assert (xr_tracker.hand == tracker_nhand) + assert(xr_tracker.hand == tracker_nhand) print(xr_tracker.description, " ", xr_tracker.hand, " ", xr_tracker.name, " ", xr_tracker.profile, " ", xr_tracker.type) xr_headtracker = XRServer.get_tracker("head") var islefthand = (tracker_name == "left_hand") - assert (tracker_nhand == (XRPositionalTracker.TrackerHand.TRACKER_HAND_LEFT if islefthand else XRPositionalTracker.TrackerHand.TRACKER_HAND_RIGHT)) + assert(tracker_nhand == (XRPositionalTracker.TrackerHand.TRACKER_HAND_LEFT if islefthand else XRPositionalTracker.TrackerHand.TRACKER_HAND_RIGHT)) print(tracker_name, " ", tracker_nhand) print("action_sets: ", xr_interface.get_action_sets()) $AutoTracker.setupautotracker(tracker_nhand, islefthand, xr_controller_node) - func _ready(): findxrnodes() findxrtrackerobjects() @@ -173,7 +170,6 @@ func _ready(): findhandnodes() set_process(xr_interface != null) - func getoxrjointpositions(): var oxrjps = [ ] @@ -188,9 +184,9 @@ func getoxrjointrotations(): return oxrjrot func fixmiddlefingerpositions(oxrjps): - for j in [ OpenXRInterface.HAND_JOINT_MIDDLE_TIP, OpenXRInterface.HAND_JOINT_RING_TIP ]: + for j in [OpenXRInterface.HAND_JOINT_MIDDLE_TIP, OpenXRInterface.HAND_JOINT_RING_TIP]: var b = Basis(xr_interface.get_hand_joint_rotation(hand, j)) - oxrjps[j] += -0.01*b.y + 0.005*b.z + oxrjps[j] += - 0.01 * b.y + 0.005 * b.z func calchandnodetransform(oxrjps, xrt): # solve for handnodetransform where @@ -203,11 +199,11 @@ func calchandnodetransform(oxrjps, xrt): # and rotated so that the line between index and ring knuckles are in the same plane # We want skel.global_transform*wristboneresttransform to have origin xrorigintransform*gg[OpenXRInterface.HAND_JOINT_WRIST].origin - var wristorigin = xrt*oxrjps[OpenXRInterface.HAND_JOINT_WRIST] + var wristorigin = xrt * oxrjps[OpenXRInterface.HAND_JOINT_WRIST] - var middleknuckle = xrt*oxrjps[OpenXRInterface.HAND_JOINT_MIDDLE_PROXIMAL] - var leftknuckle = xrt*oxrjps[OpenXRInterface.HAND_JOINT_RING_PROXIMAL if hand == 0 else OpenXRInterface.HAND_JOINT_INDEX_PROXIMAL] - var rightknuckle = xrt*oxrjps[OpenXRInterface.HAND_JOINT_INDEX_PROXIMAL if hand == 0 else OpenXRInterface.HAND_JOINT_RING_PROXIMAL] + var middleknuckle = xrt * oxrjps[OpenXRInterface.HAND_JOINT_MIDDLE_PROXIMAL] + var leftknuckle = xrt * oxrjps[OpenXRInterface.HAND_JOINT_RING_PROXIMAL if hand == 0 else OpenXRInterface.HAND_JOINT_INDEX_PROXIMAL] + var rightknuckle = xrt * oxrjps[OpenXRInterface.HAND_JOINT_INDEX_PROXIMAL if hand == 0 else OpenXRInterface.HAND_JOINT_RING_PROXIMAL] var middlerestreltransform = fingerboneresttransforms[2][0] * fingerboneresttransforms[2][1] var leftrestreltransform = fingerboneresttransforms[3 if hand == 0 else 1][0] * fingerboneresttransforms[3 if hand == 0 else 1][1] @@ -217,34 +213,34 @@ func calchandnodetransform(oxrjps, xrt): var skelmiddleknuckle = handnode.transform * hstw * middlerestreltransform var m2g1g3 = leftrestreltransform.origin - rightrestreltransform.origin - var hnbasis = rotationtoalignB(hstw.basis*m2g1.origin, middleknuckle - wristorigin, - hstw.basis*m2g1g3, leftknuckle - rightknuckle) + var hnbasis = rotationtoalignB(hstw.basis * m2g1.origin, middleknuckle - wristorigin, + hstw.basis * m2g1g3, leftknuckle - rightknuckle) - var hnorigin = wristorigin - hnbasis*hstw.origin + var hnorigin = wristorigin - hnbasis * hstw.origin if not coincidewristorknuckle: - hnorigin = middleknuckle - hnbasis*(hstw*middlerestreltransform).origin + hnorigin = middleknuckle - hnbasis * (hstw * middlerestreltransform).origin return Transform3D(hnbasis, hnorigin) -const carpallist = [ OpenXRInterface.HAND_JOINT_THUMB_METACARPAL, - OpenXRInterface.HAND_JOINT_INDEX_METACARPAL, OpenXRInterface.HAND_JOINT_MIDDLE_METACARPAL, - OpenXRInterface.HAND_JOINT_RING_METACARPAL, OpenXRInterface.HAND_JOINT_LITTLE_METACARPAL ] +const carpallist = [OpenXRInterface.HAND_JOINT_THUMB_METACARPAL, + OpenXRInterface.HAND_JOINT_INDEX_METACARPAL, OpenXRInterface.HAND_JOINT_MIDDLE_METACARPAL, + OpenXRInterface.HAND_JOINT_RING_METACARPAL, OpenXRInterface.HAND_JOINT_LITTLE_METACARPAL] func calcboneposes(oxrjps, handnodetransform, xrt): var fingerbonetransformsOut = fingerboneresttransforms.duplicate(true) for f in range(5): var mfg = handnodetransform * hstw # (A.basis, A.origin) * (B.basis, B.origin) = (A.basis*B.basis, A.origin + A.basis*B.origin) - for i in range(len(fingerboneresttransforms[f])-1): - mfg = mfg*fingerboneresttransforms[f][i] + for i in range(len(fingerboneresttransforms[f]) - 1): + mfg = mfg * fingerboneresttransforms[f][i] # (tIbasis,atIorigin)*fingerboneresttransforms[f][i+1]).origin = mfg.inverse()*kpositions[f][i+1] # tIbasis*fingerboneresttransforms[f][i+1] = mfg.inverse()*kpositions[f][i+1] - atIorigin - var atIorigin = Vector3(0,0,0) - var kpositionsfip1 = xrt*oxrjps[carpallist[f] + i+1] - var tIbasis = rotationtoalignScaled(fingerboneresttransforms[f][i+1].origin, mfg.affine_inverse()*kpositionsfip1 - atIorigin) - var tIorigin = mfg.affine_inverse()*kpositionsfip1 - tIbasis*fingerboneresttransforms[f][i+1].origin # should be 0 + var atIorigin = Vector3(0, 0, 0) + var kpositionsfip1 = xrt * oxrjps[carpallist[f] + i + 1] + var tIbasis = rotationtoalignScaled(fingerboneresttransforms[f][i + 1].origin, mfg.affine_inverse() * kpositionsfip1 - atIorigin) + var tIorigin = mfg.affine_inverse() * kpositionsfip1 - tIbasis * fingerboneresttransforms[f][i + 1].origin # should be 0 var tI = Transform3D(tIbasis, tIorigin) - fingerbonetransformsOut[f][i] = fingerboneresttransforms[f][i]*tI - mfg = mfg*tI + fingerbonetransformsOut[f][i] = fingerboneresttransforms[f][i] * tI + mfg = mfg * tI return fingerbonetransformsOut func copyouttransformstoskel(fingerbonetransformsOut): @@ -258,17 +254,17 @@ func copyouttransformstoskel(fingerbonetransformsOut): skel.set_bone_pose_position(ix, t.origin) skel.set_bone_pose_scale(ix, t.basis.get_scale()) - func _process(delta): var handjointflagswrist = xr_interface.get_hand_joint_flags(hand, OpenXRInterface.HAND_JOINT_WRIST); - var lhandtrackingactive = (handjointflagswrist & OpenXRInterface.HAND_JOINT_POSITION_VALID) != 0 + var lhandtrackingactive = (handjointflagswrist&OpenXRInterface.HAND_JOINT_POSITION_VALID) != 0 if handtrackingactive != lhandtrackingactive: handtrackingactive = lhandtrackingactive handnode.top_level = handtrackingactive if handanimationtree: handanimationtree.active = not handtrackingactive - print("setting hand "+str(hand)+" active: ", handtrackingactive) + print("setting hand " + str(hand) + " active: ", handtrackingactive) + hand_active_changed.emit(hand, handtrackingactive) $VisibleHandTrackSkeleton.visible = visiblehandtrackskeleton and handtrackingactive if handtrackingactive: if enableautotracker: @@ -297,6 +293,3 @@ func _process(delta): print("...xr_aimpose ", xr_aimpose) if xr_aimpose != null and $AutoTracker.autotrackeractive: $AutoTracker.xr_autotracker.set_pose(xr_controller_node.pose, xr_aimpose.transform, xr_aimpose.linear_velocity, xr_aimpose.angular_velocity, xr_aimpose.tracking_confidence) - - - diff --git a/app/content/main.tscn b/app/content/main.tscn index 34c071e..91b4f1e 100644 --- a/app/content/main.tscn +++ b/app/content/main.tscn @@ -42,6 +42,9 @@ transform = Transform3D(0.967043, 0.24582, -0.0663439, -0.0663439, 0.494837, 0.8 [node name="MiddleTip" parent="XROrigin3D/XRControllerLeft" index="8"] transform = Transform3D(0.98042, 0.196912, 0.00149799, 0.001498, -0.015065, 0.999885, 0.196912, -0.980305, -0.0150651, -0.00327212, -0.00771427, -0.176318) +[node name="Palm" parent="XROrigin3D/XRControllerLeft" index="9"] +transform = Transform3D(1, 3.12361e-06, -3.13859e-06, -3.12371e-06, 1, -1.97886e-05, 3.13859e-06, 1.97889e-05, 1, 0.0307807, -0.0419722, -0.0399505) + [node name="XRControllerRight" parent="XROrigin3D" instance=ExtResource("7_0b3tc")] transform = Transform3D(0.999999, -1.39635e-11, 0, 1.31553e-10, 1, 0, 0, 0, 1, 0.336726, 0.575093, -0.437942) diff --git a/app/content/system/controller_left/controller_left.gd b/app/content/system/controller_left/controller_left.gd index 7d7e4fa..f7aea0b 100644 --- a/app/content/system/controller_left/controller_left.gd +++ b/app/content/system/controller_left/controller_left.gd @@ -11,6 +11,7 @@ const Miniature = preload ("res://content/system/house/mini/miniature.gd") @onready var main = $"/root/Main" @onready var hand = $hand_l @onready var hand_mesh = $hand_l/Armature/Skeleton3D/mesh_Hand_L +@onready var auto_hand = $AutoHandtracker @onready var index_tip = $IndexTip @onready var thumb_tip = $ThumbTip @@ -27,6 +28,7 @@ const Miniature = preload ("res://content/system/house/mini/miniature.gd") @onready var animation = $AnimationPlayer @onready var quick_actions = $Palm/QuickActions +var hand_active = false var initiator: Initiator = Initiator.new() var collide: Collide var pointer: Pointer @@ -103,12 +105,18 @@ func _ready(): ) func _process(_delta): + if !hand_active: + if quick_actions.is_inside_tree(): palm.remove_child(quick_actions) + return + if main.camera.global_transform.basis.z.dot(palm.global_transform.basis.x) > 0.85: if quick_actions.is_inside_tree() == false: palm.add_child(quick_actions) else: if quick_actions.is_inside_tree(): palm.remove_child(quick_actions) func _physics_process(_delta): + if !hand_active: return + var distance_trigger = index_tip.global_position.distance_to(thumb_tip.global_position) var distance_grab = middle_tip.global_position.distance_to(thumb_tip.global_position) @@ -144,6 +152,15 @@ func _setup_hand(): collide = Collide.new(hand, hand_mesh, index_tip) add_child(collide) + auto_hand.hand_active_changed.connect(func(hand: int, active: bool): + if hand != 0: return + + hand_active=active + + $IndexTip/TouchArea/CollisionShape3D.disabled=!active + hand_mesh.visible=active + ) + mini_view_button.on_button_up.connect(func(): House.body.mini_view.small.value=!House.body.mini_view.small.value ) diff --git a/app/content/system/controller_right/controller_right.gd b/app/content/system/controller_right/controller_right.gd index 88e4df1..f63b690 100644 --- a/app/content/system/controller_right/controller_right.gd +++ b/app/content/system/controller_right/controller_right.gd @@ -11,11 +11,13 @@ const Miniature = preload ("res://content/system/house/mini/miniature.gd") @onready var ray: RayCast3D = $Raycast @onready var hand: Node3D = $hand_r @onready var hand_mesh = $hand_r/Armature/Skeleton3D/mesh_Hand_R +@onready var auto_hand = $AutoHandtracker @onready var index_tip = $IndexTip @onready var thumb_tip = $ThumbTip @onready var middle_tip = $MiddleTip +var hand_active = false var initiator: Initiator = Initiator.new() var collide: Collide var pointer: Pointer @@ -37,7 +39,18 @@ func _ready(): pointer = Pointer.new(initiator, ray) add_child(pointer) + auto_hand.hand_active_changed.connect(func(hand: int, active: bool): + if hand != 1: return + + hand_active=active + + $IndexTip/TouchArea/CollisionShape3D.disabled=!active + hand_mesh.visible=active + ) + func _physics_process(_delta): + if !hand_active: return + var distance_trigger = index_tip.global_position.distance_to(thumb_tip.global_position) var distance_grab = middle_tip.global_position.distance_to(thumb_tip.global_position)