grecomoran

Parallelized POV-Ray

Nov 28th, 2023 (edited)
67
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Bash 6.29 KB | None | 0 0
  1. #!/bin/sh
  2.  
  3. # Parallelized POV-Ray script
  4. # Usage: ./script FILE.POV [+FLAGS...]
  5.  
  6. #-------------------------------------------------------------------------------
  7. # PARAMS
  8. #-------------------------------------------------------------------------------
  9.  
  10. # povray exe path, space separated include directories (simple paths ONLY)
  11. # the directory of the input file is included automatically
  12. HERE="$(dirname "$(readlink -f "${0}")")"
  13. POVEXE="$HERE/povray"
  14. POVINC="$HERE/include $HERE/demo"
  15.  
  16. # ImageMagick or GraphicsMagick command (typically `magick` or `gm`)
  17. MAGICK="magick"
  18.  
  19. # default render options
  20. W=640       # output image width
  21. H=480       # output image height
  22. CHUNK=240   # chunk width & height (240)
  23. MAXPROCS=16 # maximum number of parallel processes
  24. MARGIN=4    # safety margin around each chunk (4)
  25. Q=9         # quality (9)
  26. R=3         # number of rays (3)
  27. A=0.1       # anti-alias threshold
  28. V=2         # major POV-Ray version (1 or 2)
  29.  
  30. #-------------------------------------------------------------------------------
  31. # INPUT
  32. #-------------------------------------------------------------------------------
  33.  
  34. # check for ImageMagick
  35. if ! which $MAGICK >/dev/null 2>&1; then
  36.    echo "Error: \`$MAGICK\` not found, please install ImageMagick."
  37.    exit 1
  38. fi
  39.  
  40. # parse command line args
  41. for arg in "$@"; do
  42.    case "$arg" in
  43.    +W*)    W="${arg#+W}"       ;;
  44.    +H*)    H="${arg#+H}"       ;;
  45.    +A*)    A="${arg#+A}"       ;;
  46.    +R*)    R="${arg#+R}"       ;;
  47.    +*)     echo "??? $arg"     ;;
  48.    *)      f="`realpath "$1"`" ;;
  49.    esac
  50. done
  51.  
  52. # get input file name if not provided already
  53. if [ -z "$f" ]; then
  54.    printf "Input POV file (%d x %d, Q=%d, R=%d): " $W $H $Q $R
  55.    read f
  56.    f="${f#"'"}" && f="${f%"'"}"
  57. fi
  58.  
  59. # symlink directory of input file to temp directory without spaces
  60. fdir_o="`dirname "$f"`"
  61. fdir="`mktemp -tu povincXXXXXX`"
  62. ln -s "$fdir_o" "$fdir"
  63.  
  64. # generate include flags
  65. INCDIR="+L$fdir"
  66. for i in $POVINC; do INCDIR="$INCDIR +L$i"; done
  67.  
  68. # generate input and output file names
  69. INFILE="$fdir/`basename "$f"`"
  70. OUTFILE="${INFILE%.pov}" && OUTFILE="${OUTFILE%.POV}.png"
  71.  
  72. # generate chunk information
  73. step=$(( CHUNK - 1 )) # 1 -> 119+1
  74. COLS=$(( (W + CHUNK - 1) / CHUNK )) # total columns rounded up
  75. ROWS=$(( (H + CHUNK - 1) / CHUNK )) # total rows    rounded up
  76. TOTAL=$(( COLS * ROWS ))            # total number of chunks
  77.  
  78. # create temporary working directory
  79. POVTMP=`mktemp -td povtmpXXXXXX`
  80.  
  81. # create empty scene for padding chunks
  82. BLKPOV="$POVTMP/black.pov"
  83. echo 'light_source {<0,0,0> color red 0}' > "$BLKPOV"
  84.  
  85. # create lists for started and finished render jobs
  86. J0="$POVTMP/j0"
  87. J1="$POVTMP/j1"
  88. true > $J0 && true > $J1
  89.  
  90. # start timer
  91. start_time=`date +%s`
  92.  
  93. #-------------------------------------------------------------------------------
  94. # RENDER
  95. #-------------------------------------------------------------------------------
  96.  
  97. # iterate over rows from top to bottom
  98. i=0 && ER=0
  99. while [ $i -lt $ROWS ]; do
  100.    
  101.    # start at last iteration's end + 1, stop if start row is out of bounds
  102.    SR=$(( ER + 1 ))
  103.    if [ $SR -gt $H ]; then break; fi
  104.    
  105.    # end at <step> rows after start, keep end row within image bounds
  106.    ER=$(( SR + step ))
  107.    if [ $ER -gt $H ]; then ER=$H; fi
  108.    
  109.    # iterate over columns from left to right
  110.    j=0 && EC=0
  111.    while [ $j -lt $COLS ]; do
  112.        
  113.        # same thing we did for rows
  114.        SC=$(( EC + 1 ))
  115.        if [ $SC -gt $W ]; then break; fi
  116.        
  117.        EC=$(( SC + step ))
  118.        if [ $EC -gt $W ]; then EC=$W; fi
  119.        
  120.        # add safety margin around each chunk...
  121.        SR1=$(( SR - MARGIN ))
  122.        SC1=$(( SC - MARGIN ))
  123.        ER1=$(( ER + MARGIN ))
  124.        EC1=$(( EC + MARGIN ))
  125.        
  126.        # ...but stay within bounds
  127.        if [ $SR1 -lt 1 ];  then SR1=1;     fi
  128.        if [ $SC1 -lt 1 ];  then SC1=1;     fi
  129.        if [ $EC1 -gt $W ]; then EC1=$W;    fi
  130.        if [ $ER1 -gt $H ]; then ER1=$H;    fi
  131.        
  132.        # wait until background job count is under maximum allowed
  133.        while true; do
  134.            started=`cat $J0 | wc -c`
  135.            ended=`cat $J1 | wc -c`
  136.            procs=$(( started - ended ))
  137.            echo "$procs render jobs running (maximum $MAXPROCS)"
  138.            if [ $procs -lt $MAXPROCS ]
  139.                then break      # under capacity, proceed
  140.                else sleep 1s   # over  capacity, wait
  141.            fi
  142.        done
  143.        
  144.        # use numbered file names for the chunks
  145.        TMPTGA="$POVTMP/`printf "%04d" $i``printf "%04d" $j`.tga"
  146.        
  147.        # render chunk, pad it with black, crop it, delete uncropped
  148.        # all in background { ... } &
  149.        printf "0" >> $J0
  150.        {
  151.            $POVEXE +I$INFILE +O$TMPTGA $INCDIR                 \
  152.                    +FT -P -V +A$A +W$W +H$H +Q$Q +R$R +MV$V.0  \
  153.                    +SC$SC1 +EC$EC1 +SR$SR1 +ER$ER1             ;
  154.            $POVEXE +I$BLKPOV +O$TMPTGA             \
  155.                    +FT -P -V -A +C +W$W +H$H +Q0   ;
  156.            x=$(( SC - 1 )) ;
  157.            if [ $SR -eq 1 ]; then y=0; else y=$MARGIN; fi ;
  158.            w=$(( EC - SC + 1 )) ;
  159.            h=$(( ER - SR + 1 )) ;
  160.            $MAGICK convert $TMPTGA -crop ${w}x${h}+${x}+${y} ${TMPTGA%tga}png ;
  161.            rm $TMPTGA ;
  162.            printf "1" >> $J1 ;
  163.        } &
  164.        
  165.        j=$(( j + 1 ))
  166.    done
  167.    
  168.    i=$(( i + 1 ))
  169. done
  170.  
  171. #-------------------------------------------------------------------------------
  172. # FINALIZE
  173. #-------------------------------------------------------------------------------
  174.  
  175. # wait for all render jobs to finish
  176. while [ `cat $J1 | wc -c` -lt $TOTAL ]; do
  177.    started=`cat $J0 | wc -c`
  178.    ended=`cat $J1 | wc -c`
  179.    procs=$(( started - ended ))
  180.    echo "Waiting for $procs render jobs to finish..."
  181.    sleep 1s
  182. done
  183.  
  184. # concatenate chunks into final image
  185. $MAGICK montage -mode concatenate -tile ${COLS}x${ROWS} $POVTMP/*.png $OUTFILE
  186.  
  187. # clean up temporary files
  188. rm -r $POVTMP
  189. rm $fdir
  190. echo "Finished"
  191.  
  192. # calculate time elapsed
  193. end_time="`date +%s`"
  194. seconds=$(( end_time - start_time ))
  195. hours=$(( seconds / 3600 ))
  196. seconds=$(( seconds - hours * 3600 ))
  197. minutes=$(( seconds / 60 ))
  198. seconds=$(( seconds - minutes * 60 ))
  199. echo "Time elapsed: $hours hours, $minutes minutes, $seconds seconds"
Advertisement
Add Comment
Please, Sign In to add comment