@@ -658,6 +658,71 @@ class Worker(QObject):
658
658
blender_error_with_data = pyqtSignal (str ) # 1007
659
659
enable_interface = pyqtSignal () # 1008
660
660
661
+ def __init__ (self ):
662
+ super ().__init__ ()
663
+ s = settings .get_settings ()
664
+ self .blender_exec_path = s .get ("blender_command" )
665
+
666
+ # Init regex expression used to determine blender's render progress
667
+ self .blender_frame_re = re .compile (r"Fra:([0-9,]*)" )
668
+ self .blender_saved_re = re .compile (r"Saved: '(.*\.png)" )
669
+ self .blender_version_re = re .compile (
670
+ r"^Blender ([0-9a-z\.]*)" , flags = re .MULTILINE )
671
+
672
+ self .version = None
673
+ self .process = None
674
+ self .is_running = False
675
+
676
+ self .startupinfo = None
677
+ if sys .platform == 'win32' :
678
+ self .startupinfo = subprocess .STARTUPINFO ()
679
+ self .startupinfo .dwFlags |= subprocess .STARTF_USESHOWWINDOW
680
+
681
+ def blender_version_check (self ):
682
+ # Check the version of Blender
683
+ command_get_version = [self .blender_exec_path , '-v' ]
684
+ log .debug ("Checking Blender version, command: {}" .format (
685
+ " " .join ([shlex .quote (x ) for x in command_get_version ])))
686
+
687
+ try :
688
+ if self .process :
689
+ self .process .terminate ()
690
+ self .process = subprocess .Popen (
691
+ command_get_version ,
692
+ stdout = subprocess .PIPE , stderr = subprocess .STDOUT ,
693
+ startupinfo = self .startupinfo ,
694
+ )
695
+ # Give Blender up to 10 seconds to respond
696
+ (out , err ) = self .process .communicate (timeout = 10 )
697
+ except subprocess .SubprocessError :
698
+ # Error running command. Most likely the blender executable path in
699
+ # the settings is incorrect, or is not a supported Blender version
700
+ self .blender_error_nodata .emit ()
701
+ return False
702
+ except subprocess .TimeoutExpired :
703
+ self .process .kill ()
704
+ self .blender_error_nodata .emit ()
705
+ return False
706
+ except Exception :
707
+ log .error ("Version check exception" , exc_info = 1 )
708
+ return
709
+
710
+ ver_string = out .decode ('utf-8' )
711
+ log .debug ("Blender output:\n %s" , ver_string )
712
+
713
+ ver_match = self .blender_version_re .search (ver_string )
714
+ if not ver_match :
715
+ raise Exception ("No Blender version detected in output" )
716
+ log .debug ("Matched %s in output" , str (ver_match ))
717
+
718
+ self .version = ver_match .group (1 )
719
+ log .info ("Found Blender version {}" .format (self .version ))
720
+
721
+ if self .version < info .BLENDER_MIN_VERSION :
722
+ # Wrong version of Blender.
723
+ self .blender_version_error .emit (self .version )
724
+ return (self .version >= info .BLENDER_MIN_VERSION )
725
+
661
726
@pyqtSlot ()
662
727
def Cancel (self ):
663
728
"""Cancel worker render"""
@@ -670,35 +735,20 @@ def Cancel(self):
670
735
def Render (self , blend_file_path , target_script , preview_frame = 0 ):
671
736
""" Worker's Render method which invokes the Blender rendering commands """
672
737
673
- # Init regex expression used to determine blender's render progress
674
- s = settings .get_settings ()
675
-
676
738
_ = get_app ()._tr
677
739
678
740
# get the blender executable path
679
- self .blender_exec_path = s .get ("blender_command" )
680
741
self .blend_file_path = blend_file_path
681
742
self .target_script = target_script
682
- self .preview_mode = bool (preview_frame > 0 )
683
- self .frame_detected = False
684
- self .last_frame = 0
685
- self .version = None
686
- self .command_output = ""
687
- self .process = None
688
- self .is_running = False
689
-
690
- blender_frame_re = re .compile (r"Fra:([0-9,]*)" )
691
- blender_saved_re = re .compile (r"Saved: '(.*\.png)" )
692
- blender_version_re = re .compile (r"Blender (.*?) " )
743
+ preview_mode = bool (preview_frame > 0 )
744
+ command_output = ""
693
745
694
- startupinfo = None
695
- if sys .platform == 'win32' :
696
- startupinfo = subprocess .STARTUPINFO ()
697
- startupinfo .dwFlags |= subprocess .STARTF_USESHOWWINDOW
746
+ if not self .version :
747
+ if not self .blender_version_check ():
748
+ return
698
749
699
750
try :
700
751
# Shell the blender command to create the image sequence
701
- command_get_version = [self .blender_exec_path , '-v' ]
702
752
command_render = [
703
753
self .blender_exec_path , '-b' , self .blend_file_path ,
704
754
'-y' , '-P' , self .target_script
@@ -711,49 +761,18 @@ def Render(self, blend_file_path, target_script, preview_frame=0):
711
761
# Render entire animation
712
762
command_render .extend (['-a' ])
713
763
714
- # Check the version of Blender
715
- import shlex
716
- log .info ("Checking Blender version, command: {}" .format (
717
- " " .join ([shlex .quote (x ) for x in command_get_version ])))
718
-
719
- self .process = subprocess .Popen (
720
- command_get_version ,
721
- stdout = subprocess .PIPE , stderr = subprocess .STDOUT ,
722
- startupinfo = startupinfo ,
723
- )
724
-
725
- # Check the version of Blender
726
- try :
727
- # Give Blender up to 10 seconds to respond
728
- (out , err ) = self .process .communicate (timeout = 10 )
729
- except subprocess .TimeoutExpired :
730
- self .blender_error_nodata .emit ()
731
- return
732
-
733
- ver_string = out .decode ('utf-8' )
734
- ver_match = blender_version_re .search (ver_string )
735
-
736
- if not ver_match :
737
- raise Exception ("No Blender version detected in output" )
738
-
739
- self .version = ver_match .group (1 )
740
- log .info ("Found Blender version {}" .format (self .version ))
741
-
742
- if self .version < info .BLENDER_MIN_VERSION :
743
- # Wrong version of Blender.
744
- self .blender_version_error .emit (self .version )
745
- return
746
-
747
764
# debug info
748
- log .info ("Running Blender, command: {}" .format (
765
+ log .debug ("Running Blender, command: {}" .format (
749
766
" " .join ([shlex .quote (x ) for x in command_render ])))
750
- log .info ("Blender output:" )
767
+ log .debug ("Blender output:" )
751
768
752
- # Run real command to render Blender project
769
+ # Run command to render Blender frame(s)
770
+ if self .process :
771
+ self .process .terminate ()
753
772
self .process = subprocess .Popen (
754
773
command_render , bufsize = 512 ,
755
774
stdout = subprocess .PIPE , stderr = subprocess .STDOUT ,
756
- startupinfo = startupinfo ,
775
+ startupinfo = self . startupinfo ,
757
776
)
758
777
self .is_running = True
759
778
@@ -763,42 +782,41 @@ def Render(self, blend_file_path, target_script, preview_frame=0):
763
782
self .is_running = False
764
783
self .blender_error_nodata .emit ()
765
784
raise
766
- except Exception as ex :
767
- log .error ("Worker exception: {}" . format ( ex ) )
785
+ except Exception :
786
+ log .error ("Worker exception" , exc_info = 1 )
768
787
return
769
788
789
+ last_frame = 0
790
+ frame_saved = False
770
791
while self .is_running and self .process .poll () is None :
771
- for outline in iter (self .process .stdout .readline , b'' ):
772
- line = outline .decode ('utf-8' ).strip ()
792
+ for out_line in iter (self .process .stdout .readline , b'' ):
793
+ line = out_line .decode ('utf-8' ).strip ()
773
794
774
795
# Skip blank output
775
796
if not line :
776
797
continue
777
798
778
799
# append all output into a variable, and log
779
- self . command_output = self . command_output + line + "\n "
780
- log .info (" {}" .format (line ))
800
+ command_output += line + "\n "
801
+ log .debug (" {}" .format (line ))
781
802
782
803
# Look for progress info in the Blender Output
783
- output_frame = blender_frame_re .search (line )
784
- output_saved = blender_saved_re .search (line )
785
-
786
- # Does it have a match?
787
- if output_frame or output_saved :
788
- # Yes, we have a match
789
- self .frame_detected = True
804
+ output_frame = self .blender_frame_re .search (line )
805
+ output_saved = self .blender_saved_re .search (line )
790
806
791
807
if output_frame :
792
808
current_frame = int (output_frame .group (1 ))
793
809
794
810
# Update progress bar
795
- if current_frame != self . last_frame and not self . preview_mode :
811
+ if current_frame != last_frame and not preview_mode :
796
812
# update progress on frame change, if in 'render' mode
797
813
self .progress .emit (current_frame )
798
814
799
- self . last_frame = current_frame
815
+ last_frame = current_frame
800
816
801
817
if output_saved :
818
+ frame_saved = True
819
+ log .debug ("Saved frame %d" , last_frame )
802
820
# Update preview image
803
821
self .image_updated .emit (output_saved .group (1 ))
804
822
@@ -808,13 +826,13 @@ def Render(self, blend_file_path, target_script, preview_frame=0):
808
826
self .enable_interface .emit ()
809
827
810
828
# Check if NO FRAMES are detected
811
- if not self . frame_detected :
829
+ if not frame_saved :
812
830
# Show Error that no frames are detected. This is likely caused by
813
831
# the wrong command being executed... or an error in Blender.
814
832
self .blender_error_with_data .emit (_ ("No frame was found in the output from Blender" ))
815
833
816
834
# Done with render (i.e. close window)
817
- elif self .is_running and not self . preview_mode :
835
+ elif self .is_running and not preview_mode :
818
836
# only add file to project data if in 'render' mode and not canceled
819
837
self .finished .emit ()
820
838
0 commit comments