File: vtkVRCamera.cxx

package info (click to toggle)
paraview 5.11.0%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 497,236 kB
  • sloc: cpp: 3,171,290; ansic: 1,315,072; python: 134,290; xml: 103,324; sql: 65,887; sh: 5,286; javascript: 4,901; yacc: 4,383; java: 3,977; perl: 2,363; lex: 1,909; f90: 1,255; objc: 143; makefile: 119; tcl: 59; pascal: 50; fortran: 29
file content (178 lines) | stat: -rw-r--r-- 6,700 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
/*=========================================================================

  Program:   Visualization Toolkit

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
#include "vtkVRCamera.h"
#include "vtkMatrix4x4.h"
#include "vtkVRInteractorStyle.h"
#include "vtkVRRenderWindow.h"
#include "vtkVRRenderWindowInteractor.h"
#include "vtkVectorOperators.h"

VTK_ABI_NAMESPACE_BEGIN
vtkVRCamera::vtkVRCamera() = default;
vtkVRCamera::~vtkVRCamera() = default;

namespace
{

// A simple herlper function to return an unit vector closest to the input
// vector that is orthogonal to the normal vector
vtkVector3d sanitizeVector(vtkVector3d& in, vtkVector3d& normal)
{
  vtkVector3d result;

  // handle coincident vectors
  if (fabs(in.Dot(normal)) > 0.999) // some epsilon
  {
    if (fabs(normal[0]) < 0.1)
    {
      result.Set(1.0, 0.0, 0.0);
    }
    else
    {
      result.Set(0.0, 1.0, 0.0);
    }
  }
  else
  {
    result = in - (in.Dot(normal)) * normal;
    result.Normalize();
  }
  return result;
}
} // end anonymous namespace

// fairly simply we just save the current physical and view properties
void vtkVRCamera::SetPoseFromCamera(vtkVRCamera::Pose* pose, vtkVRRenderWindow* win)
{
  win->GetPhysicalTranslation(pose->Translation);
  win->GetPhysicalViewUp(pose->PhysicalViewUp);
  pose->Distance = win->GetPhysicalScale();
  vtkVRInteractorStyle* is =
    static_cast<vtkVRInteractorStyle*>(win->GetInteractor()->GetInteractorStyle());
  pose->MotionFactor = is->GetDollyPhysicalSpeed();

  this->GetPosition(pose->Position);

  win->GetPhysicalViewDirection(pose->PhysicalViewDirection);
  this->GetDirectionOfProjection(pose->ViewDirection);
}

// much more complicated as we cannot simply set the camera based on
// the pose as the camera is head tracked (the HMD) and whatever we set will
// be instantly overridden with the latest HMD matrix. So instead we adjust
// the physical space properties to best reproduce the pose based on the HMDs
// current pose.
void vtkVRCamera::ApplyPoseToCamera(vtkVRCamera::Pose* pose, vtkVRRenderWindow* win)
{
  // newPhysicalViewUp is always the same as what was saved
  vtkVector3d newPhysicalViewUp(pose->PhysicalViewUp);
  win->SetPhysicalViewUp(newPhysicalViewUp.GetData());

  //==========================================================
  // (1) Get the saved values (some sanitizing)
  vtkVector3d savedTranslation(pose->Translation);
  vtkVector3d savedPosition(pose->Position);
  double savedDistance = pose->Distance;

  // sanitize the savedViewDirection, must be orthogonal to newPhysicalViewUp
  vtkVector3d savedViewDirection(pose->ViewDirection);
  savedViewDirection = sanitizeVector(savedViewDirection, newPhysicalViewUp);

  //==========================================================
  // (2) Get the current values (some sanitizing)
  // c = current values
  vtkVector3d cPosition;
  this->GetPosition(cPosition.GetData());
  vtkVector3d cTranslation;
  win->GetPhysicalTranslation(cTranslation.GetData());
  double cDistance = win->GetPhysicalScale();

  // sanitize cViewDirection and cPhysicalViewDirection, must be orthogonal
  // to newPhysicalViewUp
  vtkVector3d cViewDirection;
  this->GetDirectionOfProjection(cViewDirection.GetData());
  cViewDirection = sanitizeVector(cViewDirection, newPhysicalViewUp);
  vtkVector3d cPhysicalViewDirection;
  win->GetPhysicalViewDirection(cPhysicalViewDirection.GetData());
  cPhysicalViewDirection = sanitizeVector(cPhysicalViewDirection, newPhysicalViewUp);
  vtkVector3d cPhysicalViewRight = cPhysicalViewDirection.Cross(newPhysicalViewUp);

  //==========================================================
  // (3) start doing all the calculations

  // find the newPhysicalViewDirection
  vtkVector3d newPhysicalViewDirection;
  double theta = acos(savedViewDirection.Dot(cViewDirection));
  if (newPhysicalViewUp.Dot(cViewDirection.Cross(savedViewDirection)) < 0.0)
  {
    theta = -theta;
  }
  // rotate cPhysicalViewDirection by theta
  newPhysicalViewDirection = cPhysicalViewDirection * cos(theta) - cPhysicalViewRight * sin(theta);
  win->SetPhysicalViewDirection(newPhysicalViewDirection.GetData());
  vtkVector3d newPhysicalViewRight = newPhysicalViewDirection.Cross(newPhysicalViewUp);

  // adjust translation so that we are in the same spot
  // as when the camera was saved
  vtkVector3d newTranslation;
  vtkVector3d cppwc;
  cppwc = cPosition + cTranslation;
  double x = cppwc.Dot(cPhysicalViewDirection) / cDistance;
  double y = cppwc.Dot(cPhysicalViewRight) / cDistance;

  newTranslation = savedTranslation * newPhysicalViewUp +
    newPhysicalViewDirection * (x * savedDistance - savedPosition.Dot(newPhysicalViewDirection)) +
    newPhysicalViewRight * (y * savedDistance - savedPosition.Dot(newPhysicalViewRight));

  win->SetPhysicalTranslation(newTranslation.GetData());
  this->SetPosition(cPosition.GetData());

  // this really only sets the distance as the render loop
  // sets focal point and position every frame
  vtkVector3d newFocalPoint;
  newFocalPoint = cPosition + newPhysicalViewDirection * savedDistance;
  this->SetFocalPoint(newFocalPoint.GetData());
  win->SetPhysicalScale(savedDistance);

  win->SetPhysicalViewUp(newPhysicalViewUp.GetData());
  vtkInteractorStyle3D* is =
    static_cast<vtkInteractorStyle3D*>(win->GetInteractor()->GetInteractorStyle());
  is->SetDollyPhysicalSpeed(pose->MotionFactor);
}

// extract the camera ivars from the provided device/view matrix
void vtkVRCamera::SetCameraFromWorldToDeviceMatrix(vtkMatrix4x4* mat, double distance)
{
  // the input matrix should be a pose/view matrix without projection
  this->TempMatrix4x4->DeepCopy(mat);
  this->TempMatrix4x4->Invert();
  this->SetCameraFromDeviceToWorldMatrix(this->TempMatrix4x4, distance);
}

void vtkVRCamera::SetCameraFromDeviceToWorldMatrix(vtkMatrix4x4* mat, double distance)
{
  double* ele = mat->GetData();

  // position is the last column of the matrix
  this->SetPosition(ele[3], ele[7], ele[11]);

  // view up is the second column of the matrix
  this->SetViewUp(ele[1], ele[5], ele[9]);

  // direction of projection is the third column of the matrix
  // but we set it by setting the focal point
  this->SetFocalPoint(
    ele[3] - distance * ele[2], ele[7] - distance * ele[6], ele[11] - distance * ele[10]);
}
VTK_ABI_NAMESPACE_END