Merge pull request #146 from Nitwel/fixes-2
Update Hands to look a lot cleaner
This commit is contained in:
commit
91e05f047d
295
app/addons/xr-autohandtracker/auto_handtracker.gd
Normal file
295
app/addons/xr-autohandtracker/auto_handtracker.gd
Normal file
|
@ -0,0 +1,295 @@
|
||||||
|
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
|
||||||
|
|
||||||
|
signal hand_active_changed(hand: int, active: bool)
|
||||||
|
|
||||||
|
# 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 "<none>")
|
||||||
|
|
||||||
|
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)
|
||||||
|
hand_active_changed.emit(hand, 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)
|
130
app/addons/xr-autohandtracker/auto_handtracker.tscn
Normal file
130
app/addons/xr-autohandtracker/auto_handtracker.tscn
Normal file
|
@ -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("../..")
|
215
app/addons/xr-autohandtracker/auto_tracker.gd
Normal file
215
app/addons/xr-autohandtracker/auto_tracker.gd
Normal file
|
@ -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)
|
||||||
|
|
60
app/addons/xr-autohandtracker/visible_handtrack_skeleton.gd
Normal file
60
app/addons/xr-autohandtracker/visible_handtrack_skeleton.gd
Normal file
|
@ -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)
|
25
app/assets/materials/hands.gdshader
Normal file
25
app/assets/materials/hands.gdshader
Normal file
|
@ -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);
|
||||||
|
}
|
||||||
|
|
3
app/assets/models/hands/Hand_low_L.gltf
Normal file
3
app/assets/models/hands/Hand_low_L.gltf
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:d258e8207dcf0824402a184007086eb4e1ae599996ee855549321536a35cf494
|
||||||
|
size 70342
|
34
app/assets/models/hands/Hand_low_L.gltf.import
Normal file
34
app/assets/models/hands/Hand_low_L.gltf.import
Normal file
|
@ -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
|
3
app/assets/models/hands/Hand_low_R.gltf
Normal file
3
app/assets/models/hands/Hand_low_R.gltf
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:19cbbf3c2fd3b8f0a1319056854975b99cdb6dfe3caa9b09018bb865a3964de1
|
||||||
|
size 70346
|
34
app/assets/models/hands/Hand_low_R.gltf.import
Normal file
34
app/assets/models/hands/Hand_low_R.gltf.import
Normal file
|
@ -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
|
|
@ -10,7 +10,7 @@
|
||||||
[sub_resource type="BoxShape3D" id="BoxShape3D_3qyo4"]
|
[sub_resource type="BoxShape3D" id="BoxShape3D_3qyo4"]
|
||||||
size = Vector3(0.32, 0.16, 0.02)
|
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
|
resource_local_to_scene = true
|
||||||
render_priority = 10
|
render_priority = 10
|
||||||
shader = ExtResource("6_40cd1")
|
shader = ExtResource("6_40cd1")
|
||||||
|
@ -25,7 +25,7 @@ shader_parameter/corner_radius = 0.8
|
||||||
shader_parameter/roughness = 0.3
|
shader_parameter/roughness = 0.3
|
||||||
shader_parameter/grain_amount = 0.02
|
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)
|
size = Vector2(0.32, 0.16)
|
||||||
|
|
||||||
[node name="Timer" type="StaticBody3D" groups=["entity"]]
|
[node name="Timer" type="StaticBody3D" groups=["entity"]]
|
||||||
|
@ -78,7 +78,7 @@ label = "stop"
|
||||||
icon = true
|
icon = true
|
||||||
|
|
||||||
[node name="Panel" parent="." instance=ExtResource("5_j3gsb")]
|
[node name="Panel" parent="." instance=ExtResource("5_j3gsb")]
|
||||||
material_override = SubResource("ShaderMaterial_cw188")
|
material_override = SubResource("ShaderMaterial_nktla")
|
||||||
mesh = SubResource("QuadMesh_ryeda")
|
mesh = SubResource("QuadMesh_mqjqg")
|
||||||
size = Vector2(0.32, 0.16)
|
size = Vector2(0.32, 0.16)
|
||||||
corner_radius = 0.8
|
corner_radius = 0.8
|
||||||
|
|
|
@ -86,6 +86,10 @@ func _on_grab_move(event: EventPointer):
|
||||||
if lock_rotation:
|
if lock_rotation:
|
||||||
get_parent().global_transform = TransformTools.rotate_around_point(get_parent().global_transform, get_parent().to_global(initial_point), initial_rotation - get_parent().global_rotation)
|
get_parent().global_transform = TransformTools.rotate_around_point(get_parent().global_transform, get_parent().to_global(initial_point), initial_rotation - get_parent().global_rotation)
|
||||||
|
|
||||||
|
if restrict_movement:
|
||||||
|
get_parent().global_position = restrict_movement.call(get_parent().global_position)
|
||||||
|
on_move.emit(get_parent().global_position, get_parent().global_rotation)
|
||||||
|
|
||||||
func _on_grab_up(event: EventPointer):
|
func _on_grab_up(event: EventPointer):
|
||||||
if event.initiator == initiator2:
|
if event.initiator == initiator2:
|
||||||
initiator2 = null
|
initiator2 = null
|
||||||
|
|
|
@ -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="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="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="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="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://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://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://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://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://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"]
|
[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"]
|
[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)
|
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")
|
script = ExtResource("1_uvrd4")
|
||||||
|
@ -41,20 +33,20 @@ enable_passthrough = true
|
||||||
[node name="XRControllerLeft" parent="XROrigin3D" instance=ExtResource("2_2lraw")]
|
[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)
|
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"]
|
[node name="IndexTip" parent="XROrigin3D/XRControllerLeft" index="6"]
|
||||||
transform = Transform3D(0.999999, -1.39633e-11, 0, 9.48075e-12, 1, 0, 0, 0, 1, 0.272616, 0.559282, -0.468369)
|
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)
|
||||||
tracker = &"right_hand"
|
|
||||||
pose = &"aim"
|
|
||||||
|
|
||||||
[node name="MeshInstance3D" type="MeshInstance3D" parent="XROrigin3D/XRControllerRight"]
|
[node name="ThumbTip" parent="XROrigin3D/XRControllerLeft" index="7"]
|
||||||
mesh = SubResource("BoxMesh_ir3co")
|
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")]
|
[node name="Palm" parent="XROrigin3D/XRControllerLeft" index="9"]
|
||||||
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)
|
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)
|
||||||
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")]
|
[node name="XRSimulator" parent="." instance=ExtResource("5_3qc8g")]
|
||||||
min_camera_height = 0.01
|
min_camera_height = 0.01
|
||||||
|
@ -74,3 +66,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)
|
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"]
|
||||||
|
[editable path="XROrigin3D/XRControllerLeft/hand_l"]
|
||||||
|
|
|
@ -1,10 +1,42 @@
|
||||||
extends XRController3D
|
extends XRController3D
|
||||||
|
|
||||||
const Entity = preload ("res://content/entities/entity.gd")
|
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 auto_hand = $AutoHandtracker
|
||||||
|
|
||||||
|
@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 area = $trash_bin/Area3D
|
||||||
@onready var trash_bin = $trash_bin
|
@onready var trash_bin = $trash_bin
|
||||||
@onready var animation = $AnimationPlayer
|
@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
|
||||||
|
var press_distance = 0.02
|
||||||
|
var grip_distance = 0.02
|
||||||
|
|
||||||
|
var pressed = false
|
||||||
|
var grabbed = false
|
||||||
|
|
||||||
var to_delete = []
|
var to_delete = []
|
||||||
var trash_bin_visible: bool = true:
|
var trash_bin_visible: bool = true:
|
||||||
|
@ -36,6 +68,8 @@ var trash_bin_large: bool = false:
|
||||||
func _ready():
|
func _ready():
|
||||||
trash_bin_visible = false
|
trash_bin_visible = false
|
||||||
|
|
||||||
|
_setup_hand()
|
||||||
|
|
||||||
EventSystem.on_grab_down.connect(func(event: EventPointer):
|
EventSystem.on_grab_down.connect(func(event: EventPointer):
|
||||||
trash_bin_visible=_get_entity(event.target) != null
|
trash_bin_visible=_get_entity(event.target) != null
|
||||||
)
|
)
|
||||||
|
@ -70,6 +104,39 @@ func _ready():
|
||||||
House.body.save_all_entities()
|
House.body.save_all_entities()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
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):
|
func _get_entity(node: Node):
|
||||||
if node is Entity:
|
if node is Entity:
|
||||||
return node
|
return node
|
||||||
|
@ -77,4 +144,43 @@ func _get_entity(node: Node):
|
||||||
if node.get_parent() == null:
|
if node.get_parent() == null:
|
||||||
return null
|
return null
|
||||||
|
|
||||||
return _get_entity(node.get_parent())
|
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)
|
||||||
|
|
||||||
|
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
|
||||||
|
)
|
||||||
|
|
||||||
|
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)
|
|
@ -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="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://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://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"]
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_m58yb"]
|
||||||
ao_enabled = true
|
ao_enabled = true
|
||||||
|
@ -94,6 +98,17 @@ _data = {
|
||||||
"add_trashbin": SubResource("Animation_hax52")
|
"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"]
|
[node name="XRControllerLeft" type="XRController3D"]
|
||||||
tracker = &"left_hand"
|
tracker = &"left_hand"
|
||||||
pose = &"aim"
|
pose = &"aim"
|
||||||
|
@ -120,3 +135,79 @@ libraries = {
|
||||||
|
|
||||||
[node name="Raycast" parent="." instance=ExtResource("4_n7lao")]
|
[node name="Raycast" parent="." instance=ExtResource("4_n7lao")]
|
||||||
is_right = false
|
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"]
|
||||||
|
|
72
app/content/system/controller_right/controller_right.gd
Normal file
72
app/content/system/controller_right/controller_right.gd
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
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 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
|
||||||
|
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)
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
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
|
80
app/content/system/controller_right/controller_right.tscn
Normal file
80
app/content/system/controller_right/controller_right.tscn
Normal file
|
@ -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"]
|
8
app/content/system/controller_right/hands_material.tres
Normal file
8
app/content/system/controller_right/hands_material.tres
Normal file
|
@ -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)
|
|
@ -8,8 +8,6 @@ const Collide = preload ("res://lib/utils/touch/collide.gd")
|
||||||
const Miniature = preload ("res://content/system/house/mini/miniature.gd")
|
const Miniature = preload ("res://content/system/house/mini/miniature.gd")
|
||||||
|
|
||||||
@onready var main = $"/root/Main"
|
@onready var main = $"/root/Main"
|
||||||
@onready var hand_right: OpenXRHand = $XRHandRight
|
|
||||||
@onready var hand_left: OpenXRHand = $XRHandLeft
|
|
||||||
@onready var palm = $XRHandLeft/Palm
|
@onready var palm = $XRHandLeft/Palm
|
||||||
@onready var quick_actions = $XRHandLeft/Palm/QuickActions
|
@onready var quick_actions = $XRHandLeft/Palm/QuickActions
|
||||||
@onready var mini_view_button = $XRHandLeft/Palm/QuickActions/MiniView
|
@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
|
@onready var humidity_button = $XRHandLeft/Palm/QuickActions/Humidity
|
||||||
@export var ray_left: RayCast3D
|
@export var ray_left: RayCast3D
|
||||||
@export var ray_right: 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 left_initiator: Initiator = Initiator.new()
|
||||||
var right_initiator: Initiator = Initiator.new()
|
var right_initiator: Initiator = Initiator.new()
|
||||||
var touch: Touch
|
var touch: Touch
|
||||||
|
@ -84,13 +90,13 @@ func _process(_delta):
|
||||||
if quick_actions.is_inside_tree(): palm.remove_child(quick_actions)
|
if quick_actions.is_inside_tree(): palm.remove_child(quick_actions)
|
||||||
|
|
||||||
func _physics_process(_delta):
|
func _physics_process(_delta):
|
||||||
_process_hand(hand_left)
|
_process_hand_left(hand_left)
|
||||||
_process_hand(hand_right)
|
_process_hand_right(hand_right)
|
||||||
|
|
||||||
func _process_hand(hand: OpenXRHand):
|
func _process_hand_left(hand: Node3D):
|
||||||
var index_tip = hand.get_node("IndexTip/Marker3D")
|
var index_tip = bone_attachments_left[Fingers.INDEX].get_node("Marker3D")
|
||||||
var thumb_tip = hand.get_node("ThumbTip/Marker3D")
|
var thumb_tip = bone_attachments_left[Fingers.THUMB].get_node("Marker3D")
|
||||||
var middle_tip = hand.get_node("MiddleTip/Marker3D")
|
var middle_tip = bone_attachments_left[Fingers.MIDDLE].get_node("Marker3D")
|
||||||
|
|
||||||
var _ray = ray_left if hand == hand_left else ray_right
|
var _ray = ray_left if hand == hand_left else ray_right
|
||||||
var initiator = left_initiator if hand == hand_left else right_initiator
|
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 trigger_close = distance_trigger <= press_distance
|
||||||
var grab_close = distance_grab <= grip_distance
|
var grab_close = distance_grab <= grip_distance
|
||||||
|
|
||||||
if hand == hand_left:
|
if trigger_close&&!pressed_left:
|
||||||
if trigger_close&&!pressed_left:
|
initiator.on_press.emit(Initiator.EventType.TRIGGER)
|
||||||
initiator.on_press.emit(Initiator.EventType.TRIGGER)
|
pressed_left = true
|
||||||
pressed_left = true
|
elif !trigger_close&&pressed_left:
|
||||||
elif !trigger_close&&pressed_left:
|
initiator.on_release.emit(Initiator.EventType.TRIGGER)
|
||||||
initiator.on_release.emit(Initiator.EventType.TRIGGER)
|
pressed_left = false
|
||||||
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 grab_close&&!grabbed_right:
|
if grab_close&&!grabbed_left:
|
||||||
initiator.on_press.emit(Initiator.EventType.GRIP)
|
initiator.on_press.emit(Initiator.EventType.GRIP)
|
||||||
grabbed_right = true
|
grabbed_left = true
|
||||||
elif !grab_close&&grabbed_right:
|
elif !grab_close&&grabbed_left:
|
||||||
initiator.on_release.emit(Initiator.EventType.GRIP)
|
initiator.on_release.emit(Initiator.EventType.GRIP)
|
||||||
grabbed_right = false
|
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
|
|
@ -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="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"]
|
[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"]
|
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_dopke"]
|
||||||
radius = 0.001
|
radius = 0.001
|
||||||
height = 0.02
|
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"]
|
[node name="Hands" type="Node3D"]
|
||||||
script = ExtResource("1_c4f76")
|
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)
|
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"]
|
[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_name = "Index_Tip_L"
|
||||||
bone_idx = 9
|
bone_idx = 9
|
||||||
use_external_skeleton = true
|
use_external_skeleton = true
|
||||||
external_skeleton = NodePath("../left_hand/Armature_001/Skeleton3D")
|
external_skeleton = NodePath("")
|
||||||
|
|
||||||
[node name="Marker3D" type="Marker3D" parent="XRHandLeft/IndexTip"]
|
[node name="Marker3D" type="Marker3D" parent="XRHandLeft/IndexTip"]
|
||||||
gizmo_extents = 0.02
|
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")
|
shape = SubResource("CapsuleShape3D_dopke")
|
||||||
|
|
||||||
[node name="ThumbTip" type="BoneAttachment3D" parent="XRHandLeft"]
|
[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_name = "Thumb_Tip_L"
|
||||||
bone_idx = 4
|
bone_idx = 4
|
||||||
use_external_skeleton = true
|
use_external_skeleton = true
|
||||||
external_skeleton = NodePath("../left_hand/Armature_001/Skeleton3D")
|
external_skeleton = NodePath("")
|
||||||
|
|
||||||
[node name="Marker3D" type="Marker3D" parent="XRHandLeft/ThumbTip"]
|
[node name="Marker3D" type="Marker3D" parent="XRHandLeft/ThumbTip"]
|
||||||
gizmo_extents = 0.02
|
gizmo_extents = 0.02
|
||||||
|
|
||||||
[node name="MiddleTip" type="BoneAttachment3D" parent="XRHandLeft"]
|
[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_name = "Middle_Tip_L"
|
||||||
bone_idx = 14
|
bone_idx = 14
|
||||||
use_external_skeleton = true
|
use_external_skeleton = true
|
||||||
external_skeleton = NodePath("../left_hand/Armature_001/Skeleton3D")
|
external_skeleton = NodePath("")
|
||||||
|
|
||||||
[node name="Marker3D" type="Marker3D" parent="XRHandLeft/MiddleTip"]
|
[node name="Marker3D" type="Marker3D" parent="XRHandLeft/MiddleTip"]
|
||||||
gizmo_extents = 0.02
|
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"
|
label = "humidity_mid"
|
||||||
icon = true
|
icon = true
|
||||||
|
|
||||||
[node name="XRHandRight" type="OpenXRHand" parent="."]
|
[node name="XRHandRight" type="Node3D" 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)
|
transform = Transform3D(0.999998, 0, 0, 0, 0.999999, 0, 0, 0, 0.999999, 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="IndexTip" type="BoneAttachment3D" parent="XRHandRight"]
|
[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_name = "Index_Tip_R"
|
||||||
bone_idx = 9
|
bone_idx = 9
|
||||||
use_external_skeleton = true
|
use_external_skeleton = true
|
||||||
external_skeleton = NodePath("../right_hand/Armature/Skeleton3D")
|
external_skeleton = NodePath("")
|
||||||
|
|
||||||
[node name="Marker3D" type="Marker3D" parent="XRHandRight/IndexTip"]
|
[node name="Marker3D" type="Marker3D" parent="XRHandRight/IndexTip"]
|
||||||
gizmo_extents = 0.02
|
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")
|
shape = SubResource("CapsuleShape3D_dopke")
|
||||||
|
|
||||||
[node name="ThumbTip" type="BoneAttachment3D" parent="XRHandRight"]
|
[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_name = "Thumb_Tip_R"
|
||||||
bone_idx = 4
|
bone_idx = 4
|
||||||
use_external_skeleton = true
|
use_external_skeleton = true
|
||||||
external_skeleton = NodePath("../right_hand/Armature/Skeleton3D")
|
external_skeleton = NodePath("")
|
||||||
|
|
||||||
[node name="Marker3D" type="Marker3D" parent="XRHandRight/ThumbTip"]
|
[node name="Marker3D" type="Marker3D" parent="XRHandRight/ThumbTip"]
|
||||||
gizmo_extents = 0.02
|
gizmo_extents = 0.02
|
||||||
|
|
||||||
[node name="MiddleTip" type="BoneAttachment3D" parent="XRHandRight"]
|
[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_name = "Middle_Tip_R"
|
||||||
bone_idx = 14
|
bone_idx = 14
|
||||||
use_external_skeleton = true
|
use_external_skeleton = true
|
||||||
external_skeleton = NodePath("../right_hand/Armature/Skeleton3D")
|
external_skeleton = NodePath("")
|
||||||
|
|
||||||
[node name="Marker3D" type="Marker3D" parent="XRHandRight/MiddleTip"]
|
[node name="Marker3D" type="Marker3D" parent="XRHandRight/MiddleTip"]
|
||||||
gizmo_extents = 0.02
|
gizmo_extents = 0.02
|
||||||
|
@ -160,6 +135,3 @@ monitorable = false
|
||||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="XRHandRight/MiddleTip/TouchArea"]
|
[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)
|
transform = Transform3D(1, -7.45058e-09, -2.22045e-16, 7.45058e-09, 1, 0, 0, 0, 1, 0, 0, 0)
|
||||||
shape = SubResource("CapsuleShape3D_dopke")
|
shape = SubResource("CapsuleShape3D_dopke")
|
||||||
|
|
||||||
[editable path="XRHandLeft/left_hand"]
|
|
||||||
[editable path="XRHandRight/right_hand"]
|
|
||||||
|
|
|
@ -32,4 +32,4 @@ func get_history(entity_id: String, start: String, end=null):
|
||||||
"has_mean": meta_response.payload.result[0]["has_mean"],
|
"has_mean": meta_response.payload.result[0]["has_mean"],
|
||||||
"unit_class": meta_response.payload.result[0]["unit_class"],
|
"unit_class": meta_response.payload.result[0]["unit_class"],
|
||||||
"data": data_response.payload.result[entity_id]
|
"data": data_response.payload.result[entity_id]
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,24 +4,15 @@ extends Node3D
|
||||||
const Finger = preload ("res://lib/utils/touch/finger.gd")
|
const Finger = preload ("res://lib/utils/touch/finger.gd")
|
||||||
const TipCollider = preload ("res://content/system/hands/tip_collider.tscn")
|
const TipCollider = preload ("res://content/system/hands/tip_collider.tscn")
|
||||||
|
|
||||||
var tip_right: Node3D
|
var tip: Node3D
|
||||||
var tip_left: Node3D
|
var tip_body: RigidBody3D
|
||||||
|
var hand: Node3D
|
||||||
|
var hand_mesh: MeshInstance3D
|
||||||
|
|
||||||
var tip_left_body: RigidBody3D
|
func _init(hand: Node3D, hand_mesh: MeshInstance3D, tip: Node3D):
|
||||||
var tip_right_body: RigidBody3D
|
self.tip = tip
|
||||||
|
self.hand = hand
|
||||||
var hand_left: Node3D
|
self.hand_mesh = hand_mesh
|
||||||
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 _ready():
|
func _ready():
|
||||||
var body_container = Node3D.new()
|
var body_container = Node3D.new()
|
||||||
|
@ -29,17 +20,12 @@ func _ready():
|
||||||
|
|
||||||
get_node("/root/Main/").add_child.call_deferred(body_container)
|
get_node("/root/Main/").add_child.call_deferred(body_container)
|
||||||
|
|
||||||
tip_right_body = TipCollider.instantiate()
|
tip_body = TipCollider.instantiate()
|
||||||
tip_right_body.global_position = tip_right.global_position
|
tip_body.global_position = tip.global_position
|
||||||
body_container.add_child(tip_right_body)
|
body_container.add_child(tip_body)
|
||||||
|
|
||||||
tip_left_body = TipCollider.instantiate()
|
|
||||||
tip_left_body.global_position = tip_left.global_position
|
|
||||||
body_container.add_child(tip_left_body)
|
|
||||||
|
|
||||||
func _physics_process(_delta):
|
func _physics_process(_delta):
|
||||||
_move_tip_rigidbody_to_bone(tip_left_body, tip_left)
|
_move_tip_rigidbody_to_bone(tip_body, tip)
|
||||||
_move_tip_rigidbody_to_bone(tip_right_body, tip_right)
|
|
||||||
|
|
||||||
func _move_tip_rigidbody_to_bone(tip_rigidbody: RigidBody3D, tip_bone: Node3D):
|
func _move_tip_rigidbody_to_bone(tip_rigidbody: RigidBody3D, tip_bone: Node3D):
|
||||||
if tip_rigidbody.is_inside_tree() == false:
|
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
|
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.
|
# Snap back the rigidbody if it's too far away.
|
||||||
if move_delta.length() > 0.1:
|
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
|
var coef_force = 30.0
|
||||||
tip_rigidbody.apply_central_force(move_delta * coef_force)
|
tip_rigidbody.apply_central_force(move_delta * coef_force)
|
||||||
tip_rigidbody.global_transform.basis = hand_right.global_transform.basis
|
tip_rigidbody.global_transform.basis = hand.global_transform.basis
|
||||||
|
|
|
@ -8,18 +8,20 @@ var finger_areas: Dictionary
|
||||||
|
|
||||||
var areas_entered = {}
|
var areas_entered = {}
|
||||||
|
|
||||||
func _init(finger_areas: Dictionary):
|
func add_finger(finger_type: Finger.Type, area: Area3D):
|
||||||
self.finger_areas = finger_areas
|
finger_areas[finger_type] = area
|
||||||
|
|
||||||
func _ready():
|
area.area_entered.connect(func(entered_area):
|
||||||
for finger_type in finger_areas.keys():
|
_on_area_entered(finger_type, entered_area)
|
||||||
finger_areas[finger_type].area_entered.connect(func(area):
|
)
|
||||||
_on_area_entered(finger_type, area)
|
|
||||||
)
|
|
||||||
|
|
||||||
finger_areas[finger_type].area_exited.connect(func(area):
|
area.area_exited.connect(func(entered_area):
|
||||||
_on_area_exited(finger_type, 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):
|
func _physics_process(_delta):
|
||||||
for area in areas_entered.keys():
|
for area in areas_entered.keys():
|
||||||
|
|
|
@ -28,6 +28,7 @@ Store="*res://lib/globals/main_store.gd"
|
||||||
EventSystem="*res://lib/globals/event_system.gd"
|
EventSystem="*res://lib/globals/event_system.gd"
|
||||||
House="*res://lib/globals/house_body.gd"
|
House="*res://lib/globals/house_body.gd"
|
||||||
Request="*res://lib/globals/request.gd"
|
Request="*res://lib/globals/request.gd"
|
||||||
|
TouchManager="*res://lib/utils/touch/touch.gd"
|
||||||
|
|
||||||
[display]
|
[display]
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user