#!/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 = ; 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`; }