@@ -68,11 +68,7 @@ protected override void OnEnable()
6868 }
6969
7070 // If we already found our subsystem, just return
71- if ( handSubsystem != null && handSubsystem . running )
72- {
73- handSubsystem . updatedHands += OnHandsUpdated ;
74- return ;
75- }
71+ if ( handSubsystem != null && handSubsystem . running ) { return ; }
7672
7773 List < XRHandSubsystem > subsystems = XRSubsystemHelpers . GetAllSubsystems < XRHandSubsystem > ( ) ;
7874 foreach ( XRHandSubsystem subsystem in subsystems )
@@ -81,7 +77,6 @@ protected override void OnEnable()
8177 {
8278 Debug . Log ( $ "Using { provider . handMeshDataSupplier . GetType ( ) } for hand visualization.") ;
8379 handSubsystem = subsystem ;
84- handSubsystem . updatedHands += OnHandsUpdated ;
8580 return ;
8681 }
8782 }
@@ -105,16 +100,6 @@ protected override void OnEnable()
105100 enabled = false ;
106101 }
107102
108- protected override void OnDisable ( )
109- {
110- base . OnDisable ( ) ;
111-
112- if ( handSubsystem != null )
113- {
114- handSubsystem . updatedHands -= OnHandsUpdated ;
115- }
116- }
117-
118103 protected void Update ( )
119104 {
120105 if ( ! ShouldRenderHand ( ) )
@@ -127,10 +112,65 @@ protected void Update()
127112 return ;
128113 }
129114
130- // This path is handled in the OnHandsUpdated event handler
131115 if ( handSubsystem != null && handSubsystem . running )
132116 {
133- return ;
117+ XRHandMeshDataQueryParams queryParams = new ( )
118+ {
119+ allocator = Unity . Collections . Allocator . Temp ,
120+ } ;
121+
122+ // Sometimes, the mesh update will fail, but that doesn't mean we don't have a valid mesh
123+ // So, reuse the last mesh until the subsystem tells us we're untracked
124+ if ( lastUpdatedFrame != Time . frameCount && ! handSubsystem . TryGetMeshData ( out result , ref queryParams ) )
125+ {
126+ return ;
127+ }
128+
129+ if ( ( handSubsystem . updateSuccessFlags & updateSuccessFlags ) != 0 )
130+ {
131+ lastUpdatedFrame = Time . frameCount ;
132+ XRHandMeshData handMeshData = HandNode == XRNode . LeftHand ? result . leftHand : result . rightHand ;
133+ handRenderer . enabled = true ;
134+ Mesh mesh = meshFilter . mesh ;
135+
136+ if ( handMeshData . positions . Length > 0 && handMeshData . indices . Length > 0 )
137+ {
138+ mesh . SetVertices ( handMeshData . positions ) ;
139+ Unity . Collections . NativeArray < int > indices = handMeshData . indices ;
140+ // This API appears to return CCW triangles, but Unity expects CW triangles
141+ for ( int i = 0 ; i < indices . Length ; i += 3 )
142+ {
143+ ( indices [ i + 1 ] , indices [ i + 2 ] ) = ( indices [ i + 2 ] , indices [ i + 1 ] ) ;
144+ }
145+ mesh . SetIndices ( indices , MeshTopology . Triangles , 0 ) ;
146+ mesh . RecalculateBounds ( ) ;
147+ }
148+
149+ if ( handMeshData . uvs . IsCreated && handMeshData . uvs . Length == mesh . vertexCount )
150+ {
151+ mesh . SetUVs ( 0 , handMeshData . uvs ) ;
152+ }
153+ else
154+ {
155+ mesh . uv = null ;
156+ }
157+
158+ if ( handMeshData . normals . IsCreated && handMeshData . normals . Length == mesh . vertexCount )
159+ {
160+ mesh . SetNormals ( handMeshData . normals ) ;
161+ }
162+ else
163+ {
164+ mesh . RecalculateNormals ( ) ;
165+ }
166+
167+ if ( handMeshData . TryGetRootPose ( out Pose rootPose ) )
168+ {
169+ transform . SetWorldPose ( PlayspaceUtilities . TransformPose ( rootPose ) ) ;
170+ }
171+ UpdateHandMaterial ( ) ;
172+ return ;
173+ }
134174 }
135175#if MROPENXR_PRESENT && ( UNITY_STANDALONE_WIN || UNITY_WSA || UNITY_ANDROID )
136176 else if ( handMeshTracker ! = null
@@ -160,72 +200,6 @@ protected void Update()
160200 handRenderer . enabled = false ;
161201 }
162202
163- private void OnHandsUpdated ( XRHandSubsystem subsystem , XRHandSubsystem . UpdateSuccessFlags successFlags , XRHandSubsystem . UpdateType updateType )
164- {
165- // Only update visualization on OnBeforeRender for the most accurate data
166- if ( updateType == XRHandSubsystem . UpdateType . Dynamic ) { return ; }
167-
168- XRHandMeshDataQueryParams queryParams = new ( )
169- {
170- allocator = Unity . Collections . Allocator . Temp ,
171- } ;
172-
173- if ( lastUpdatedFrame != Time . frameCount && ! subsystem . TryGetMeshData ( out result , ref queryParams ) )
174- {
175- return ;
176- }
177-
178- if ( ( successFlags & updateSuccessFlags ) != 0 )
179- {
180- lastUpdatedFrame = Time . frameCount ;
181- XRHandMeshData handMeshData = HandNode == XRNode . LeftHand ? result . leftHand : result . rightHand ;
182- handRenderer . enabled = true ;
183- Mesh mesh = meshFilter . mesh ;
184-
185- if ( handMeshData . positions . Length > 0 && handMeshData . indices . Length > 0 )
186- {
187- mesh . SetVertices ( handMeshData . positions ) ;
188- Unity . Collections . NativeArray < int > indices = handMeshData . indices ;
189- // This API appears to return CCW triangles, but Unity expects CW triangles
190- for ( int i = 0 ; i < indices . Length ; i += 3 )
191- {
192- ( indices [ i + 1 ] , indices [ i + 2 ] ) = ( indices [ i + 2 ] , indices [ i + 1 ] ) ;
193- }
194- mesh . SetIndices ( indices , MeshTopology . Triangles , 0 ) ;
195- mesh . RecalculateBounds ( ) ;
196- }
197-
198- if ( handMeshData . uvs . IsCreated && handMeshData . uvs . Length == mesh . vertexCount )
199- {
200- mesh . SetUVs ( 0 , handMeshData . uvs ) ;
201- }
202- else
203- {
204- mesh . uv = null ;
205- }
206-
207- if ( handMeshData . normals . IsCreated && handMeshData . normals . Length == mesh . vertexCount )
208- {
209- mesh . SetNormals ( handMeshData . normals ) ;
210- }
211- else
212- {
213- mesh . RecalculateNormals ( ) ;
214- }
215-
216- if ( handMeshData . TryGetRootPose ( out Pose rootPose ) )
217- {
218- transform . SetWorldPose ( PlayspaceUtilities . TransformPose ( rootPose ) ) ;
219- }
220-
221- UpdateHandMaterial ( ) ;
222- return ;
223- }
224-
225- // Hide the hand if we weren't able to obtain a valid mesh
226- handRenderer . enabled = false ;
227- }
228-
229203 protected override bool ShouldRenderHand ( )
230204 {
231205 // If we're missing anything, don't render the hand.
0 commit comments