Advertisement
grecomoran

Parallelized POV-Ray

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