2727
2828vtkStandardNewMacro (vtkOpenVRCamera);
2929
30- // ------------------------------------------------------------------------------
31- vtkOpenVRCamera::vtkOpenVRCamera ()
32- {
33- this ->LeftEyeProjection = nullptr ;
34- this ->RightEyeProjection = nullptr ;
35-
36- this ->LeftEyeTCDCMatrix = vtkMatrix4x4::New ();
37- this ->RightEyeTCDCMatrix = vtkMatrix4x4::New ();
30+ // not default due to vtkNew
31+ vtkOpenVRCamera::vtkOpenVRCamera (){};
32+ vtkOpenVRCamera::~vtkOpenVRCamera (){};
3833
39- // approximate for Vive
40- // we use the projection matrix directly from the vive
41- // so this is just to help make view <--> display
42- // adjustments reasonable, not correct, just reasonable
43- this ->SetViewAngle (110.0 );
44- }
34+ // a reminder, with vtk order matrices multiplcation goes right to left
35+ // e.g. vtkMatrix4x4::Multiply(BtoC, AtoB, AtoC);
4536
46- // ------------------------------------------------------------------------------
47- vtkOpenVRCamera::~vtkOpenVRCamera ()
37+ namespace
38+ {
39+ void setMatrixFromOpenVRMatrix (vtkMatrix4x4* result, const vr::HmdMatrix34_t& vrMat)
4840{
49- if (this ->LeftEyeProjection )
41+ // because openvr is in left handed coords we
42+ // have to invert z, apply the transform, then invert z again
43+ for (vtkIdType i = 0 ; i < 3 ; ++i)
5044 {
51- this -> LeftEyeProjection -> Delete ();
52- this -> RightEyeProjection -> Delete ();
53- this -> LeftEyeProjection = nullptr ;
54- this -> RightEyeProjection = nullptr ;
45+ for (vtkIdType j = 0 ; j < 4 ; ++j)
46+ {
47+ result-> SetElement (i, j, ((i == 2 ) != (j == 2 ) ? - 1 : 1 ) * vrMat. m [i][j]) ;
48+ }
5549 }
5650
57- this ->LeftEyeTCDCMatrix ->Delete ();
58- this ->RightEyeTCDCMatrix ->Delete ();
51+ // Add last row
52+ result->SetElement (3 , 0 , 0.0 );
53+ result->SetElement (3 , 1 , 0.0 );
54+ result->SetElement (3 , 2 , 0.0 );
55+ result->SetElement (3 , 3 , 1.0 );
56+ result->Invert ();
57+ }
5958}
6059
6160// ------------------------------------------------------------------------------
62- void vtkOpenVRCamera::GetHMDEyePoses (vtkRenderer* ren)
61+ // we could try to do some smart caching here where we only
62+ // check the eyetohead transform when the ipd changes etc
63+ void vtkOpenVRCamera::UpdateHMDToEyeMatrices (vtkRenderer* ren)
6364{
6465 vtkOpenVRRenderWindow* win = vtkOpenVRRenderWindow::SafeDownCast (ren->GetRenderWindow ());
6566
6667 vr::IVRSystem* hMD = win->GetHMD ();
6768
68- // left handed coordinate system so have to -1*Z
6969 vr::HmdMatrix34_t matEye = hMD->GetEyeToHeadTransform (vr::Eye_Left);
70- this ->LeftEyePose [0 ] = matEye.m [0 ][3 ];
71- this ->LeftEyePose [1 ] = matEye.m [1 ][3 ];
72- this ->LeftEyePose [2 ] = -matEye.m [2 ][3 ];
70+ setMatrixFromOpenVRMatrix (this ->HMDToLeftEyeMatrix , matEye);
7371
7472 matEye = hMD->GetEyeToHeadTransform (vr::Eye_Right);
75- this ->RightEyePose [0 ] = matEye.m [0 ][3 ];
76- this ->RightEyePose [1 ] = matEye.m [1 ][3 ];
77- this ->RightEyePose [2 ] = -matEye.m [2 ][3 ];
73+ setMatrixFromOpenVRMatrix (this ->HMDToRightEyeMatrix , matEye);
7874}
7975
8076// ------------------------------------------------------------------------------
81- void vtkOpenVRCamera::GetHMDEyeProjections (vtkRenderer* ren)
77+ void vtkOpenVRCamera::UpdateWorldToEyeMatrices (vtkRenderer* ren)
78+ {
79+ // could do this next call only every now and then as these matrices
80+ // rarely change typically only when the user is changing the ipd
81+ this ->UpdateHMDToEyeMatrices (ren);
82+
83+ vtkOpenVRRenderWindow* win = vtkOpenVRRenderWindow::SafeDownCast (ren->GetRenderWindow ());
84+
85+ auto hmdHandle = win->GetDeviceHandleForOpenVRHandle (vr::k_unTrackedDeviceIndex_Hmd);
86+
87+ // first we get the physicalToHMDMatrix (by inverting deviceToPhysical for the HMD)
88+ this ->PhysicalToHMDMatrix ->DeepCopy (win->GetDeviceToPhysicalMatrixForDeviceHandle (hmdHandle));
89+ this ->PhysicalToHMDMatrix ->Invert ();
90+
91+ // compute the physicalToEye matrices
92+ vtkMatrix4x4::Multiply4x4 (
93+ this ->HMDToLeftEyeMatrix , this ->PhysicalToHMDMatrix , this ->PhysicalToLeftEyeMatrix );
94+ vtkMatrix4x4::Multiply4x4 (
95+ this ->HMDToRightEyeMatrix , this ->PhysicalToHMDMatrix , this ->PhysicalToRightEyeMatrix );
96+
97+ // get the world to physical matrix by inverting phsycialToWorld
98+ win->GetPhysicalToWorldMatrix (this ->WorldToPhysicalMatrix );
99+ this ->WorldToPhysicalMatrix ->Invert ();
100+
101+ // compute the world to eye matrices
102+ vtkMatrix4x4::Multiply4x4 (
103+ this ->PhysicalToLeftEyeMatrix , this ->WorldToPhysicalMatrix , this ->WorldToLeftEyeMatrix );
104+ vtkMatrix4x4::Multiply4x4 (
105+ this ->PhysicalToRightEyeMatrix , this ->WorldToPhysicalMatrix , this ->WorldToRightEyeMatrix );
106+ }
107+
108+ // ------------------------------------------------------------------------------
109+ void vtkOpenVRCamera::UpdateEyeToProjectionMatrices (vtkRenderer* ren)
82110{
83111 vtkOpenVRRenderWindow* win = vtkOpenVRRenderWindow::SafeDownCast (ren->GetRenderWindow ());
84112
@@ -97,52 +125,29 @@ void vtkOpenVRCamera::GetHMDEyeProjections(vtkRenderer* ren)
97125 ymin = fymin * znear;
98126 ymax = fymax * znear;
99127
100- this ->LeftEyeProjection ->Zero ();
101- this ->LeftEyeProjection ->SetElement (0 , 0 , 2 * znear / (xmax - xmin));
102- this ->LeftEyeProjection ->SetElement (1 , 1 , 2 * znear / (ymax - ymin));
103- this ->LeftEyeProjection ->SetElement (2 , 0 , (xmin + xmax) / (xmax - xmin));
104- this ->LeftEyeProjection ->SetElement (2 , 1 , (ymin + ymax) / (ymax - ymin));
105- this ->LeftEyeProjection ->SetElement (2 , 2 , -(znear + zfar) / (zfar - znear));
106- this ->LeftEyeProjection ->SetElement (2 , 3 , -1 );
107- this ->LeftEyeProjection ->SetElement (3 , 2 , -2 * znear * zfar / (zfar - znear));
128+ this ->LeftEyeToProjectionMatrix ->Zero ();
129+ this ->LeftEyeToProjectionMatrix ->SetElement (0 , 0 , 2 * znear / (xmax - xmin));
130+ this ->LeftEyeToProjectionMatrix ->SetElement (1 , 1 , 2 * znear / (ymax - ymin));
131+ this ->LeftEyeToProjectionMatrix ->SetElement (0 , 2 , (xmin + xmax) / (xmax - xmin));
132+ this ->LeftEyeToProjectionMatrix ->SetElement (1 , 2 , (ymin + ymax) / (ymax - ymin));
133+ this ->LeftEyeToProjectionMatrix ->SetElement (2 , 2 , -(znear + zfar) / (zfar - znear));
134+ this ->LeftEyeToProjectionMatrix ->SetElement (3 , 2 , -1 );
135+ this ->LeftEyeToProjectionMatrix ->SetElement (2 , 3 , -2 * znear * zfar / (zfar - znear));
108136
109137 hMD->GetProjectionRaw (vr::Eye_Right, &fxmin, &fxmax, &fymin, &fymax);
110138 xmin = fxmin * znear;
111139 xmax = fxmax * znear;
112140 ymin = fymin * znear;
113141 ymax = fymax * znear;
114142
115- this ->RightEyeProjection ->Zero ();
116- this ->RightEyeProjection ->SetElement (0 , 0 , 2 * znear / (xmax - xmin));
117- this ->RightEyeProjection ->SetElement (1 , 1 , 2 * znear / (ymax - ymin));
118- this ->RightEyeProjection ->SetElement (2 , 0 , (xmin + xmax) / (xmax - xmin));
119- this ->RightEyeProjection ->SetElement (2 , 1 , (ymin + ymax) / (ymax - ymin));
120- this ->RightEyeProjection ->SetElement (2 , 2 , -(znear + zfar) / (zfar - znear));
121- this ->RightEyeProjection ->SetElement (2 , 3 , -1 );
122- this ->RightEyeProjection ->SetElement (3 , 2 , -2 * znear * zfar / (zfar - znear));
123- }
124-
125- void vtkOpenVRCamera::ApplyEyePose (vtkVRRenderWindow* win, bool left, double factor)
126- {
127- double physicalScale = win->GetPhysicalScale ();
128-
129- double * dop = this ->GetDirectionOfProjection ();
130- double * vup = this ->GetViewUp ();
131- double vright[3 ];
132- vtkMath::Cross (dop, vup, vright);
133-
134- double * offset = (left ? this ->LeftEyePose : this ->RightEyePose );
135- double newOffset[3 ];
136- newOffset[0 ] =
137- factor * (offset[0 ] * vright[0 ] + offset[1 ] * vup[0 ] - offset[2 ] * dop[0 ]) * physicalScale;
138- newOffset[1 ] =
139- factor * (offset[0 ] * vright[1 ] + offset[1 ] * vup[1 ] - offset[2 ] * dop[1 ]) * physicalScale;
140- newOffset[2 ] =
141- factor * (offset[0 ] * vright[2 ] + offset[1 ] * vup[2 ] - offset[2 ] * dop[2 ]) * physicalScale;
142- double * pos = this ->GetPosition ();
143- this ->SetPosition (pos[0 ] + newOffset[0 ], pos[1 ] + newOffset[1 ], pos[2 ] + newOffset[2 ]);
144- double * fp = this ->GetFocalPoint ();
145- this ->SetFocalPoint (fp[0 ] + newOffset[0 ], fp[1 ] + newOffset[1 ], fp[2 ] + newOffset[2 ]);
143+ this ->RightEyeToProjectionMatrix ->Zero ();
144+ this ->RightEyeToProjectionMatrix ->SetElement (0 , 0 , 2 * znear / (xmax - xmin));
145+ this ->RightEyeToProjectionMatrix ->SetElement (1 , 1 , 2 * znear / (ymax - ymin));
146+ this ->RightEyeToProjectionMatrix ->SetElement (0 , 2 , (xmin + xmax) / (xmax - xmin));
147+ this ->RightEyeToProjectionMatrix ->SetElement (1 , 2 , (ymin + ymax) / (ymax - ymin));
148+ this ->RightEyeToProjectionMatrix ->SetElement (2 , 2 , -(znear + zfar) / (zfar - znear));
149+ this ->RightEyeToProjectionMatrix ->SetElement (3 , 2 , -1 );
150+ this ->RightEyeToProjectionMatrix ->SetElement (2 , 3 , -2 * znear * zfar / (zfar - znear));
146151}
147152
148153// ------------------------------------------------------------------------------
@@ -156,14 +161,6 @@ void vtkOpenVRCamera::Render(vtkRenderer* ren)
156161 int renSize[2 ];
157162 win->GetRenderBufferSize (renSize[0 ], renSize[1 ]);
158163
159- // get the eye pose and projection matricies once
160- if (!this ->LeftEyeProjection )
161- {
162- this ->LeftEyeProjection = vtkMatrix4x4::New ();
163- this ->RightEyeProjection = vtkMatrix4x4::New ();
164- this ->GetHMDEyePoses (ren);
165- }
166-
167164 // if were on a stereo renderer draw to special parts of screen
168165 if (this ->LeftEye )
169166 {
@@ -172,12 +169,6 @@ void vtkOpenVRCamera::Render(vtkRenderer* ren)
172169 {
173170 ostate->vtkglEnable (GL_MULTISAMPLE);
174171 }
175-
176- // adjust for left eye position
177- if (!ren->GetSelector ())
178- {
179- this ->ApplyEyePose (win, true , 1.0 );
180- }
181172 }
182173 else
183174 {
@@ -186,14 +177,6 @@ void vtkOpenVRCamera::Render(vtkRenderer* ren)
186177 {
187178 ostate->vtkglEnable (GL_MULTISAMPLE);
188179 }
189-
190- if (!ren->GetSelector ())
191- {
192- // adjust for left eye position
193- this ->ApplyEyePose (win, true , -1.0 );
194- // adjust for right eye position
195- this ->ApplyEyePose (win, false , 1.0 );
196- }
197180 }
198181
199182 ostate->vtkglViewport (0 , 0 , renSize[0 ], renSize[1 ]);
@@ -206,133 +189,3 @@ void vtkOpenVRCamera::Render(vtkRenderer* ren)
206189
207190 vtkOpenGLCheckErrorMacro (" failed after Render" );
208191}
209-
210- // ------------------------------------------------------------------------------
211- void vtkOpenVRCamera::GetKeyMatrices (vtkRenderer* ren, vtkMatrix4x4*& wcvc, vtkMatrix3x3*& normMat,
212- vtkMatrix4x4*& vcdc, vtkMatrix4x4*& wcdc)
213- {
214- if (ren->GetSelector ())
215- {
216- return this ->Superclass ::GetKeyMatrices (ren, wcvc, normMat, vcdc, wcdc);
217- }
218-
219- // has the camera changed?
220- if (ren != this ->LastRenderer || this ->MTime > this ->KeyMatrixTime ||
221- ren->GetMTime () > this ->KeyMatrixTime )
222- {
223- vtkMatrix4x4* w2v = this ->GetModelViewTransformMatrix ();
224- this ->WCVCMatrix ->DeepCopy (w2v);
225-
226- if (this ->LeftEye )
227- {
228- this ->GetHMDEyeProjections (ren);
229-
230- // only compute normal matrix once
231- for (int i = 0 ; i < 3 ; ++i)
232- {
233- for (int j = 0 ; j < 3 ; ++j)
234- {
235- this ->NormalMatrix ->SetElement (i, j, w2v->GetElement (i, j));
236- }
237- }
238- this ->NormalMatrix ->Invert ();
239- }
240-
241- this ->WCVCMatrix ->Transpose ();
242-
243- if (this ->LeftEye )
244- {
245- vtkOpenVRRenderWindow* win = vtkOpenVRRenderWindow::SafeDownCast (ren->GetRenderWindow ());
246-
247- vtkMatrix4x4::Multiply4x4 (this ->WCVCMatrix , this ->LeftEyeProjection , this ->WCDCMatrix );
248-
249- // build the tracking to device coordinate matrix
250- this ->PoseTransform ->Identity ();
251- double trans[3 ];
252- win->GetPhysicalTranslation (trans);
253- this ->PoseTransform ->Translate (-trans[0 ], -trans[1 ], -trans[2 ]);
254- double scale = win->GetPhysicalScale ();
255- this ->PoseTransform ->Scale (scale, scale, scale);
256-
257- // deal with Vive to World rotations
258- double * vup = win->GetPhysicalViewUp ();
259- double * dop = win->GetPhysicalViewDirection ();
260- double vr[3 ];
261- vtkMath::Cross (dop, vup, vr);
262- double rot[16 ] = { vr[0 ], vup[0 ], -dop[0 ], 0.0 , vr[1 ], vup[1 ], -dop[1 ], 0.0 , vr[2 ], vup[2 ],
263- -dop[2 ], 0.0 , 0.0 , 0.0 , 0.0 , 1.0 };
264-
265- this ->PoseTransform ->Concatenate (rot);
266-
267- this ->LeftEyeTCDCMatrix ->DeepCopy (this ->PoseTransform ->GetMatrix ());
268- this ->LeftEyeTCDCMatrix ->Transpose ();
269-
270- vtkMatrix4x4::Multiply4x4 (this ->LeftEyeTCDCMatrix , this ->WCDCMatrix , this ->LeftEyeTCDCMatrix );
271- }
272- else
273- {
274- vtkMatrix4x4::Multiply4x4 (this ->WCVCMatrix , this ->RightEyeProjection , this ->WCDCMatrix );
275-
276- this ->RightEyeTCDCMatrix ->DeepCopy (this ->PoseTransform ->GetMatrix ());
277- this ->RightEyeTCDCMatrix ->Transpose ();
278-
279- vtkMatrix4x4::Multiply4x4 (
280- this ->RightEyeTCDCMatrix , this ->WCDCMatrix , this ->RightEyeTCDCMatrix );
281- }
282-
283- this ->KeyMatrixTime .Modified ();
284- this ->LastRenderer = ren;
285- }
286-
287- wcdc = this ->WCDCMatrix ;
288- wcvc = this ->WCVCMatrix ;
289- normMat = this ->NormalMatrix ;
290-
291- if (this ->LeftEye )
292- {
293- vcdc = this ->LeftEyeProjection ;
294- }
295- else
296- {
297- vcdc = this ->RightEyeProjection ;
298- }
299- }
300-
301- // ------------------------------------------------------------------------------
302- void vtkOpenVRCamera::GetTrackingToDCMatrix (vtkMatrix4x4*& tcdc)
303- {
304- if (this ->LeftEye )
305- {
306- tcdc = this ->LeftEyeTCDCMatrix ;
307- }
308- else
309- {
310- tcdc = this ->RightEyeTCDCMatrix ;
311- }
312- }
313-
314- // ------------------------------------------------------------------------------
315- void vtkOpenVRCamera::PrintSelf (ostream& os, vtkIndent indent)
316- {
317- this ->Superclass ::PrintSelf (os, indent);
318-
319- os << indent << " LeftEyePose : (" << this ->LeftEyePose [0 ] << " , " << this ->LeftEyePose [1 ] << " , "
320- << this ->LeftEyePose [2 ] << " )\n " ;
321- os << indent << " RightEyePose : (" << this ->RightEyePose [0 ] << " , " << this ->RightEyePose [1 ]
322- << " , " << this ->RightEyePose [2 ] << " )\n " ;
323-
324- this ->LeftEyeTCDCMatrix ->PrintSelf (os, indent);
325- this ->RightEyeTCDCMatrix ->PrintSelf (os, indent);
326-
327- if (this ->LeftEyeProjection != nullptr )
328- {
329- this ->LeftEyeProjection ->PrintSelf (os, indent);
330- }
331-
332- if (this ->RightEyeProjection != nullptr )
333- {
334- this ->RightEyeProjection ->PrintSelf (os, indent);
335- }
336-
337- this ->PoseTransform ->PrintSelf (os, indent);
338- }
0 commit comments