To calibrate a Desk (Immersa- or Porta-) for the EVL Cave libraries, we need to: If we assume that the screen's horizontal direction (e.g. its bottom edge) is actually parallel to the floor, then it's natural to define Cave axis directions as follows.

right
(Cave +X) (horizontally along the screen),
up
(Cave +Y) (perpendicular to the floor),
back
(Cave +Z) (horizontally backward away from the screen).

The process of establishing a coordinate system and writing relevant portions of a CAVE configuration file is automated by programs like deskconf. But, in case you'd like to go through the process manually, or understand what the autocalibration programs do, here's how you could do it.

  1. Measure reference points in tracker coordinates

    To measure sensor coordinates, edit the cave config to impose trivial sensor->cave transformations, and to report the wand position as just where its sensor was. To do this by hand, it's handiest to write a file containing these statements, then invoke e.g.

     cavevars -caveconfig identity.conf

    where identity.conf contains:

    
    TransmitterRotationMatrix 1 0 0  0 1 0  0 0 1
    TransmitterOffset	0 0 0
    CaveRotationMatrix	1 0 0  0 1 0  0 0 1
    CaveOffset		0 0 0
    WandOffset		0 0 0
    CaveScale		1
    

    Now use e.g. cavevars' "wand" display to measure some points. We need three 3-D positions to determine the coordinate frame. Since we've set the WandOffset to zero, hold the wand's white sensor knob (rather than its head) to the given spot to take a reading. Measure, say:

    These points should all be within the tracker's range. (If the screen's top edge is out of reach, try measuring the center of the screen.) Given the identity tracker->cave transformations established by identity.conf, we know where the tracker thinks these are.

  2. Build orthogonal coordinate frame

    Now establish the screen's X direction as the vector
    ScreenX = normalize(B - A), i.e. B - A normalized to be a unit vector.
    The screen's Y direction is approximately
    scrY = normalize(C - (B + A)/2).
    If all were perfect, the scrY vector would be perpendicular to the ScreenX vector, and we could use it directly in the coordinate basis. It probably isn't, so subtract the component parallel to the X vector:
    ScreenY = normalize( scrY - (scrY dot screenX)*screenX ).

    Finally,
    ScreenZ = ScreenX cross ScreenY.

    From these vectors we can build a coordinate system, but it's probably not the one wanted for Cave coordinates. Those normally have Y vertical, and the desk's screen is probably tilted.

    So, measure the screen's tilt from the vertical -- 0 degrees if it is vertical, 90 if horizontal facing up -- and construct Cave-coordinate direction vectors:

  3. Calibrate tracker scale

    Note that we'd ignored the scale of the cave. Conventional Cave units are feet, but the tracker doesn't necessarily return measurements in feet (at least ours didn't -- it was off by about a factor of two). Scale isn't critical if you just care that things have the right orientation and that the tracking matches the screen. But, if you'd like to get it (more nearly) correct, you could compensate for the tracker's scaling as follows.

    The (non-normalized) vector B - A gives the tracker's idea of the width of the screen. Let Wvirtual be magnitude of that vector. Measure the real-world distance between those same two points, and let Wreal be the result in feet (or whatever you'd like Cave units to be measured in). Multiply the vectors CaveX, CaveY, and CaveZ by the factor Wreal / Wvirtual.

  4. Calibrate adopted origin

    Next, choose an origin. If you're going through this process by hand, it's probably best to make a copy of identity.conf, say test.conf, and insert those Cave vectors into the TransmitterRotationMatrix. The vectors become the columns of the matrix; thus if the components of e.g. CaveX are X0 X1 X2, the TransmitterRotationMatrix line will have the form:
    TransmitterRotationMatrix X0 Y0 Z0   X1 Y1 Z1   X2 Y2 Z2

    Re-invoke cavevars, specifying the new test.conf file. Now you can simply hold the wand's sensor at the desired origin point -- conventionally I think it'd lie on the floor, a foot or two directly in front of the center of the screen -- and note the reading. If that point is beyond the tracker's range, just hold the wand in some other convenient spot, say 3 feet above the desired origin, and subtract 3 from the reported Y value.

    Edit test.conf, changing the TransmitterOffset values to be the negatives of the values reported by cavevars at the chosen origin.

  5. Measure screen in Cave coordinates

    Determine the coordinates of the screen's corners in the new coordinate system. Again, if you're doing this by hand, it's simplest to update the test.conf file to reflect the chosen origin and restart cavevars -caveconfig test.conf.

    Measure three points on the screen:

    (If the tracker's range doesn't extend that far, you may have to measure other points -- say the screen's lower left, lower right, and center -- and extrapolate to find coordinates of the rest.) Using the results, add two lines to test.conf:

      ProjectionCorners   screen7   llX llY llZ   ulX ulY ulZ   lrX lrY lrZ
      ProjectionData   screen7 both wall   llX llY llZ   ulX ulY ulZ   lrX lrY lrZ

    The latter is needed for CAVE library version 2.6, the former for earlier versions. (I'm not sure whether screen7 is always the right choice, though it is for the two desks here at NCSA; it should match whatever is mentioned in the Walls statement in the existing /usr/local/CAVE/etc/cave.config file.)

  6. Test and install

    If desired, remove the WandOffset from test.conf and re-invoke cavevars -caveconfig test.conf. If the calibration is correct, the wand's real-space position should match its projected position on the screen as seen by someone wearing the tracked glasses.

    Assuming you like the result, copy the TransmitterRotationMatrix, TransmitterOffset, ProjectionCorners and ProjectionData statements from test.conf to the systemwide cave configuration file. Be sure there aren't any CaveRotation, CaveRotationMatrix, CaveOffset, or CaveScale statements in it.

That's it. Note that deskconf doesn't work exactly as described above. Rather than letting you place the wand at the adopted origin, it prompts for horizontal and vertical distances from the screen's bottom center. And rather than being restarted three times, it calculates how the Cave libraries will transform the given points, and derives the Cave-coordinate screen corners itself.


Stuart Levy, slevy@ncsa.uiuc.edu