If you want to play with the red/cyan glasses, use red and cyan for your colors, not red and blue. Cyan is 180 degrees opposite of red. Blue is only 120 degrees opposite and gives very poor results. I was playing with this a while back, and I've currently misplaced my glasses, but this seems to be the code I was using...
// Shows the right-handed axis system, point sizes and smooth points,
// line widths and stippling patterns.
// Right hand fingers: thumb=x, index=y, middle=z.
Names Default To Here( 1 );
dl = Scene Display List( 0 );
//dl << color( 1, 0, 0 );
//dl << LineStipple( 1, 255 );
//dl << LineWidth( 3 );
dl << Begin( LINES );
dl << Vertex( 0, 0, 0 );
dl << Vertex( 1, 0, 0 );
dl << End();
dl << enable( POINT_SMOOTH );
For( i = 1, i < 10, i++,
dl << PointSize( i );
dl << BEGIN( POINTS );
dl << Vertex( -i / 10, 0, 0 );
dl << END;
);
dl << disable( POINT_SMOOTH );
dl << Translate( 1, 0, 0 );
dl << Text( center, middle, .3, "+ X" );
dl << Translate( -1, 0, 0 );
//dl << color( 0, 1, 0 );
//dl << LineStipple( 2, 1 + 4 + 16 + 64 + 256 + 1024 + 4096 + 16384 );
//dl << LineWidth( 6 );
dl << Begin( LINES );
dl << Vertex( 0, 0, 0 );
dl << Vertex( 0, 1, 0 );
dl << End();
For( i = 1, i < 10, i++,
dl << PointSize( i );
dl << BEGIN( POINTS );
dl << Vertex( 0, -i / 10, 0 );
dl << END;
);
dl << Translate( 0, 1, 0 );
dl << Text( center, middle, .3, "+ Y", billboard ); // new feature: billboard text always faces viewer
dl << Translate( 0, -1, 0 );
//dl << color( 0, 0, 1 );
//dl << LineStipple( 3, 1 + 4 + 16 + 64 + 256 + 1024 );
//dl << LineWidth( 9 );
dl << Begin( LINES );
dl << Vertex( 0, 0, 0 );
dl << Vertex( 0, 0, 1 );
dl << End();
For( i = 1, i < 10, i++,
dl << PointSize( i );
dl << BEGIN( POINTS );
dl << Vertex( 0, 0, -i / 10 );
dl << END;
);
dl << Translate( 0, 0, 1 );
dl << Text( center, middle, .3, "+ Z" );
dl << Translate( 0, 0, -1 );
//dl << color( .5, .5, .5 );
dl << Text( center, middle, .3, "0,0" );
ncp = Function( {a, b, c},
{Default Local}, // normalized cross product: 3D vectors ba and vector bc, 3D result
// calculate the normal; this is the vector cross product of the two lines leaving b to a or c
q = a - b;
p = c - b;
nx = p[2] * q[3] - p[3] * q[2];
ny = p[3] * q[1] - p[1] * q[3];
nz = p[1] * q[2] - p[2] * q[1];
len = Sqrt( nx * nx + ny * ny + nz * nz );
nx / len || ny / len || nz / len; // return 3D unit column vector w.r.t. b
);
// modified from "Offaxis frustums - OpenGL" http://paulbourke.net/stereographics/stereorender/ (Thanks!)
// "Camera is defined by its position, view direction, up vector, eye separation, distance to zero
// parallax (see fo below) and the near and far cutting planes. Position, eye separation, zero
// parallax distance, and cutting planes are most conveniently specified in model coordinates,
// direction and up vector are orthonormal vectors. With regard to parameters for adjusting
// stereoscopic viewing I would argue that the distance to zero parallax is the most natural, not
// only does it relate directly to the scale of the model and the relative position of the camera,
// it also has a direct bearing on the stereoscopic result ... namely that objects at that
// distance will appear to be at the depth of the screen. In order not to burden the operators
// with multiple stereo controls one can usually just internally set the eye separation to 1/30 of
// the zero parallax distance (camera.eyesep = camera.fo / 30), this will give acceptable stereoscopic
// viewing in almost all situations and is independent of model scale." -- quoted from link above
defCamera = New Namespace(
"defCamera",
{
aperture = 45,
pos = [0, 0, 4],
dir = [0, 0, -1],
up = [0, 1, 0],
fo = 4,
near = 1,
far = 20
}
);
stereoRender = Function(
{model, windowWidth = 1920, windowHeight = 1080, sideBySide = "left,right", camera = defCamera},
{Default Local},
DegToRad = Pi() / 180;
aspectratio = windowwidth / windowheight;
eyeSeparation = camera:fo / 30;
widthdiv2 = camera:near * Tan( DegToRad * camera:aperture / 2 );
cameraright = ncp( camera:pos+camera:dir, camera:pos, camera:pos+camera:up ); // returns Cross Product column vector, normalized
cameraright *= (eyeSeparation / 2.0);
sceneList = Scene Display List();
If( Contains( sideBySide, "right" ),
sceneList << MatrixMode( "PROJECTION" );
sceneList << LoadIdentity();
If( Contains( sideBySide, "left" ), // For frame sequential, earlier use glDrawBuffer(GL_BACK_RIGHT); (not in JSL)
sceneList << color( 1, 0, 0 ); // ...or... the left eye will be centered too, draw right in red
);
top = widthdiv2;
bottom = -widthdiv2;
left = -aspectratio * widthdiv2 - 0.5 * eyeSeparation * camera:near / camera:fo;
right = aspectratio * widthdiv2 - 0.5 * eyeSeparation * camera:near / camera:fo;
sceneList << Frustum( left, right, bottom, top, camera:near, camera:far );
sceneList << MatrixMode( MODELVIEW );
sceneList << LoadIdentity();
sceneList << LookAt(
camera:pos[1] + cameraright[1],
camera:pos[2] + cameraright[2],
camera:pos[3] + cameraright[3],
camera:pos[1] + cameraright[1] + camera:dir[1],
camera:pos[2] + cameraright[2] + camera:dir[2],
camera:pos[3] + cameraright[3] + camera:dir[3],
camera:up[1],
camera:up[2],
camera:up[3]
);
sceneList << calllist( model );
);
If( Contains( sideBySide, "left" ),
sceneList << MatrixMode( PROJECTION );
sceneList << LoadIdentity();
If( Contains( sideBySide, "right" ), // For frame sequential, earlier use glDrawBuffer(GL_BACK_LEFT); (not in JSL)
sceneList << color( 0, 255/255, 250/255 ); // ...or... the right eye will be centered too, draw left in blue
);
top = widthdiv2;
bottom = -widthdiv2;
left = -aspectratio * widthdiv2 + 0.5 * eyeSeparation * camera:near / camera:fo;
right = aspectratio * widthdiv2 + 0.5 * eyeSeparation * camera:near / camera:fo;
sceneList << Frustum( left, right, bottom, top, camera:near, camera:far );
sceneList << MatrixMode( MODELVIEW );
sceneList << LoadIdentity();
sceneList << LookAt(
camera:pos[1] - cameraright[1],
camera:pos[2] - cameraright[2],
camera:pos[3] - cameraright[3],
camera:pos[1] - cameraright[1] + camera:dir[1],
camera:pos[2] - cameraright[2] + camera:dir[2],
camera:pos[3] - cameraright[3] + camera:dir[3],
camera:up[1],
camera:up[2],
camera:up[3]
);
sceneList << calllist( model );
);
Return( sceneList );
);
background = scenedisplaylist();
for(y=-9, y<=9, y+=1,
background<<PUSHMATRIX></PUSHMATRIX>
cyan looks black through the red lens, white through the cyan lens. red looks black...cyan looks black through the red lens, white through the cyan lens. red looks black...
the background color was chosen to minimize ghosting...for the glasses I had.