Home | Linux | Adventures in Ray Tracing |     Share This Page

All content Copyright © 2005, P. Lutus. All rights reserved.

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`;
}
    

 

Home | Linux | Adventures in Ray Tracing |     Share This Page