[vtkusers] Shearing a vtkCamera (for head tracking use)

a.meijster at rc.rug.nl a.meijster at rc.rug.nl
Thu Mar 3 18:24:29 EST 2005



Hi all,

I'm trying to use VTK for stereo rendering on 
a stero projection system using head tracking. 
At each moment of time the tracker can yield me 
the 3D coordinates of the viewer's eyes and
the orientation (view direction). Now, let's assume
the screen is 2.5x2.5 meters, and the origin of the
3D world is chosen such that the center of the
projection screen is at (0,0,-1.25), i.e.
the screen is at distance 1.25 from the origin.

The field of view (viewangle) is 90 degrees.


Now, I wrote the follwing small code snippet to
simulate a user that views a cube of size 50x50x50 cm.,
which has its front face in the projection screen,
and for the rest lies behind the screen. 

Now, if a user stands in front of the screen, moving
along the line z=0, and y=0 (only x varies), he/she
should see that the front face of the cube stays 
at the same place, while the faces behind the screen 
change (of course). 

Now, my problem. How do you program this? I believe
I should use a sheared camera, since the projection 
screen (obviously) stays at the same place when
a user moves. However, I don't understand the text 
given in the doxygen manual page of vtkCamera at
all. There are methods setViewShear and
SetObliqueAngles. I believe I need only
one of these two (is that right?). However,
both descriptions are completely incomprehensible to me.
I wrote a small program that renders with a camera 
at (0,0,0) looking perpendicular to the screen, and sleep
for a second. Than it moves the camera to (0.5,0,0) (half 
a meter further) and it (should) render a new image. 
What I expect to see is that the front face does not get
distorted and stays rectangular (and in the projection
plane). However, it doesn't.

Can anyone please txplain me how to do this, or 
even better, send me the corrected code?

All help is very much appreciated.

Regards,

  Arnold Meijster


#include <iostream>

#include "vtkCubeSource.h"
#include "vtkSphereSource.h"
#include "vtkPolyDataMapper.h"
#include "vtkRenderWindow.h"
#include "vtkCamera.h"
#include "vtkActor.h"
#include "vtkRenderer.h"
#include "vtkProperty.h"

using namespace std;

void AddSphere (double cx, double cy, double cz,
		double radius,
		double r, double g, double b, 
		int wireframe, vtkRenderer *ren) {
  vtkSphereSource *sphere = vtkSphereSource::New();
  sphere->SetCenter(cx, cy, cz);
  sphere->SetRadius(radius);

  vtkPolyDataMapper *sphereMapper = vtkPolyDataMapper::New();
  sphereMapper->SetInput( sphere->GetOutput() );
  vtkActor *sphereActor = vtkActor::New();
  sphereActor->SetMapper( sphereMapper );
  sphereActor->GetProperty()->SetColor(r,g,b);
  if (wireframe) {
    sphereActor->GetProperty()->SetRepresentationToWireframe();
  }
  ren->AddActor(sphereActor );
}

int main(int argc, char *argv[]) {
  float headpos[3], wandpos[3];
  float headorn[3], wandorn[3];

  vtkRenderer *ren1= vtkRenderer::New();
  ren1->SetBackground( 0.5, 0.5, 0.5 );

  vtkRenderWindow *renWin = vtkRenderWindow::New();
 renWin->AddRenderer( ren1 );

#if 1
  renWin->StereoCapableWindowOn();
  renWin->SetStereoTypeToCrystalEyes();
  renWin->StereoRenderOn();
#endif
  
  renWin->SetSize(500, 500);

  // Add a cube to the scene. Its front
  // face lies in the screen.
  vtkCubeSource *cube = vtkCubeSource::New();
  vtkCamera *camera;
  cube->SetCenter(0,0,-1.5);
  cube->SetXLength(0.5);
  cube->SetYLength(0.5);
  cube->SetZLength(0.5);
  vtkPolyDataMapper *cubeMapper = vtkPolyDataMapper::New();
  cubeMapper->SetInput( cube->GetOutput() );
  vtkActor *cubeActor = vtkActor::New();
  cubeActor->SetMapper( cubeMapper );
  cubeActor->GetProperty()->SetRepresentationToWireframe();
  ren1->AddActor( cubeActor );


  AddSphere (0, 0, -1.25, 0.05,
	     0.0, 1.0, 0.0,   /* green */
	     0, ren1);
  
  // Add a small white sphere on top of cube.
  // This sphere is used to see if the camera is not upside down :-)
  AddSphere (0, 0.25, -1.25, 0.01,
	     1.0, 1.0, 1.0,   /* white */
	     0, ren1);

  // Add spheres in each corner 
  AddSphere (-1.25, -1.25, -1.25, 0.03,      /* left,bottom  */
	     1.0, 1.0, 0.0,   /* yellow */
	     0, ren1);
  AddSphere (-1.25, +1.25, -1.25, 0.03,      /* left,top     */
	     1.0, 1.0, 0.0,   /* yellow */
	     0, ren1);
  AddSphere (+1.25, -1.25, -1.25, 0.03,      /* right,bottom */
	     1.0, 1.0, 0.0,   /* yellow */
	     0, ren1);
  AddSphere (+1.25, +1.25, -1.25, 0.03,      /* right,top    */
	     1.0, 1.0, 0.0,   /* yellow */
	     0, ren1);
  
  
  int even=0;
  double dxdz, dydz, c;
  camera = ren1->GetActiveCamera();
  while(1) {
    camera->SetViewAngle(90);
    camera->SetClippingRange(0.01, 1000.0);
    camera->SetViewUp  (0, 1, 0);
    if (even) {
      camera->SetPosition(0, 0, 0);
      camera->SetFocalPoint (0, 0, -1.25);
      camera->SetViewShear(0,0,1);
    } else {
      camera->SetPosition(0.5, 0, 0);
      camera->SetFocalPoint (0.5, 0, -1.25);
      // WHAT SHOULD BE THE CORRECT VALUES FOR SHEARING?
      // We don't have shear in vertical direction, 
      // so I expect dydz=0. I also expect that
      // dxdz=1.25/0.5=0.4, but I'm not sure about this. 
      // center is completely unclear to me. I tried center
      // center=1, and center=0 and some random values in between.
      // Nothing seems right.  
      camera->SetViewShear(0.4,0,0);
    }
    even = 1-even;
    camera->GetViewShear(dxdz, dydz, c);
    printf ("fd=%f: dxdz=%f, dydz=%f, center=%f\n", 
	    camera->GetDistance(),
	    dxdz, dydz, c);
    // render the image
    renWin->Render();
    // wait a second
    sleep(1);
  }
  return 0;
}


========================================================
Dr. Arnold Meijster
Center for High Performance Computing & Visualization,
Nettelbosje 1,
9747 AJ Groningen, Netherlands

e-mail: a.meijster at rc.rug.nl
tel:    +31 50 363 9246
mobile: +31  6 184 89 380



More information about the vtkusers mailing list