From 89abe2915ca81be4500d19a2728ee46624c9d6a4 Mon Sep 17 00:00:00 2001 From: Nitwel Date: Mon, 6 May 2024 18:22:12 +0200 Subject: [PATCH] update hands to look a lot better --- .../xr-autohandtracker/auto_handtracker.gd | 302 ++++++++++++++++++ .../xr-autohandtracker/auto_handtracker.tscn | 130 ++++++++ app/addons/xr-autohandtracker/auto_tracker.gd | 215 +++++++++++++ .../visible_handtrack_skeleton.gd | 60 ++++ app/assets/materials/hands.gdshader | 25 ++ app/assets/models/hands/Hand_low_L.gltf | 3 + .../models/hands/Hand_low_L.gltf.import | 34 ++ app/assets/models/hands/Hand_low_R.gltf | 3 + .../models/hands/Hand_low_R.gltf.import | 34 ++ app/content/entities/timer/timer.tscn | 8 +- app/content/main.tscn | 32 +- .../system/controller_left/controller_left.gd | 91 +++++- .../controller_left/controller_left.tscn | 93 +++++- .../controller_right/controller_right.gd | 59 ++++ .../controller_right/controller_right.tscn | 80 +++++ .../controller_right/hands_material.tres | 8 + app/content/system/hands/hands.gd | 89 ++++-- app/content/system/hands/hands.tscn | 60 +--- app/lib/home_apis/hass_ws/handlers/history.gd | 2 +- app/lib/utils/touch/collide.gd | 42 +-- app/lib/utils/touch/touch.gd | 22 +- app/project.godot | 1 + 22 files changed, 1248 insertions(+), 145 deletions(-) create mode 100644 app/addons/xr-autohandtracker/auto_handtracker.gd create mode 100644 app/addons/xr-autohandtracker/auto_handtracker.tscn create mode 100644 app/addons/xr-autohandtracker/auto_tracker.gd create mode 100644 app/addons/xr-autohandtracker/visible_handtrack_skeleton.gd create mode 100644 app/assets/materials/hands.gdshader create mode 100644 app/assets/models/hands/Hand_low_L.gltf create mode 100644 app/assets/models/hands/Hand_low_L.gltf.import create mode 100644 app/assets/models/hands/Hand_low_R.gltf create mode 100644 app/assets/models/hands/Hand_low_R.gltf.import create mode 100644 app/content/system/controller_right/controller_right.gd create mode 100644 app/content/system/controller_right/controller_right.tscn create mode 100644 app/content/system/controller_right/hands_material.tres diff --git a/app/addons/xr-autohandtracker/auto_handtracker.gd b/app/addons/xr-autohandtracker/auto_handtracker.gd new file mode 100644 index 0000000..232a3d3 --- /dev/null +++ b/app/addons/xr-autohandtracker/auto_handtracker.gd @@ -0,0 +1,302 @@ +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 + +# Hand tracking data access object +var xr_interface : OpenXRInterface + +# Local origin for the hand tracking positions +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 + + +# 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 handtrackingactive = false + +var handnode = null +var skel = null +var handanimationtree = null + + +# values calculated from the hand skeleton itself +var handtoskeltransform +var wristboneindex +var wristboneresttransform +var hstw +var fingerboneindexes +var fingerboneresttransforms + +static func basisfromA(a, v): + var vx = a.normalized() + var vy = vx.cross(v.normalized()) + var vz = vx.cross(vy) + return Basis(vx, vy, vz) + +static func rotationtoalignB(a, b, va, vb): + 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() + if (axis.length_squared() != 0): + 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)) + + +func extractrestfingerbones(): + print(handnode.name) + var lr = "L" if hand == 0 else "R" + handtoskeltransform = handnode.global_transform.inverse()*skel.global_transform + wristboneindex = skel.find_bone("Wrist_" + lr) + wristboneresttransform = skel.get_bone_rest(wristboneindex) + hstw = handtoskeltransform * wristboneresttransform + fingerboneindexes = [ ] + fingerboneresttransforms = [ ] + for f in ["Thumb", "Index", "Middle", "Ring", "Little"]: + fingerboneindexes.push_back([ ]) + fingerboneresttransforms.push_back([ ]) + 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) + else: + 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 + while nd != null and not (nd is XRController3D): + nd = nd.get_parent() + if nd == null: + print("Warning, no controller node detected") + return false + xr_controller_node = nd + tracker_nhand = xr_controller_node.get_tracker_hand() + tracker_name = xr_controller_node.tracker + xr_controller_node.tracking_changed.connect(_xr_controller_node_tracking_changed) + while nd != null and not (nd is XROrigin3D): + nd = nd.get_parent() + if nd == null: + print("Warning, no xrorigin node detected") + return false + xr_origin = nd + + # Then look for the hand skeleton that we are going to map to + for cch in xr_origin.get_children(): + if cch is XRCamera3D: + xr_camera_node = cch + + # 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")) + hand = OpenXRInterface.Hand.HAND_LEFT if islefthand else OpenXRInterface.Hand.HAND_RIGHT + + print("All nodes for %s detected" % tracker_name) + return true + +func findhandnodes(): + if xr_controller_node == null: + return + for ch in xr_controller_node.get_children(): + var lskel = ch.find_child("Skeleton3D") + if lskel: + if lskel.get_bone_count() == 26: + handnode = ch + else: + print("unrecognized skeleton in controller") + if handnode == null: + print("Warning, no handnode (mesh and animationtree) detected") + return false + skel = handnode.find_child("Skeleton3D") + if skel == null: + print("Warning, no Skeleton3D found") + return false + handanimationtree = handnode.get_node_or_null("AnimationTree") + extractrestfingerbones() + +func findxrtrackerobjects(): + xr_interface = XRServer.find_interface("OpenXR") + if xr_interface == null: + return + var tracker_name = xr_controller_node.tracker + xr_tracker = XRServer.get_tracker(tracker_name) + if xr_tracker == null: + return + 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)) + 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() + + # As a transform we are effectively reparenting ourselves directly under the XROrigin3D + if xr_origin != null: + var rt = RemoteTransform3D.new() + rt.remote_path = get_path() + xr_origin.add_child.call_deferred(rt) + + findhandnodes() + set_process(xr_interface != null) + + +func getoxrjointpositions(): + var oxrjps = [ ] + for j in range(OpenXRInterface.HAND_JOINT_MAX): + oxrjps.push_back(xr_interface.get_hand_joint_position(hand, j)) + return oxrjps + +func getoxrjointrotations(): + var oxrjrot = [ ] + for j in range(OpenXRInterface.HAND_JOINT_MAX): + oxrjrot.push_back(xr_interface.get_hand_joint_rotation(hand, j)) + return oxrjrot + +func fixmiddlefingerpositions(oxrjps): + 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 + +func calchandnodetransform(oxrjps, xrt): + # solve for handnodetransform where + # avatarwristtrans = handnode.get_parent().global_transform * handnodetransform * handtoskeltransform * wristboneresttransform + # avatarwristpos = avatarwristtrans.origin + # avatarmiddleknucklepos = avatarwristtrans * fingerboneresttransforms[2][0] * fingerboneresttransforms[2][1] + # handwrist = xrorigintransform * oxrjps[OpenXRInterface.HAND_JOINT_WRIST] + # handmiddleknuckle = xrorigintransform * oxrjps[OpenXRInterface.HAND_JOINT_MIDDLE_PROXIMAL] + # so that avatarwristpos->avatarmiddleknucklepos is aligned along handwrist->handmiddleknuckle + # 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 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] + var rightrestreltransform = fingerboneresttransforms[1 if hand == 0 else 3][0] * fingerboneresttransforms[1 if hand == 0 else 3][1] + + var m2g1 = middlerestreltransform + 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 hnorigin = wristorigin - hnbasis*hstw.origin + if not coincidewristorknuckle: + 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 ] +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] + # (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 tI = Transform3D(tIbasis, tIorigin) + fingerbonetransformsOut[f][i] = fingerboneresttransforms[f][i]*tI + mfg = mfg*tI + return fingerbonetransformsOut + +func copyouttransformstoskel(fingerbonetransformsOut): + for f in range(len(fingerboneindexes)): + for i in range(len(fingerboneindexes[f])): + var ix = fingerboneindexes[f][i] + var t = fingerbonetransformsOut[f][i] + skel.set_bone_pose_rotation(ix, t.basis.get_rotation_quaternion()) + if not applyscaling: + t = fingerboneresttransforms[f][i] + 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 + + if handtrackingactive != lhandtrackingactive: + handtrackingactive = lhandtrackingactive + handnode.top_level = handtrackingactive + if handanimationtree: + handanimationtree.active = not handtrackingactive + print("setting hand "+str(hand)+" active: ", handtrackingactive) + $VisibleHandTrackSkeleton.visible = visiblehandtrackskeleton and handtrackingactive + if handtrackingactive: + if enableautotracker: + $AutoTracker.activateautotracker(xr_controller_node) + else: + if $AutoTracker.autotrackeractive: + $AutoTracker.deactivateautotracker(xr_controller_node, xr_tracker) + handnode.transform = Transform3D() + + if handtrackingactive: + var oxrjps = getoxrjointpositions() + var xrt = xr_origin.global_transform + if $AutoTracker.autotrackeractive: + $AutoTracker.autotrackgestures(oxrjps, xrt, xr_camera_node) + if applymiddlefingerfix: + fixmiddlefingerpositions(oxrjps) + var handnodetransform = calchandnodetransform(oxrjps, xrt) + var fingerbonetransformsOut = calcboneposes(oxrjps, handnodetransform, xrt) + handnode.transform = handnodetransform + copyouttransformstoskel(fingerbonetransformsOut) + if visible and $VisibleHandTrackSkeleton.visible: + var oxrjrot = getoxrjointrotations() + $VisibleHandTrackSkeleton.updatevisiblehandskeleton(oxrjps, oxrjrot, xrt) + if xr_aimpose == null: + xr_aimpose = xr_tracker.get_pose("aim") + 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/addons/xr-autohandtracker/auto_handtracker.tscn b/app/addons/xr-autohandtracker/auto_handtracker.tscn new file mode 100644 index 0000000..93b9e2b --- /dev/null +++ b/app/addons/xr-autohandtracker/auto_handtracker.tscn @@ -0,0 +1,130 @@ +[gd_scene load_steps=20 format=3 uid="uid://bufelcry36rw1"] + +[ext_resource type="Script" path="res://addons/xr-autohandtracker/auto_handtracker.gd" id="1_kokq6"] +[ext_resource type="Script" path="res://addons/xr-autohandtracker/visible_handtrack_skeleton.gd" id="2_51p5j"] +[ext_resource type="Script" path="res://addons/xr-autohandtracker/auto_tracker.gd" id="3_6kyde"] + +[sub_resource type="BoxMesh" id="BoxMesh_lsd0h"] +size = Vector3(0.1, 0.8, 0.1) + +[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_dawss"] +albedo_color = Color(0.6842, 0.671572, 0.696409, 1) + +[sub_resource type="BoxMesh" id="BoxMesh_h2ysa"] +size = Vector3(0.8, 0.8, 0.8) + +[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_kb47o"] +albedo_color = Color(0.188235, 0.6, 0.00392157, 1) + +[sub_resource type="CylinderMesh" id="CylinderMesh_ga8xh"] +top_radius = 0.2 +bottom_radius = 0.4 +height = 1.0 + +[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_2y0qr"] +albedo_color = Color(0, 0.470588, 0.698039, 1) + +[sub_resource type="TorusMesh" id="TorusMesh_r0bsl"] +inner_radius = 0.19 +outer_radius = 0.2 + +[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_r0qnr"] +transparency = 1 +albedo_color = Color(1, 1, 0.00784314, 1) + +[sub_resource type="TorusMesh" id="TorusMesh_wsh6v"] +inner_radius = 0.59 +outer_radius = 0.6 + +[sub_resource type="CylinderMesh" id="CylinderMesh_pce3n"] +top_radius = 0.05 +bottom_radius = 0.05 +height = 0.002 + +[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_2wqtw"] +transparency = 1 +shading_mode = 0 +albedo_color = Color(1, 1, 0.00784314, 0.235294) +disable_receive_shadows = true + +[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_53tyc"] +transparency = 1 +shading_mode = 0 +albedo_color = Color(1, 1, 0.00784314, 0.235294) +disable_receive_shadows = true + +[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_f71oj"] +albedo_color = Color(1, 1, 0, 1) + +[sub_resource type="BoxMesh" id="BoxMesh_epivk"] +material = SubResource("StandardMaterial3D_f71oj") +size = Vector3(0.01, 0.02, 0.01) + +[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_fvumm"] +albedo_color = Color(1, 0.0431373, 0, 1) + +[sub_resource type="BoxMesh" id="BoxMesh_ssbes"] +material = SubResource("StandardMaterial3D_fvumm") +size = Vector3(0.005, 0.19, 0.005) + +[node name="AutoHandtracker" type="Node3D"] +top_level = true +script = ExtResource("1_kokq6") + +[node name="VisibleHandTrackSkeleton" type="Node3D" parent="."] +visible = false +script = ExtResource("2_51p5j") + +[node name="ExampleStick" type="Node3D" parent="VisibleHandTrackSkeleton"] + +[node name="StemY" type="MeshInstance3D" parent="VisibleHandTrackSkeleton/ExampleStick"] +mesh = SubResource("BoxMesh_lsd0h") +surface_material_override/0 = SubResource("StandardMaterial3D_dawss") + +[node name="ExampleJoint" type="Node3D" parent="VisibleHandTrackSkeleton"] + +[node name="Box" type="MeshInstance3D" parent="VisibleHandTrackSkeleton/ExampleJoint"] +mesh = SubResource("BoxMesh_h2ysa") +surface_material_override/0 = SubResource("StandardMaterial3D_kb47o") + +[node name="AutoTracker" type="Node3D" parent="."] +script = ExtResource("3_6kyde") + +[node name="DragRod" type="MeshInstance3D" parent="AutoTracker"] +transform = Transform3D(-8.74228e-09, -1, 0, 0.2, -4.37114e-08, 0, 0, 0, 0.2, -0.5, 0, 0) +mesh = SubResource("CylinderMesh_ga8xh") +surface_material_override/0 = SubResource("StandardMaterial3D_2y0qr") + +[node name="ThumbstickBoundaries" type="Node3D" parent="AutoTracker"] + +[node name="InnerRing" type="MeshInstance3D" parent="AutoTracker/ThumbstickBoundaries"] +mesh = SubResource("TorusMesh_r0bsl") +skeleton = NodePath("../..") +surface_material_override/0 = SubResource("StandardMaterial3D_r0qnr") + +[node name="OuterRing" type="MeshInstance3D" parent="AutoTracker/ThumbstickBoundaries"] +mesh = SubResource("TorusMesh_wsh6v") +skeleton = NodePath("../..") +surface_material_override/0 = SubResource("StandardMaterial3D_r0qnr") + +[node name="UpDisc" type="MeshInstance3D" parent="AutoTracker/ThumbstickBoundaries"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.5, 0) +cast_shadow = 0 +mesh = SubResource("CylinderMesh_pce3n") +skeleton = NodePath("../..") +surface_material_override/0 = SubResource("StandardMaterial3D_2wqtw") + +[node name="DownDisc" type="MeshInstance3D" parent="AutoTracker/ThumbstickBoundaries"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.5, 0) +cast_shadow = 0 +mesh = SubResource("CylinderMesh_pce3n") +skeleton = NodePath("../..") +surface_material_override/0 = SubResource("StandardMaterial3D_53tyc") + +[node name="GraspMarker" type="MeshInstance3D" parent="AutoTracker"] +mesh = SubResource("BoxMesh_epivk") +skeleton = NodePath("../..") + +[node name="ControllerMarker" type="MeshInstance3D" parent="AutoTracker"] +mesh = SubResource("BoxMesh_ssbes") +skeleton = NodePath("../..") diff --git a/app/addons/xr-autohandtracker/auto_tracker.gd b/app/addons/xr-autohandtracker/auto_tracker.gd new file mode 100644 index 0000000..e4100cc --- /dev/null +++ b/app/addons/xr-autohandtracker/auto_tracker.gd @@ -0,0 +1,215 @@ +extends Node3D + +# The autotracker is swapped onto the xr_controller_node when hand-tracking is active +# so that we can insert in our own button and float signals from the hand gestures, +# as well as setting the pose from the xr_aimpose (which is filtered by the system during hand tracking) +# Calling set_pose emits a pose_changed signal that copies its values into the xr_controller_node +var xr_autotracker : XRPositionalTracker = null +var xr_autopose : XRPose = null +var autotrackeractive = false + +var graspsqueezer = SqueezeButton.new() +var pinchsqueezer = SqueezeButton.new() + + +# Called when the node enters the scene tree for the first time. +func _ready(): + $ThumbstickBoundaries/InnerRing.mesh.outer_radius = innerringrad + $ThumbstickBoundaries/InnerRing.mesh.inner_radius = 0.95*innerringrad + $ThumbstickBoundaries/OuterRing.mesh.outer_radius = outerringrad + $ThumbstickBoundaries/OuterRing.mesh.inner_radius = 0.95*outerringrad + $ThumbstickBoundaries/UpDisc.transform.origin.y = updowndistbutton + $ThumbstickBoundaries/DownDisc.transform.origin.y = -updowndistbutton + +func setupautotracker(tracker_nhand, islefthand, xr_controller_node): + xr_autotracker = XRPositionalTracker.new() + xr_autotracker.hand = tracker_nhand + xr_autotracker.name = "left_autohand" if islefthand else "right_autohand" + xr_autotracker.profile = "/interaction_profiles/autohand" # "/interaction_profiles/none" + xr_autotracker.type = 2 + + xr_autotracker.set_pose(xr_controller_node.pose, Transform3D(), Vector3(), Vector3(), XRPose.TrackingConfidence.XR_TRACKING_CONFIDENCE_NONE) + xr_autopose = xr_autotracker.get_pose(xr_controller_node.pose) + + graspsqueezer.setinputstrings(xr_autotracker, "grip", "", "grip_click") + pinchsqueezer.setinputstrings(xr_autotracker, "trigger", "trigger_touch", "trigger_click") + + XRServer.add_tracker(xr_autotracker) + +func activateautotracker(xr_controller_node): + xr_controller_node.set_tracker(xr_autotracker.name) + autotrackeractive = true + +func deactivateautotracker(xr_controller_node, xr_tracker): + setaxbybuttonstatus(0) + graspsqueezer.applysqueeze(graspsqueezer.touchbuttondistance + 1) + pinchsqueezer.applysqueeze(pinchsqueezer.touchbuttondistance + 1) + xr_controller_node.set_tracker(xr_tracker.name) + autotrackeractive = false + +func autotrackgestures(oxrjps, xrt, xr_camera_node): + thumbsticksimulation(oxrjps, xrt, xr_camera_node) + + # detect forming a fist + var middleknuckletip = (oxrjps[OpenXRInterface.HAND_JOINT_MIDDLE_TIP] - oxrjps[OpenXRInterface.HAND_JOINT_MIDDLE_PROXIMAL]).length() + var ringknuckletip = (oxrjps[OpenXRInterface.HAND_JOINT_RING_TIP] - oxrjps[OpenXRInterface.HAND_JOINT_RING_PROXIMAL]).length() + var littleknuckletip = (oxrjps[OpenXRInterface.HAND_JOINT_LITTLE_TIP] - oxrjps[OpenXRInterface.HAND_JOINT_LITTLE_PROXIMAL]).length() + var avgknuckletip = (middleknuckletip + ringknuckletip + littleknuckletip)/3 + graspsqueezer.applysqueeze(avgknuckletip) + + # detect the finger pinch + var pinchdist = (oxrjps[OpenXRInterface.HAND_JOINT_INDEX_TIP] - oxrjps[OpenXRInterface.HAND_JOINT_THUMB_TIP]).length() + pinchsqueezer.applysqueeze(pinchdist*2) + + #$GraspMarker.global_transform.origin = xrt*oxrjps[OpenXRInterface.HAND_JOINT_MIDDLE_TIP] + #$GraspMarker.visible = buttoncurrentlyclicked + + + +var thumbstickstartpt = null +const thumbdistancecontact = 0.025 +const thumbdistancerelease = 0.045 +const innerringrad = 0.05 +const outerringrad = 0.22 +const updowndisttouch = 0.08 +const updowndistbutton = 0.12 +var thumbsticktouched = false +var axbybuttonstatus = 0 # -2:by_button, -1:by_touch, 1:ax_touch, 1:ax_button +var by_is_up = true + + +func setaxbybuttonstatus(newaxbybuttonstatus): + if axbybuttonstatus == newaxbybuttonstatus: + return + if abs(axbybuttonstatus) == 2: + xr_autotracker.set_input("ax_button" if axbybuttonstatus > 0 else "by_button", false) + axbybuttonstatus = 1 if axbybuttonstatus > 0 else -1 + if axbybuttonstatus == newaxbybuttonstatus: + return + xr_autotracker.set_input("ax_touch" if axbybuttonstatus > 0 else "by_touch", false) + axbybuttonstatus = 0 + if axbybuttonstatus == newaxbybuttonstatus: + return + xr_autotracker.set_input("ax_touch" if newaxbybuttonstatus > 0 else "by_touch", true) + axbybuttonstatus = 1 if newaxbybuttonstatus > 0 else -1 + if axbybuttonstatus == newaxbybuttonstatus: + return + xr_autotracker.set_input("ax_button" if newaxbybuttonstatus > 0 else "by_button", true) + axbybuttonstatus = newaxbybuttonstatus + +func thumbsticksimulation(oxrjps, xrt, xr_camera_node): + var middletip = oxrjps[OpenXRInterface.HAND_JOINT_MIDDLE_TIP] + var thumbtip = oxrjps[OpenXRInterface.HAND_JOINT_THUMB_TIP] + var ringtip = oxrjps[OpenXRInterface.HAND_JOINT_RING_TIP] + var tipcen = (middletip + thumbtip + ringtip)/3.0 + var middleknuckle = oxrjps[OpenXRInterface.HAND_JOINT_MIDDLE_PROXIMAL] + var thumbdistance = max((middletip - tipcen).length(), (thumbtip - tipcen).length(), (ringtip - tipcen).length()) + if thumbstickstartpt == null: + if thumbdistance < thumbdistancecontact and middleknuckle.y < tipcen.y - 0.029: + thumbstickstartpt = tipcen + visible = true + global_transform.origin = xrt*tipcen + $ThumbstickBoundaries.global_transform.origin = xrt*thumbstickstartpt + else: + if thumbdistance > thumbdistancerelease: + thumbstickstartpt = null + if thumbsticktouched: + xr_autotracker.set_input("primary", Vector2(0.0, 0.0)) + xr_autotracker.set_input("primary_touch", true) + thumbsticktouched = false + setaxbybuttonstatus(0) + + visible = (thumbstickstartpt != null) + if thumbstickstartpt != null: + $DragRod.global_transform = sticktransformB(xrt*thumbstickstartpt, xrt*tipcen) + var facingangle = Vector2(xr_camera_node.transform.basis.z.x, xr_camera_node.transform.basis.z.z).angle() if xr_camera_node != null else 0.0 + var hvec = Vector2(tipcen.x - thumbstickstartpt.x, tipcen.z - thumbstickstartpt.z) + var hv = hvec.rotated(deg_to_rad(90) - facingangle) + var hvlen = hv.length() + if not thumbsticktouched: + var frat = hvlen/max(hvlen, innerringrad) + frat = frat*frat*frat + $ThumbstickBoundaries/InnerRing.get_surface_override_material(0).albedo_color.a = frat + $ThumbstickBoundaries/OuterRing.get_surface_override_material(0).albedo_color.a = frat + if hvlen > innerringrad: + xr_autotracker.set_input("primary_touch", true) + thumbsticktouched = true + + if thumbsticktouched: + var hvN = hv/max(hvlen, outerringrad) + xr_autotracker.set_input("primary", Vector2(hvN.x, -hvN.y)) + + var ydist = (tipcen.y - thumbstickstartpt.y) + var rawnewaxbybuttonstatus = 0 + if ydist > updowndisttouch: + $ThumbstickBoundaries/UpDisc.visible = true + $ThumbstickBoundaries/UpDisc.get_surface_override_material(0).albedo_color.a = (ydist - updowndisttouch)/(updowndistbutton - updowndisttouch)*0.5 if ydist < updowndistbutton else 1.0 + rawnewaxbybuttonstatus = 2 if ydist > updowndistbutton else 1 + else: + $ThumbstickBoundaries/UpDisc.visible = false + if ydist < -updowndisttouch: + $ThumbstickBoundaries/DownDisc.visible = true + $ThumbstickBoundaries/DownDisc.get_surface_override_material(0).albedo_color.a = (-ydist - updowndisttouch)/(updowndistbutton - updowndisttouch)*0.5 if -ydist < updowndistbutton else 1.0 + rawnewaxbybuttonstatus = -2 if -ydist > updowndistbutton else -1 + else: + $ThumbstickBoundaries/DownDisc.visible = false + setaxbybuttonstatus(rawnewaxbybuttonstatus*(1 if by_is_up else -1)) + + +class SqueezeButton: + const touchbuttondistance = 0.07 + const depressbuttondistance = 0.04 + const clickbuttononratio = 0.6 + const clickbuttonoffratio = 0.4 + + var xr_autotracker = null + var squeezestring = "" + var touchstring = "" + var clickstring = "" + + var buttoncurrentlyclicked = false + var buttoncurrentlytouched = false + + func setinputstrings(lxr_autotracker, lsqueezestring, ltouchstring, lclickstring): + xr_autotracker = lxr_autotracker + squeezestring = lsqueezestring + touchstring = ltouchstring + clickstring = lclickstring + + func xrsetinput(name, value): + if xr_autotracker and name: + xr_autotracker.set_input(name, value) + + func applysqueeze(squeezedistance): + var buttonratio = min(inverse_lerp(touchbuttondistance, depressbuttondistance, squeezedistance), 1.0) + if buttonratio < 0.0: + if buttoncurrentlytouched: + xrsetinput(squeezestring, 0.0) + xrsetinput(touchstring, false) + buttoncurrentlytouched = false + else: + xrsetinput(squeezestring, buttonratio) + if not buttoncurrentlytouched: + xrsetinput(touchstring, true) + buttoncurrentlytouched = true + var buttonclicked = (buttonratio > (clickbuttonoffratio if buttoncurrentlyclicked else clickbuttononratio)) + if buttonclicked != buttoncurrentlyclicked: + xrsetinput(clickstring, buttonclicked) + buttoncurrentlyclicked = buttonclicked + + +const stickradius = 0.01 +static func sticktransformB(j1, j2): + var v = j2 - j1 + var vlen = v.length() + var b + if vlen != 0: + var vy = v/vlen + var vyunaligned = Vector3(0,1,0) if abs(vy.y) < abs(vy.x) + abs(vy.z) else Vector3(1,0,0) + var vz = vy.cross(vyunaligned) + var vx = vy.cross(vz) + b = Basis(vx*stickradius, v, vz*stickradius) + else: + b = Basis().scaled(Vector3(0.01, 0.0, 0.01)) + return Transform3D(b, (j1 + j2)*0.5) + diff --git a/app/addons/xr-autohandtracker/visible_handtrack_skeleton.gd b/app/addons/xr-autohandtracker/visible_handtrack_skeleton.gd new file mode 100644 index 0000000..467ea27 --- /dev/null +++ b/app/addons/xr-autohandtracker/visible_handtrack_skeleton.gd @@ -0,0 +1,60 @@ +extends Node3D + + + +const hjsticks = [ [ OpenXRInterface.HAND_JOINT_WRIST, OpenXRInterface.HAND_JOINT_THUMB_METACARPAL, OpenXRInterface.HAND_JOINT_THUMB_PROXIMAL, OpenXRInterface.HAND_JOINT_THUMB_DISTAL, OpenXRInterface.HAND_JOINT_THUMB_TIP ], + [ OpenXRInterface.HAND_JOINT_WRIST, OpenXRInterface.HAND_JOINT_INDEX_METACARPAL, OpenXRInterface.HAND_JOINT_INDEX_PROXIMAL, OpenXRInterface.HAND_JOINT_INDEX_INTERMEDIATE, OpenXRInterface.HAND_JOINT_INDEX_DISTAL, OpenXRInterface.HAND_JOINT_INDEX_TIP ], + [ OpenXRInterface.HAND_JOINT_WRIST, OpenXRInterface.HAND_JOINT_MIDDLE_METACARPAL, OpenXRInterface.HAND_JOINT_MIDDLE_PROXIMAL, OpenXRInterface.HAND_JOINT_MIDDLE_INTERMEDIATE, OpenXRInterface.HAND_JOINT_MIDDLE_DISTAL, OpenXRInterface.HAND_JOINT_MIDDLE_TIP ], + [ OpenXRInterface.HAND_JOINT_WRIST, OpenXRInterface.HAND_JOINT_RING_METACARPAL, OpenXRInterface.HAND_JOINT_RING_PROXIMAL, OpenXRInterface.HAND_JOINT_RING_INTERMEDIATE, OpenXRInterface.HAND_JOINT_RING_DISTAL, OpenXRInterface.HAND_JOINT_RING_TIP ], + [ OpenXRInterface.HAND_JOINT_WRIST, OpenXRInterface.HAND_JOINT_LITTLE_METACARPAL, OpenXRInterface.HAND_JOINT_LITTLE_PROXIMAL, OpenXRInterface.HAND_JOINT_LITTLE_INTERMEDIATE, OpenXRInterface.HAND_JOINT_LITTLE_DISTAL, OpenXRInterface.HAND_JOINT_LITTLE_TIP ] + ] + +func _ready(): + var sticknode = $ExampleStick + remove_child(sticknode) + var jointnode = $ExampleJoint + remove_child(jointnode) + for j in range(OpenXRInterface.HAND_JOINT_MAX): + var rj = jointnode.duplicate() + rj.name = "J%d" % j + rj.scale = Vector3(0.01, 0.01, 0.01) + add_child(rj) + + for hjstick in hjsticks: + for i in range(0, len(hjstick)-1): + var rstick = sticknode.duplicate() + var j1 = hjstick[i] + var j2 = hjstick[i+1] + rstick.name = "S%d_%d" % [j1, j2] + rstick.scale = Vector3(0.01, 0.01, 0.01) + add_child(rstick) + #get_node("J%d" % hjstick[i+1]).get_node("Sphere").visible = (i > 0) + + +const knuckleradius = 0.01 +func updatevisiblehandskeleton(oxrjps, oxrjrot, xrt): + for j in range(OpenXRInterface.HAND_JOINT_MAX): + get_node("J%d" % j).global_transform = Transform3D(xrt.basis*Basis(oxrjrot[j]).scaled(Vector3(knuckleradius, knuckleradius, knuckleradius)), xrt*oxrjps[j]) + + for hjstick in hjsticks: + for i in range(0, len(hjstick)-1): + var j1 = hjstick[i] + var j2 = hjstick[i+1] + var rstick = get_node("S%d_%d" % [j1, j2]) + rstick.global_transform = sticktransformB(xrt*oxrjps[j1], xrt*oxrjps[j2]) + + +const stickradius = 0.01 +static func sticktransformB(j1, j2): + var v = j2 - j1 + var vlen = v.length() + var b + if vlen != 0: + var vy = v/vlen + var vyunaligned = Vector3(0,1,0) if abs(vy.y) < abs(vy.x) + abs(vy.z) else Vector3(1,0,0) + var vz = vy.cross(vyunaligned) + var vx = vy.cross(vz) + b = Basis(vx*stickradius, v, vz*stickradius) + else: + b = Basis().scaled(Vector3(0.01, 0.0, 0.01)) + return Transform3D(b, (j1 + j2)*0.5) diff --git a/app/assets/materials/hands.gdshader b/app/assets/materials/hands.gdshader new file mode 100644 index 0000000..b94c8f6 --- /dev/null +++ b/app/assets/materials/hands.gdshader @@ -0,0 +1,25 @@ +shader_type spatial; + +uniform vec4 albedo: source_color = vec4(1.0, 1.0, 1.0, 0.4); +uniform float fade_offset : hint_range(-0.1, 0.1, 0.001) = 0.0; +uniform float fade_sharpness : hint_range(0.0, 35.0, 0.01) = 15.00; + +varying vec3 vertex_pos; + +void vertex() { + vertex_pos = VERTEX; +} + +float fresnel(float amount, vec3 normal, vec3 view) +{ + return pow((1.0 - clamp(dot(normalize(normal), normalize(view)), 0.0, 1.0 )), amount); +} + +void fragment() +{ + float basic_fresnel = fresnel(3.0, NORMAL, VIEW); + ALBEDO = albedo.xyz + basic_fresnel; + ALPHA = albedo.w + basic_fresnel; + ALPHA = clamp((-vertex_pos.z - fade_offset) * fade_sharpness, 0.00, ALPHA); +} + diff --git a/app/assets/models/hands/Hand_low_L.gltf b/app/assets/models/hands/Hand_low_L.gltf new file mode 100644 index 0000000..6cd6eb7 --- /dev/null +++ b/app/assets/models/hands/Hand_low_L.gltf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d258e8207dcf0824402a184007086eb4e1ae599996ee855549321536a35cf494 +size 70342 diff --git a/app/assets/models/hands/Hand_low_L.gltf.import b/app/assets/models/hands/Hand_low_L.gltf.import new file mode 100644 index 0000000..db89e3b --- /dev/null +++ b/app/assets/models/hands/Hand_low_L.gltf.import @@ -0,0 +1,34 @@ +[remap] + +importer="scene" +importer_version=1 +type="PackedScene" +uid="uid://dv6vpdc0ia05i" +path="res://.godot/imported/Hand_low_L.gltf-9c10b05e7c0ffd2a3c3b8d44362b6cfb.scn" + +[deps] + +source_file="res://assets/models/hands/Hand_low_L.gltf" +dest_files=["res://.godot/imported/Hand_low_L.gltf-9c10b05e7c0ffd2a3c3b8d44362b6cfb.scn"] + +[params] + +nodes/root_type="" +nodes/root_name="" +nodes/apply_root_scale=true +nodes/root_scale=1.0 +meshes/ensure_tangents=true +meshes/generate_lods=true +meshes/create_shadow_meshes=true +meshes/light_baking=1 +meshes/lightmap_texel_size=0.2 +meshes/force_disable_compression=false +skins/use_named_skins=true +animation/import=true +animation/fps=30 +animation/trimming=false +animation/remove_immutable_tracks=true +import_script/path="" +_subresources={} +gltf/naming_version=1 +gltf/embedded_image_handling=1 diff --git a/app/assets/models/hands/Hand_low_R.gltf b/app/assets/models/hands/Hand_low_R.gltf new file mode 100644 index 0000000..500e481 --- /dev/null +++ b/app/assets/models/hands/Hand_low_R.gltf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:19cbbf3c2fd3b8f0a1319056854975b99cdb6dfe3caa9b09018bb865a3964de1 +size 70346 diff --git a/app/assets/models/hands/Hand_low_R.gltf.import b/app/assets/models/hands/Hand_low_R.gltf.import new file mode 100644 index 0000000..4f2f4f6 --- /dev/null +++ b/app/assets/models/hands/Hand_low_R.gltf.import @@ -0,0 +1,34 @@ +[remap] + +importer="scene" +importer_version=1 +type="PackedScene" +uid="uid://dy70ty8fowgbf" +path="res://.godot/imported/Hand_low_R.gltf-dae5df2e2e7666d45bce4f244fa11afb.scn" + +[deps] + +source_file="res://assets/models/hands/Hand_low_R.gltf" +dest_files=["res://.godot/imported/Hand_low_R.gltf-dae5df2e2e7666d45bce4f244fa11afb.scn"] + +[params] + +nodes/root_type="" +nodes/root_name="" +nodes/apply_root_scale=true +nodes/root_scale=1.0 +meshes/ensure_tangents=true +meshes/generate_lods=true +meshes/create_shadow_meshes=true +meshes/light_baking=1 +meshes/lightmap_texel_size=0.2 +meshes/force_disable_compression=false +skins/use_named_skins=true +animation/import=true +animation/fps=30 +animation/trimming=false +animation/remove_immutable_tracks=true +import_script/path="" +_subresources={} +gltf/naming_version=1 +gltf/embedded_image_handling=1 diff --git a/app/content/entities/timer/timer.tscn b/app/content/entities/timer/timer.tscn index a56c485..b7cf37d 100644 --- a/app/content/entities/timer/timer.tscn +++ b/app/content/entities/timer/timer.tscn @@ -10,7 +10,7 @@ [sub_resource type="BoxShape3D" id="BoxShape3D_3qyo4"] size = Vector3(0.32, 0.16, 0.02) -[sub_resource type="ShaderMaterial" id="ShaderMaterial_cw188"] +[sub_resource type="ShaderMaterial" id="ShaderMaterial_nktla"] resource_local_to_scene = true render_priority = 10 shader = ExtResource("6_40cd1") @@ -25,7 +25,7 @@ shader_parameter/corner_radius = 0.8 shader_parameter/roughness = 0.3 shader_parameter/grain_amount = 0.02 -[sub_resource type="QuadMesh" id="QuadMesh_ryeda"] +[sub_resource type="QuadMesh" id="QuadMesh_mqjqg"] size = Vector2(0.32, 0.16) [node name="Timer" type="StaticBody3D" groups=["entity"]] @@ -78,7 +78,7 @@ label = "stop" icon = true [node name="Panel" parent="." instance=ExtResource("5_j3gsb")] -material_override = SubResource("ShaderMaterial_cw188") -mesh = SubResource("QuadMesh_ryeda") +material_override = SubResource("ShaderMaterial_nktla") +mesh = SubResource("QuadMesh_mqjqg") size = Vector2(0.32, 0.16) corner_radius = 0.8 diff --git a/app/content/main.tscn b/app/content/main.tscn index 78b7fc1..34c071e 100644 --- a/app/content/main.tscn +++ b/app/content/main.tscn @@ -1,25 +1,17 @@ -[gd_scene load_steps=15 format=3 uid="uid://eecv28y6jxk4"] +[gd_scene load_steps=12 format=3 uid="uid://eecv28y6jxk4"] [ext_resource type="PackedScene" uid="uid://clc5dre31iskm" path="res://addons/godot-xr-tools/xr/start_xr.tscn" id="1_i4c04"] [ext_resource type="Script" path="res://content/main.gd" id="1_uvrd4"] [ext_resource type="PackedScene" uid="uid://b30w6tywfj4fp" path="res://content/system/controller_left/controller_left.tscn" id="2_2lraw"] [ext_resource type="Environment" uid="uid://cfm0g4r0h2n1p" path="res://assets/environment.tres" id="2_lsndp"] -[ext_resource type="PackedScene" uid="uid://dscp8x0ari57n" path="res://content/system/raycast/raycast.tscn" id="3_67lii"] [ext_resource type="PackedScene" uid="uid://b2kjh1fpjptdr" path="res://content/system/camera/camera.tscn" id="3_rj4ac"] -[ext_resource type="PackedScene" uid="uid://bsx12q23v8apy" path="res://content/system/hands/hands.tscn" id="4_v8xu6"] [ext_resource type="PackedScene" uid="uid://ctltchlf2j2r4" path="res://addons/xr-simulator/XRSimulator.tscn" id="5_3qc8g"] +[ext_resource type="PackedScene" uid="uid://biu66ihmvmku3" path="res://content/system/controller_right/controller_right.tscn" id="7_0b3tc"] [ext_resource type="PackedScene" uid="uid://c3kdssrmv84kv" path="res://content/ui/menu/menu.tscn" id="8_du83w"] [ext_resource type="PackedScene" uid="uid://lrehk38exd5n" path="res://content/system/keyboard/keyboard.tscn" id="9_e5n3p"] [ext_resource type="PackedScene" uid="uid://cbemihbxkd4ll" path="res://content/system/house/house.tscn" id="9_np6mw"] [ext_resource type="PackedScene" uid="uid://bhyddd1f0ry1x" path="res://content/ui/onboarding/onboarding.tscn" id="12_uq2nj"] -[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_m58yb"] -ao_enabled = true - -[sub_resource type="BoxMesh" id="BoxMesh_ir3co"] -material = SubResource("StandardMaterial3D_m58yb") -size = Vector3(0.01, 0.01, 0.01) - [node name="Main" type="Node3D"] transform = Transform3D(1, -0.000296142, 0.000270963, 0.000296143, 1, -4.5899e-06, -0.000270962, 4.67014e-06, 1, 0, 0, 0) script = ExtResource("1_uvrd4") @@ -41,20 +33,17 @@ enable_passthrough = true [node name="XRControllerLeft" parent="XROrigin3D" instance=ExtResource("2_2lraw")] transform = Transform3D(0.999999, -1.39633e-11, 0, 9.48075e-12, 1, 0, 0, 0, 1, -0.355145, 0.550439, -0.477945) -[node name="XRControllerRight" type="XRController3D" parent="XROrigin3D"] -transform = Transform3D(0.999999, -1.39633e-11, 0, 9.48075e-12, 1, 0, 0, 0, 1, 0.272616, 0.559282, -0.468369) -tracker = &"right_hand" -pose = &"aim" +[node name="IndexTip" parent="XROrigin3D/XRControllerLeft" index="6"] +transform = Transform3D(0.967526, 0.252326, -0.0150302, -0.0150302, 0.116784, 0.993043, 0.252326, -0.960569, 0.116784, -0.00665808, 0.0427912, -0.169868) -[node name="MeshInstance3D" type="MeshInstance3D" parent="XROrigin3D/XRControllerRight"] -mesh = SubResource("BoxMesh_ir3co") +[node name="ThumbTip" parent="XROrigin3D/XRControllerLeft" index="7"] +transform = Transform3D(0.967043, 0.24582, -0.0663439, -0.0663439, 0.494837, 0.86645, 0.24582, -0.833492, 0.494837, 0.0261569, 0.0891963, -0.0934418) -[node name="Raycast" parent="XROrigin3D/XRControllerRight" instance=ExtResource("3_67lii")] +[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="Hands" parent="XROrigin3D" node_paths=PackedStringArray("ray_left", "ray_right") instance=ExtResource("4_v8xu6")] -transform = Transform3D(0.999968, -1.39576e-11, 0, 9.52038e-12, 0.999984, -2.59206e-11, -2.91038e-11, 5.22959e-11, 0.999984, 0, 0, 0) -ray_left = NodePath("../XRControllerLeft/Raycast") -ray_right = NodePath("../XRControllerRight/Raycast") +[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) [node name="XRSimulator" parent="." instance=ExtResource("5_3qc8g")] min_camera_height = 0.01 @@ -74,3 +63,4 @@ transform = Transform3D(0.5, 5.24309e-05, 0.000144384, -0.000139169, 0.353553, 0 transform = Transform3D(1, -1.39636e-11, 0, 4.42413e-11, 1, 0, 0, 0, 1, -0.576793, 0.820168, -0.60016) [editable path="XROrigin3D/XRControllerLeft"] +[editable path="XROrigin3D/XRControllerLeft/hand_l"] diff --git a/app/content/system/controller_left/controller_left.gd b/app/content/system/controller_left/controller_left.gd index a29f7fb..7d7e4fa 100644 --- a/app/content/system/controller_left/controller_left.gd +++ b/app/content/system/controller_left/controller_left.gd @@ -1,10 +1,40 @@ extends XRController3D const Entity = preload ("res://content/entities/entity.gd") +const Pointer = preload ("res://lib/utils/pointer/pointer.gd") +const Initiator = preload ("res://lib/utils/pointer/initiator.gd") +const Finger = preload ("res://lib/utils/touch/finger.gd") +const Touch = preload ("res://lib/utils/touch/touch.gd") +const Collide = preload ("res://lib/utils/touch/collide.gd") +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 index_tip = $IndexTip +@onready var thumb_tip = $ThumbTip +@onready var middle_tip = $MiddleTip + +@onready var mini_view_button = $Palm/QuickActions/MiniView +@onready var temperature_button = $Palm/QuickActions/Temperature +@onready var humidity_button = $Palm/QuickActions/Humidity + +@onready var palm = $Palm +@onready var ray: RayCast3D = $Raycast @onready var area = $trash_bin/Area3D @onready var trash_bin = $trash_bin @onready var animation = $AnimationPlayer +@onready var quick_actions = $Palm/QuickActions + +var initiator: Initiator = Initiator.new() +var collide: Collide +var pointer: Pointer +var press_distance = 0.02 +var grip_distance = 0.02 + +var pressed = false +var grabbed = false var to_delete = [] var trash_bin_visible: bool = true: @@ -36,6 +66,8 @@ var trash_bin_large: bool = false: func _ready(): trash_bin_visible = false + _setup_hand() + EventSystem.on_grab_down.connect(func(event: EventPointer): trash_bin_visible=_get_entity(event.target) != null ) @@ -70,6 +102,33 @@ func _ready(): House.body.save_all_entities() ) +func _process(_delta): + 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): + 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) + + var trigger_close = distance_trigger <= press_distance + var grab_close = distance_grab <= grip_distance + + if trigger_close&&!pressed: + initiator.on_press.emit(Initiator.EventType.TRIGGER) + pressed = true + elif !trigger_close&&pressed: + initiator.on_release.emit(Initiator.EventType.TRIGGER) + pressed = false + + if grab_close&&!grabbed: + initiator.on_press.emit(Initiator.EventType.GRIP) + grabbed = true + elif !grab_close&&grabbed: + initiator.on_release.emit(Initiator.EventType.GRIP) + grabbed = false + func _get_entity(node: Node): if node is Entity: return node @@ -77,4 +136,34 @@ func _get_entity(node: Node): if node.get_parent() == null: return null - return _get_entity(node.get_parent()) \ No newline at end of file + return _get_entity(node.get_parent()) + +func _setup_hand(): + TouchManager.add_finger(Finger.Type.INDEX_LEFT, $IndexTip/TouchArea) + + collide = Collide.new(hand, hand_mesh, index_tip) + add_child(collide) + + mini_view_button.on_button_up.connect(func(): + House.body.mini_view.small.value=!House.body.mini_view.small.value + ) + + temperature_button.on_button_up.connect(func(): + if House.body.mini_view.heatmap_type.value == Miniature.HeatmapType.TEMPERATURE: + House.body.mini_view.heatmap_type.value=Miniature.HeatmapType.NONE + else: + House.body.mini_view.heatmap_type.value=Miniature.HeatmapType.TEMPERATURE + ) + + humidity_button.on_button_up.connect(func(): + if House.body.mini_view.heatmap_type.value == Miniature.HeatmapType.HUMIDITY: + House.body.mini_view.heatmap_type.value=Miniature.HeatmapType.NONE + else: + House.body.mini_view.heatmap_type.value=Miniature.HeatmapType.HUMIDITY + ) + + initiator.type = Initiator.Type.HAND_LEFT + initiator.node = self + + pointer = Pointer.new(initiator, ray) + add_child(pointer) \ No newline at end of file diff --git a/app/content/system/controller_left/controller_left.tscn b/app/content/system/controller_left/controller_left.tscn index 2b5adba..2074e32 100644 --- a/app/content/system/controller_left/controller_left.tscn +++ b/app/content/system/controller_left/controller_left.tscn @@ -1,8 +1,12 @@ -[gd_scene load_steps=10 format=3 uid="uid://b30w6tywfj4fp"] +[gd_scene load_steps=16 format=3 uid="uid://b30w6tywfj4fp"] [ext_resource type="Script" path="res://content/system/controller_left/controller_left.gd" id="1_2j3qs"] [ext_resource type="PackedScene" uid="uid://dqjcqdhe3rbtn" path="res://assets/models/trash_bin/trash_bin.gltf" id="3_m33ce"] [ext_resource type="PackedScene" uid="uid://dscp8x0ari57n" path="res://content/system/raycast/raycast.tscn" id="4_n7lao"] +[ext_resource type="PackedScene" uid="uid://bufelcry36rw1" path="res://addons/xr-autohandtracker/auto_handtracker.tscn" id="4_oe7fv"] +[ext_resource type="PackedScene" uid="uid://dhaqth6q5yw4n" path="res://addons/godot-xr-tools/hands/model/hand_l.gltf" id="5_w1pvs"] +[ext_resource type="Shader" path="res://assets/materials/hands.gdshader" id="6_wk733"] +[ext_resource type="PackedScene" uid="uid://bsjqdvkt0u87c" path="res://content/ui/components/button/button.tscn" id="6_x5vuc"] [sub_resource type="StandardMaterial3D" id="StandardMaterial3D_m58yb"] ao_enabled = true @@ -94,6 +98,17 @@ _data = { "add_trashbin": SubResource("Animation_hax52") } +[sub_resource type="ShaderMaterial" id="ShaderMaterial_ca85m"] +render_priority = 0 +shader = ExtResource("6_wk733") +shader_parameter/albedo = Color(1, 1, 1, 0.4) +shader_parameter/fade_offset = 0.0 +shader_parameter/fade_sharpness = 15.0 + +[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_65k2y"] +radius = 0.001 +height = 0.02 + [node name="XRControllerLeft" type="XRController3D"] tracker = &"left_hand" pose = &"aim" @@ -120,3 +135,79 @@ libraries = { [node name="Raycast" parent="." instance=ExtResource("4_n7lao")] is_right = false + +[node name="AutoHandtracker" parent="." instance=ExtResource("4_oe7fv")] +visible = false +visiblehandtrackskeleton = false +enableautotracker = false + +[node name="hand_l" parent="." instance=ExtResource("5_w1pvs")] + +[node name="mesh_Hand_L" parent="hand_l/Armature/Skeleton3D" index="0"] +material_override = SubResource("ShaderMaterial_ca85m") + +[node name="IndexTip" type="BoneAttachment3D" parent="."] +transform = Transform3D(0.967526, 0.252326, -0.0150302, -0.0150302, 0.116784, 0.993043, 0.252326, -0.960569, 0.116784, -0.00665802, 0.0427913, -0.169868) +bone_name = "Index_Tip_L" +bone_idx = 9 +use_external_skeleton = true +external_skeleton = NodePath("../hand_l/Armature/Skeleton3D") + +[node name="Marker3D" type="Marker3D" parent="IndexTip"] +gizmo_extents = 0.02 + +[node name="TouchArea" type="Area3D" parent="IndexTip"] +transform = Transform3D(1, 0, 0, 1.49012e-08, 1, 0, 1.86265e-09, 0, 1, 0, 0, 0) +collision_layer = 0 +collision_mask = 4 +monitorable = false + +[node name="CollisionShape3D" type="CollisionShape3D" parent="IndexTip/TouchArea"] +transform = Transform3D(1, -7.45058e-09, -2.22045e-16, 7.45058e-09, 1, 0, 0, 0, 1, 0, 0, 0) +shape = SubResource("CapsuleShape3D_65k2y") + +[node name="ThumbTip" type="BoneAttachment3D" parent="."] +transform = Transform3D(0.967042, 0.24582, -0.0663439, -0.0663439, 0.494837, 0.866449, 0.24582, -0.833492, 0.494837, 0.0261569, 0.0891964, -0.0934418) +bone_name = "Thumb_Tip_L" +bone_idx = 4 +use_external_skeleton = true +external_skeleton = NodePath("../hand_l/Armature/Skeleton3D") + +[node name="Marker3D" type="Marker3D" parent="ThumbTip"] +gizmo_extents = 0.02 + +[node name="MiddleTip" type="BoneAttachment3D" parent="."] +transform = Transform3D(0.98042, 0.196912, 0.00149799, 0.001498, -0.015065, 0.999885, 0.196912, -0.980305, -0.0150651, -0.00327212, -0.00771424, -0.176318) +bone_name = "Middle_Tip_L" +bone_idx = 14 +use_external_skeleton = true +external_skeleton = NodePath("../hand_l/Armature/Skeleton3D") + +[node name="Marker3D" type="Marker3D" parent="MiddleTip"] +gizmo_extents = 0.02 + +[node name="Palm" type="BoneAttachment3D" parent="."] +transform = Transform3D(1, 3.12364e-06, -3.13861e-06, -3.12371e-06, 1, -1.97886e-05, 3.13854e-06, 1.97889e-05, 1, 0.0307807, -0.0419721, -0.0399505) +bone_name = "Palm_L" +bone_idx = 25 +use_external_skeleton = true +external_skeleton = NodePath("../hand_l/Armature/Skeleton3D") + +[node name="QuickActions" type="Node3D" parent="Palm"] +transform = Transform3D(-1.54544e-08, -1.54544e-08, 0.5, -0.353553, 0.353553, -4.15241e-13, -0.353553, -0.353553, -2.18557e-08, -1.04308e-07, 0.0344645, -6.81728e-07) + +[node name="MiniView" parent="Palm/QuickActions" instance=ExtResource("6_x5vuc")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.0600001, 0, 0) +label = "nest_multi_room" +icon = true + +[node name="Temperature" parent="Palm/QuickActions" instance=ExtResource("6_x5vuc")] +label = "device_thermostat" +icon = true + +[node name="Humidity" parent="Palm/QuickActions" instance=ExtResource("6_x5vuc")] +transform = Transform3D(1, 1.73472e-18, 0, 0, 1, 0, 0, 0, 1, 0.0600001, -5.68873e-13, 0) +label = "humidity_mid" +icon = true + +[editable path="hand_l"] diff --git a/app/content/system/controller_right/controller_right.gd b/app/content/system/controller_right/controller_right.gd new file mode 100644 index 0000000..88e4df1 --- /dev/null +++ b/app/content/system/controller_right/controller_right.gd @@ -0,0 +1,59 @@ +extends XRController3D + +const Pointer = preload ("res://lib/utils/pointer/pointer.gd") +const Initiator = preload ("res://lib/utils/pointer/initiator.gd") +const Finger = preload ("res://lib/utils/touch/finger.gd") +const Touch = preload ("res://lib/utils/touch/touch.gd") +const Collide = preload ("res://lib/utils/touch/collide.gd") +const Miniature = preload ("res://content/system/house/mini/miniature.gd") + +@onready var main = $"/root/Main" +@onready var ray: RayCast3D = $Raycast +@onready var hand: Node3D = $hand_r +@onready var hand_mesh = $hand_r/Armature/Skeleton3D/mesh_Hand_R + +@onready var index_tip = $IndexTip +@onready var thumb_tip = $ThumbTip +@onready var middle_tip = $MiddleTip + +var initiator: Initiator = Initiator.new() +var collide: Collide +var pointer: Pointer +var press_distance = 0.02 +var grip_distance = 0.02 + +var pressed = false +var grabbed = false + +func _ready(): + TouchManager.add_finger(Finger.Type.INDEX_RIGHT, $IndexTip/TouchArea) + + collide = Collide.new(hand, hand_mesh, index_tip) + add_child(collide) + + initiator.type = Initiator.Type.HAND_RIGHT + initiator.node = self + + pointer = Pointer.new(initiator, ray) + add_child(pointer) + +func _physics_process(_delta): + 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) + + var trigger_close = distance_trigger <= press_distance + var grab_close = distance_grab <= grip_distance + + if trigger_close&&!pressed: + initiator.on_press.emit(Initiator.EventType.TRIGGER) + pressed = true + elif !trigger_close&&pressed: + initiator.on_release.emit(Initiator.EventType.TRIGGER) + pressed = false + + if grab_close&&!grabbed: + initiator.on_press.emit(Initiator.EventType.GRIP) + grabbed = true + elif !grab_close&&grabbed: + initiator.on_release.emit(Initiator.EventType.GRIP) + grabbed = false \ No newline at end of file diff --git a/app/content/system/controller_right/controller_right.tscn b/app/content/system/controller_right/controller_right.tscn new file mode 100644 index 0000000..0c3d427 --- /dev/null +++ b/app/content/system/controller_right/controller_right.tscn @@ -0,0 +1,80 @@ +[gd_scene load_steps=9 format=3 uid="uid://biu66ihmvmku3"] + +[ext_resource type="Script" path="res://content/system/controller_right/controller_right.gd" id="1_1oh5j"] +[ext_resource type="PackedScene" uid="uid://dscp8x0ari57n" path="res://content/system/raycast/raycast.tscn" id="1_3p68p"] +[ext_resource type="PackedScene" uid="uid://ds1t8vc0kxoeo" path="res://addons/godot-xr-tools/hands/model/hand_r.gltf" id="2_kex6u"] +[ext_resource type="PackedScene" uid="uid://bufelcry36rw1" path="res://addons/xr-autohandtracker/auto_handtracker.tscn" id="3_pjmb2"] +[ext_resource type="Material" uid="uid://chu0upvkheqlb" path="res://content/system/controller_right/hands_material.tres" id="4_vhkya"] + +[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_m58yb"] +ao_enabled = true + +[sub_resource type="BoxMesh" id="BoxMesh_ir3co"] +material = SubResource("StandardMaterial3D_m58yb") +size = Vector3(0.01, 0.01, 0.01) + +[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_66uu0"] +radius = 0.001 +height = 0.02 + +[node name="XRControllerRight" type="XRController3D"] +tracker = &"right_hand" +pose = &"aim" +script = ExtResource("1_1oh5j") + +[node name="MeshInstance3D" type="MeshInstance3D" parent="."] +mesh = SubResource("BoxMesh_ir3co") + +[node name="Raycast" parent="." instance=ExtResource("1_3p68p")] + +[node name="hand_r" parent="." instance=ExtResource("2_kex6u")] + +[node name="mesh_Hand_R" parent="hand_r/Armature/Skeleton3D" index="0"] +material_override = ExtResource("4_vhkya") + +[node name="AutoHandtracker" parent="." instance=ExtResource("3_pjmb2")] +visible = false +visiblehandtrackskeleton = false +enableautotracker = false + +[node name="IndexTip" type="BoneAttachment3D" parent="."] +transform = Transform3D(0.967526, -0.252326, 0.0150302, 0.0150302, 0.116784, 0.993043, -0.252326, -0.960569, 0.116784, 0.00665802, 0.0427913, -0.169868) +bone_name = "Index_Tip_R" +bone_idx = 9 +use_external_skeleton = true +external_skeleton = NodePath("../hand_r/Armature/Skeleton3D") + +[node name="Marker3D" type="Marker3D" parent="IndexTip"] +gizmo_extents = 0.02 + +[node name="TouchArea" type="Area3D" parent="IndexTip"] +transform = Transform3D(1, 0, 0, -1.49012e-08, 1, 0, -1.86265e-09, 0, 1, 0, 0, 0) +collision_layer = 0 +collision_mask = 4 +monitorable = false + +[node name="CollisionShape3D" type="CollisionShape3D" parent="IndexTip/TouchArea"] +transform = Transform3D(1, -7.45058e-09, -2.22045e-16, 7.45058e-09, 1, 0, 0, 0, 1, 0, 0, 0) +shape = SubResource("CapsuleShape3D_66uu0") + +[node name="ThumbTip" type="BoneAttachment3D" parent="."] +transform = Transform3D(0.967042, -0.24582, 0.0663439, 0.0663439, 0.494837, 0.866449, -0.24582, -0.833492, 0.494837, -0.0261569, 0.0891964, -0.0934418) +bone_name = "Thumb_Tip_R" +bone_idx = 4 +use_external_skeleton = true +external_skeleton = NodePath("../hand_r/Armature/Skeleton3D") + +[node name="Marker3D" type="Marker3D" parent="ThumbTip"] +gizmo_extents = 0.02 + +[node name="MiddleTip" type="BoneAttachment3D" parent="."] +transform = Transform3D(0.98042, -0.196912, -0.00149799, -0.001498, -0.015065, 0.999885, -0.196912, -0.980305, -0.0150651, 0.00327212, -0.00771424, -0.176318) +bone_name = "Middle_Tip_R" +bone_idx = 14 +use_external_skeleton = true +external_skeleton = NodePath("../hand_r/Armature/Skeleton3D") + +[node name="Marker3D" type="Marker3D" parent="MiddleTip"] +gizmo_extents = 0.02 + +[editable path="hand_r"] diff --git a/app/content/system/controller_right/hands_material.tres b/app/content/system/controller_right/hands_material.tres new file mode 100644 index 0000000..8625c23 --- /dev/null +++ b/app/content/system/controller_right/hands_material.tres @@ -0,0 +1,8 @@ +[gd_resource type="ShaderMaterial" load_steps=2 format=3 uid="uid://chu0upvkheqlb"] + +[ext_resource type="Shader" path="res://assets/materials/hands.gdshader" id="1_kyekt"] + +[resource] +render_priority = 0 +shader = ExtResource("1_kyekt") +shader_parameter/albedo = Color(1, 1, 1, 0.4) diff --git a/app/content/system/hands/hands.gd b/app/content/system/hands/hands.gd index 69a6c09..c9a0218 100644 --- a/app/content/system/hands/hands.gd +++ b/app/content/system/hands/hands.gd @@ -8,8 +8,6 @@ const Collide = preload ("res://lib/utils/touch/collide.gd") const Miniature = preload ("res://content/system/house/mini/miniature.gd") @onready var main = $"/root/Main" -@onready var hand_right: OpenXRHand = $XRHandRight -@onready var hand_left: OpenXRHand = $XRHandLeft @onready var palm = $XRHandLeft/Palm @onready var quick_actions = $XRHandLeft/Palm/QuickActions @onready var mini_view_button = $XRHandLeft/Palm/QuickActions/MiniView @@ -17,6 +15,14 @@ const Miniature = preload ("res://content/system/house/mini/miniature.gd") @onready var humidity_button = $XRHandLeft/Palm/QuickActions/Humidity @export var ray_left: RayCast3D @export var ray_right: RayCast3D +@export var hand_left: Node3D +@export var hand_right: Node3D + +@onready var bone_attachments_right = [$XRHandRight/IndexTip, $XRHandRight/ThumbTip, $XRHandRight/MiddleTip] +@onready var bone_attachments_left = [$XRHandLeft/IndexTip, $XRHandLeft/ThumbTip, $XRHandLeft/MiddleTip] + +enum Fingers {INDEX, THUMB, MIDDLE} + var left_initiator: Initiator = Initiator.new() var right_initiator: Initiator = Initiator.new() var touch: Touch @@ -84,13 +90,13 @@ func _process(_delta): if quick_actions.is_inside_tree(): palm.remove_child(quick_actions) func _physics_process(_delta): - _process_hand(hand_left) - _process_hand(hand_right) + _process_hand_left(hand_left) + _process_hand_right(hand_right) -func _process_hand(hand: OpenXRHand): - var index_tip = hand.get_node("IndexTip/Marker3D") - var thumb_tip = hand.get_node("ThumbTip/Marker3D") - var middle_tip = hand.get_node("MiddleTip/Marker3D") +func _process_hand_left(hand: Node3D): + var index_tip = bone_attachments_left[Fingers.INDEX].get_node("Marker3D") + var thumb_tip = bone_attachments_left[Fingers.THUMB].get_node("Marker3D") + var middle_tip = bone_attachments_left[Fingers.MIDDLE].get_node("Marker3D") var _ray = ray_left if hand == hand_left else ray_right var initiator = left_initiator if hand == hand_left else right_initiator @@ -101,31 +107,44 @@ func _process_hand(hand: OpenXRHand): var trigger_close = distance_trigger <= press_distance var grab_close = distance_grab <= grip_distance - if hand == hand_left: - if trigger_close&&!pressed_left: - initiator.on_press.emit(Initiator.EventType.TRIGGER) - pressed_left = true - elif !trigger_close&&pressed_left: - initiator.on_release.emit(Initiator.EventType.TRIGGER) - pressed_left = false - - if grab_close&&!grabbed_left: - initiator.on_press.emit(Initiator.EventType.GRIP) - grabbed_left = true - elif !grab_close&&grabbed_left: - initiator.on_release.emit(Initiator.EventType.GRIP) - grabbed_left = false - else: - if trigger_close&&!pressed_right: - initiator.on_press.emit(Initiator.EventType.TRIGGER) - pressed_right = true - elif !trigger_close&&pressed_right: - initiator.on_release.emit(Initiator.EventType.TRIGGER) - pressed_right = false + if trigger_close&&!pressed_left: + initiator.on_press.emit(Initiator.EventType.TRIGGER) + pressed_left = true + elif !trigger_close&&pressed_left: + initiator.on_release.emit(Initiator.EventType.TRIGGER) + pressed_left = false - if grab_close&&!grabbed_right: - initiator.on_press.emit(Initiator.EventType.GRIP) - grabbed_right = true - elif !grab_close&&grabbed_right: - initiator.on_release.emit(Initiator.EventType.GRIP) - grabbed_right = false \ No newline at end of file + if grab_close&&!grabbed_left: + initiator.on_press.emit(Initiator.EventType.GRIP) + grabbed_left = true + elif !grab_close&&grabbed_left: + initiator.on_release.emit(Initiator.EventType.GRIP) + grabbed_left = false + +func _process_hand_right(hand: Node3D): + var index_tip = bone_attachments_right[Fingers.INDEX].get_node("Marker3D") + var thumb_tip = bone_attachments_right[Fingers.THUMB].get_node("Marker3D") + var middle_tip = bone_attachments_right[Fingers.MIDDLE].get_node("Marker3D") + + var _ray = ray_left if hand == hand_left else ray_right + var initiator = left_initiator if hand == hand_left else right_initiator + + 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) + + var trigger_close = distance_trigger <= press_distance + var grab_close = distance_grab <= grip_distance + + if trigger_close&&!pressed_right: + initiator.on_press.emit(Initiator.EventType.TRIGGER) + pressed_right = true + elif !trigger_close&&pressed_right: + initiator.on_release.emit(Initiator.EventType.TRIGGER) + pressed_right = false + + if grab_close&&!grabbed_right: + initiator.on_press.emit(Initiator.EventType.GRIP) + grabbed_right = true + elif !grab_close&&grabbed_right: + initiator.on_release.emit(Initiator.EventType.GRIP) + grabbed_right = false \ No newline at end of file diff --git a/app/content/system/hands/hands.tscn b/app/content/system/hands/hands.tscn index 517a26b..ce0eb3f 100644 --- a/app/content/system/hands/hands.tscn +++ b/app/content/system/hands/hands.tscn @@ -1,41 +1,24 @@ -[gd_scene load_steps=8 format=3 uid="uid://bsx12q23v8apy"] +[gd_scene load_steps=4 format=3 uid="uid://bsx12q23v8apy"] [ext_resource type="Script" path="res://content/system/hands/hands.gd" id="1_c4f76"] -[ext_resource type="PackedScene" uid="uid://c0kow4g10wolq" path="res://assets/models/hands_steam/right_hand.glb" id="1_uekbj"] -[ext_resource type="PackedScene" uid="uid://dt4ksvogfctkr" path="res://assets/models/hands_steam/left_hand.glb" id="2_n73lt"] [ext_resource type="PackedScene" uid="uid://bsjqdvkt0u87c" path="res://content/ui/components/button/button.tscn" id="3_te2p8"] -[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_3bjtw"] -transparency = 1 -albedo_color = Color(1, 1, 1, 0.705882) - [sub_resource type="CapsuleShape3D" id="CapsuleShape3D_dopke"] radius = 0.001 height = 0.02 -[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_n27ki"] -transparency = 1 -albedo_color = Color(1, 1, 1, 0.705882) - [node name="Hands" type="Node3D"] script = ExtResource("1_c4f76") -[node name="XRHandLeft" type="OpenXRHand" parent="."] +[node name="XRHandLeft" type="Node3D" parent="."] transform = Transform3D(0.999999, -1.39628e-11, 0, 9.48119e-12, 0.999999, -4.54747e-13, 0, 0, 0.999999, -0.25, 0, 0) -hand_skeleton = NodePath("left_hand/Armature_001/Skeleton3D") - -[node name="left_hand" parent="XRHandLeft" instance=ExtResource("2_n73lt")] -transform = Transform3D(1, 4.42441e-11, 0, -1.06936e-10, 1, 1.81899e-12, 5.82077e-11, -1.81899e-12, 1, 0, 0, 0) - -[node name="vr_glove_left_slim" parent="XRHandLeft/left_hand/Armature_001/Skeleton3D" index="0"] -material_override = SubResource("StandardMaterial3D_3bjtw") [node name="IndexTip" type="BoneAttachment3D" parent="XRHandLeft"] -transform = Transform3D(0.19221, -0.669965, -0.717079, 0.977075, 0.19881, 0.076153, 0.0915428, -0.715277, 0.692819, 0.0345973, 0.0355402, -0.164767) +transform = Transform3D(0.967526, 0.252326, -0.0150302, -0.0150302, 0.116784, 0.993043, 0.252326, -0.960569, 0.116784, -0.00665802, 0.0427913, -0.169868) bone_name = "Index_Tip_L" bone_idx = 9 use_external_skeleton = true -external_skeleton = NodePath("../left_hand/Armature_001/Skeleton3D") +external_skeleton = NodePath("") [node name="Marker3D" type="Marker3D" parent="XRHandLeft/IndexTip"] gizmo_extents = 0.02 @@ -51,21 +34,21 @@ transform = Transform3D(1, -7.45058e-09, -2.22045e-16, 7.45058e-09, 1, 0, 0, 0, shape = SubResource("CapsuleShape3D_dopke") [node name="ThumbTip" type="BoneAttachment3D" parent="XRHandLeft"] -transform = Transform3D(0.937246, 0.0284254, -0.347508, 0.0184905, 0.991216, 0.130949, 0.348178, -0.129157, 0.928488, 0.0498668, 0.0560917, -0.112777) +transform = Transform3D(0.967043, 0.24582, -0.0663439, -0.0663439, 0.494837, 0.86645, 0.24582, -0.833492, 0.494837, 0.0261569, 0.0891964, -0.0934418) bone_name = "Thumb_Tip_L" bone_idx = 4 use_external_skeleton = true -external_skeleton = NodePath("../left_hand/Armature_001/Skeleton3D") +external_skeleton = NodePath("") [node name="Marker3D" type="Marker3D" parent="XRHandLeft/ThumbTip"] gizmo_extents = 0.02 [node name="MiddleTip" type="BoneAttachment3D" parent="XRHandLeft"] -transform = Transform3D(0.0812012, -0.650531, -0.755125, 0.996577, 0.064817, 0.051326, 0.0155558, -0.756708, 0.653568, 0.032112, 0.00654224, -0.171612) +transform = Transform3D(0.98042, 0.196912, 0.00149799, 0.001498, -0.015065, 0.999885, 0.196912, -0.980305, -0.0150651, -0.00327212, -0.00771424, -0.176318) bone_name = "Middle_Tip_L" bone_idx = 14 use_external_skeleton = true -external_skeleton = NodePath("../left_hand/Armature_001/Skeleton3D") +external_skeleton = NodePath("") [node name="Marker3D" type="Marker3D" parent="XRHandLeft/MiddleTip"] gizmo_extents = 0.02 @@ -100,23 +83,15 @@ transform = Transform3D(1, 1.73472e-18, 0, 0, 1, 0, 0, 0, 1, 0.0600001, -5.68873 label = "humidity_mid" icon = true -[node name="XRHandRight" type="OpenXRHand" parent="."] -transform = Transform3D(0.999998, -0.000567105, 2.47889e-11, 0, -4.37113e-08, -0.999999, 0.000567104, 0.999999, -4.37113e-08, 0.264391, 0, 0) -hand = 1 -hand_skeleton = NodePath("right_hand/Armature/Skeleton3D") - -[node name="right_hand" parent="XRHandRight" instance=ExtResource("1_uekbj")] - -[node name="vr_glove_right_slim" parent="XRHandRight/right_hand/Armature/Skeleton3D" index="0"] -transform = Transform3D(1, 0, 4.7579e-13, 0, 1, 0, -1.34149e-12, 1.77636e-15, 1, 0, 0, 0) -material_override = SubResource("StandardMaterial3D_n27ki") +[node name="XRHandRight" type="Node3D" parent="."] +transform = Transform3D(0.999998, 0, 0, 0, 0.999999, 0, 0, 0, 0.999999, 0.264391, 0, 0) [node name="IndexTip" type="BoneAttachment3D" parent="XRHandRight"] -transform = Transform3D(0.19221, 0.669966, 0.717079, -0.091543, -0.715277, 0.69282, 0.977075, -0.19881, -0.0761527, -0.0345977, -0.164767, -0.0355401) +transform = Transform3D(0.967526, -0.252326, 0.0150302, 0.0150302, 0.116784, 0.993043, -0.252326, -0.960569, 0.116784, 0.00665802, 0.0427913, -0.169868) bone_name = "Index_Tip_R" bone_idx = 9 use_external_skeleton = true -external_skeleton = NodePath("../right_hand/Armature/Skeleton3D") +external_skeleton = NodePath("") [node name="Marker3D" type="Marker3D" parent="XRHandRight/IndexTip"] gizmo_extents = 0.02 @@ -132,21 +107,21 @@ transform = Transform3D(1, -7.45058e-09, -2.22045e-16, 7.45058e-09, 1, 0, 0, 0, shape = SubResource("CapsuleShape3D_dopke") [node name="ThumbTip" type="BoneAttachment3D" parent="XRHandRight"] -transform = Transform3D(0.937246, -0.0284254, 0.347508, -0.348179, -0.129158, 0.928488, 0.0184906, -0.991216, -0.130949, -0.0498677, -0.112777, -0.0560909) +transform = Transform3D(0.967042, -0.24582, 0.0663439, 0.0663439, 0.494837, 0.866449, -0.24582, -0.833492, 0.494837, -0.0261569, 0.0891963, -0.0934418) bone_name = "Thumb_Tip_R" bone_idx = 4 use_external_skeleton = true -external_skeleton = NodePath("../right_hand/Armature/Skeleton3D") +external_skeleton = NodePath("") [node name="Marker3D" type="Marker3D" parent="XRHandRight/ThumbTip"] gizmo_extents = 0.02 [node name="MiddleTip" type="BoneAttachment3D" parent="XRHandRight"] -transform = Transform3D(0.0812011, 0.650531, 0.755126, -0.0155557, -0.756709, 0.653568, 0.996576, -0.0648169, -0.0513262, -0.032112, -0.171612, -0.00654216) +transform = Transform3D(0.98042, -0.196912, -0.00149799, -0.001498, -0.015065, 0.999885, -0.196912, -0.980305, -0.0150651, 0.00327212, -0.00771424, -0.176318) bone_name = "Middle_Tip_R" bone_idx = 14 use_external_skeleton = true -external_skeleton = NodePath("../right_hand/Armature/Skeleton3D") +external_skeleton = NodePath("") [node name="Marker3D" type="Marker3D" parent="XRHandRight/MiddleTip"] gizmo_extents = 0.02 @@ -160,6 +135,3 @@ monitorable = false [node name="CollisionShape3D" type="CollisionShape3D" parent="XRHandRight/MiddleTip/TouchArea"] transform = Transform3D(1, -7.45058e-09, -2.22045e-16, 7.45058e-09, 1, 0, 0, 0, 1, 0, 0, 0) shape = SubResource("CapsuleShape3D_dopke") - -[editable path="XRHandLeft/left_hand"] -[editable path="XRHandRight/right_hand"] diff --git a/app/lib/home_apis/hass_ws/handlers/history.gd b/app/lib/home_apis/hass_ws/handlers/history.gd index eb2f5d1..5118057 100644 --- a/app/lib/home_apis/hass_ws/handlers/history.gd +++ b/app/lib/home_apis/hass_ws/handlers/history.gd @@ -32,4 +32,4 @@ func get_history(entity_id: String, start: String, end=null): "has_mean": meta_response.payload.result[0]["has_mean"], "unit_class": meta_response.payload.result[0]["unit_class"], "data": data_response.payload.result[entity_id] - } \ No newline at end of file + } diff --git a/app/lib/utils/touch/collide.gd b/app/lib/utils/touch/collide.gd index 55afa09..8912d80 100644 --- a/app/lib/utils/touch/collide.gd +++ b/app/lib/utils/touch/collide.gd @@ -4,24 +4,15 @@ extends Node3D const Finger = preload ("res://lib/utils/touch/finger.gd") const TipCollider = preload ("res://content/system/hands/tip_collider.tscn") -var tip_right: Node3D -var tip_left: Node3D +var tip: Node3D +var tip_body: RigidBody3D +var hand: Node3D +var hand_mesh: MeshInstance3D -var tip_left_body: RigidBody3D -var tip_right_body: RigidBody3D - -var hand_left: Node3D -var hand_right: Node3D -var hand_left_mesh: MeshInstance3D -var hand_right_mesh: MeshInstance3D - -func _init(hand_left: OpenXRHand, hand_right: OpenXRHand, tip_left: Node3D, tip_right: Node3D): - self.tip_right = tip_right - self.tip_left = tip_left - self.hand_left = hand_left - self.hand_right = hand_right - self.hand_left_mesh = hand_left.get_node("left_hand/Armature_001/Skeleton3D/vr_glove_left_slim") - self.hand_right_mesh = hand_right.get_node("right_hand/Armature/Skeleton3D/vr_glove_right_slim") +func _init(hand: Node3D, hand_mesh: MeshInstance3D, tip: Node3D): + self.tip = tip + self.hand = hand + self.hand_mesh = hand_mesh func _ready(): var body_container = Node3D.new() @@ -29,17 +20,12 @@ func _ready(): get_node("/root/Main/").add_child.call_deferred(body_container) - tip_right_body = TipCollider.instantiate() - tip_right_body.global_position = tip_right.global_position - body_container.add_child(tip_right_body) - - tip_left_body = TipCollider.instantiate() - tip_left_body.global_position = tip_left.global_position - body_container.add_child(tip_left_body) + tip_body = TipCollider.instantiate() + tip_body.global_position = tip.global_position + body_container.add_child(tip_body) func _physics_process(_delta): - _move_tip_rigidbody_to_bone(tip_left_body, tip_left) - _move_tip_rigidbody_to_bone(tip_right_body, tip_right) + _move_tip_rigidbody_to_bone(tip_body, tip) func _move_tip_rigidbody_to_bone(tip_rigidbody: RigidBody3D, tip_bone: Node3D): if tip_rigidbody.is_inside_tree() == false: @@ -47,7 +33,7 @@ func _move_tip_rigidbody_to_bone(tip_rigidbody: RigidBody3D, tip_bone: Node3D): var move_delta: Vector3 = tip_bone.global_position - tip_rigidbody.global_position - hand_right_mesh.global_position = hand_right.global_position - move_delta + hand_mesh.global_position = hand.global_position - move_delta # Snap back the rigidbody if it's too far away. if move_delta.length() > 0.1: @@ -56,4 +42,4 @@ func _move_tip_rigidbody_to_bone(tip_rigidbody: RigidBody3D, tip_bone: Node3D): var coef_force = 30.0 tip_rigidbody.apply_central_force(move_delta * coef_force) - tip_rigidbody.global_transform.basis = hand_right.global_transform.basis \ No newline at end of file + tip_rigidbody.global_transform.basis = hand.global_transform.basis diff --git a/app/lib/utils/touch/touch.gd b/app/lib/utils/touch/touch.gd index 4a75c7b..1c29ab9 100644 --- a/app/lib/utils/touch/touch.gd +++ b/app/lib/utils/touch/touch.gd @@ -8,18 +8,20 @@ var finger_areas: Dictionary var areas_entered = {} -func _init(finger_areas: Dictionary): - self.finger_areas = finger_areas +func add_finger(finger_type: Finger.Type, area: Area3D): + finger_areas[finger_type] = area -func _ready(): - for finger_type in finger_areas.keys(): - finger_areas[finger_type].area_entered.connect(func(area): - _on_area_entered(finger_type, area) - ) + area.area_entered.connect(func(entered_area): + _on_area_entered(finger_type, entered_area) + ) - finger_areas[finger_type].area_exited.connect(func(area): - _on_area_exited(finger_type, area) - ) + area.area_exited.connect(func(entered_area): + _on_area_exited(finger_type, entered_area) + ) + +func remove_finger(finger_type: Finger.Type): + if finger_areas.has(finger_type): + finger_areas.erase(finger_type) func _physics_process(_delta): for area in areas_entered.keys(): diff --git a/app/project.godot b/app/project.godot index bf26453..9e33be5 100644 --- a/app/project.godot +++ b/app/project.godot @@ -28,6 +28,7 @@ Store="*res://lib/globals/main_store.gd" EventSystem="*res://lib/globals/event_system.gd" House="*res://lib/globals/house_body.gd" Request="*res://lib/globals/request.gd" +TouchManager="*res://lib/utils/touch/touch.gd" [display]