Here is a listing of the Anaglyph generator Perl script:
#!/usr/bin/perl -W
# 10/29/2005
# Copyright (c) P. lutus. All Rights reserved. Released under the GPL license
# this script does a better job of
# editing .pov files to create
# anaglyphic views.
# this script solves a longstanding problem of mine
# that view angles had to be nearly horizontal
# to produce an undistorted anaglyph
# now one can look straight down and still
# see a correctly rendered view
# this script assumes the presence of
# Pov-ray and ImageMagick on your system
# user settings:
# delete temporaries
$deltemps = 0;
# delta_eye, half the distance in inches
# between typical observer's eyes
$delta_eye = 1.5;
# povray's way of describing image size and quality
# (choose one)
$imageSpec = "+w320 +h240 +A";
# $imageSpec="+w500 +h375 +A";
# $imageSpec="+w640 +h480 +A";
# $imageSpec="+w1024 +h768 +A";
# $imageSpec="+w1280 +h1024 +A";
# subdirectories to work in
$animDir = "anaglyph_workarea";
$archive = "image_archive";
$pi = 3.14159265359;
sub readfile {
local $/;
open( DATA, $_[0] );
local $data = <DATA>;
close DATA;
return $data;
}
sub writefile {
local $/;
open( DATA, ">$_[0]" );
print DATA $_[1];
close DATA;
}
sub toDeg {
return $_[0] * 180.0 / $pi;
}
sub toRad {
return $_[0] * $pi / 180.0;
}
sub toPolar {
local ( $x, $y ) = @_;
return ( sqrt( $x * $x + $y * $y ), toDeg( atan2( $y, $x ) ) );
}
sub toRect {
local ( $m, $a ) = @_;
return ( $m * cos( toRad($a) ), $m * sin( toRad($a) ) );
}
sub compute_camera_positions {
local $source = $_[0];
local ( $x, $y, $z ) =
( $source =~ /.*?camera.*?location <(.*?),\s+(.*?),\s+(.*?)>.*/s );
# create a pair of camera x,z positions:
# 1. create polar equivalent for cam h pos
local ( $chm, $cha ) = toPolar( $x, $z );
# 2. build left and right eye positions
local ( $dxr, $dzr ) = toRect( $delta_eye, $cha + 90 );
local ( $dxl, $dzl ) = toRect( $delta_eye, $cha - 90 );
# 3. create rectangular equivalants
local $xl = $x + $dxl;
local $zl = $z + $dzl;
local $xr = $x + $dxr;
local $zr = $z + $dzr;
# create rotated "sky" vector":
# 1. get horizontal magnitude
local $hm = sqrt( $x * $x + $z * $z );
# 2. create polar equivalent for cam v pos
local ( $cvm, $cva ) = toPolar( $hm, $y );
# 4. create unit rect values for rotated sky vector
local ( $clah, $clav ) = toRect( 1, $cva + 90 );
# 5. produce three rectangular components
local $clax = $x * $clah / $hm;
local $claz = $z * $clah / $hm;
local $clay = $clav;
return ( $xl, $zl, $xr, $zr, $clax, $clay, $claz );
}
sub create3DScript {
local ( $data, $dir, $pref, $name, $x, $z, $lax, $lay, $laz ) = @_;
# limit the number of decimal places for all the values
$x = sprintf( "%.3lf", $x );
$z = sprintf( "%.3lf", $z );
$lax = sprintf( "%.3lf", $lax );
$lay = sprintf( "%.3lf", $lay );
$laz = sprintf( "%.3lf", $laz );
# move the camera position to the desired 3D view angle
$data =~
s/(.*?camera.*?location <)(.*?)(,\s+)(.*?)(,\s+)(.*?)(>.*)/$1$x$3$4$5$z$7/s;
# adjust 'sky' angle for correct rendering
$data =~
s/(.*?camera.*?sky <)(.*?)(,\s+)(.*?)(,\s+)(.*?)(>.*)/$1$lax$3$lay$5$laz$7/s;
local $newname = $pref . "_" . $name;
local $path = $dir . "/" . $newname;
# write the edited Pov-ray script
writefile( "$path.pov", $data );
return $newname;
}
sub create_anaglyph {
local ( $left, $right, $suff, $name ) = @_;
# render the two scripts using Pov-ray
system("povray $imageSpec $left.pov");
system("povray $imageSpec $right.pov");
$outname = $name . "_" . "$suff.png";
# temporary filenames
$ltemp = "left_mono.png";
$rtemp = "right_mono.png";
# create two monochrome images
system("convert -colorspace gray $left.png $ltemp");
system("convert -colorspace gray $right.png $rtemp");
# combine the two monochromes into an anaglyphic image
system("composite -stereo $rtemp $ltemp $outname");
# delete temporaries
if ($deltemps) {
foreach $file (
"$left.pov", "$right.pov", "$left.png", "$right.png",
"$ltemp", "$rtemp"
)
{
unlink($file) || print "Error: can't delete $file\n";
}
}
return $outname;
}
# main actions begin here
if ( $#ARGV < 0 ) {
print "usage: Pov-ray script names\n";
exit 0;
}
chomp( $baseDir = `pwd` );
foreach $fn (@ARGV) {
$basename = $fn;
$basename =~ s/\.pov//;
if ( !-e $animDir ) {
mkdir($animDir);
}
# get the original POV file as a string
$source = readfile("$basename.pov");
# generate 3D viewing positions and new "sky" vector
( $xl, $zl, $xr, $zr, $clax, $clay, $claz ) =
compute_camera_positions($source);
# create two new POV files, for left and right views
$lname = create3DScript(
$source, $animDir, "left3D", $basename, $xl,
$zl, $clax, $clay, $claz
);
$rname = create3DScript(
$source, $animDir, "right3D", $basename, $xr,
$zr, $clax, $clay, $claz
);
chdir($animDir);
# create and combine the two views into an anaglyphic image
$outname = create_anaglyph( $lname, $rname, "anaglyph", $basename );
# return to original directory
chdir $baseDir;
# create the archive directory if it doesn't exist
if ( !-e $archive ) {
mkdir($archive);
}
# copy result to image archive
`mv $animDir/$outname $archive`;
}