Skip to content
/ VTK Public

Commit 09a478a

Browse files
committed
Cleanup VR camera code and subclasses
Consolidate OpenXR and OpenVR camera code into a new superclass called vtkVRHMDCamera. Rename the members to be much more explicit about what they represent and what coordinate systems they are in. Implement UpdateHMDMatrixPose for OpenXR Make the code between OpenXR and OpenVR more similar.
1 parent a703526 commit 09a478a

19 files changed

+577
-562
lines changed

Rendering/OpenVR/vtkOpenVRCamera.cxx

Lines changed: 76 additions & 223 deletions
Original file line numberDiff line numberDiff line change
@@ -27,58 +27,86 @@
2727

2828
vtkStandardNewMacro(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

Comments
 (0)