Exemplo n.º 1
0
    def handleMesh(self, obj):
        if OBJECT_ANALYSIS: indigo_log(' -> handleMesh: %s' % obj)

        self.exportModelElements(
            obj,
            self.buildMesh(obj),
            obj.matrix_world.copy()
        )
Exemplo n.º 2
0
    def handleLamp(self, obj):
        if OBJECT_ANALYSIS: indigo_log(' -> handleLamp: %s' % obj)

        if obj.data.type == 'AREA':
            pass
        if obj.data.type == 'HEMI':
            self.ExportedLamps[obj.name] = [obj.data.indigo_lamp_hemi.build_xml_element(obj, self.scene)]
        if obj.data.type == 'SUN':
            self.ExportedLamps[obj.name] = [obj.data.indigo_lamp_sun.build_xml_element(obj, self.scene)]
Exemplo n.º 3
0
    def exportModelElements(self, obj, mesh_definition, matrix, dupli_ob=None, particle_system=None):
        if OBJECT_ANALYSIS: indigo_log('exportModelElements: %s, %s, %s' % (obj, mesh_definition))
        
        # If this object was instanced by a DupliObject, hash the DupliObject's persistent_id
        if dupli_ob != None:
            key = hash((obj, particle_system, dupli_ob.persistent_id[0]))
        else:
            key = hash(obj)
        
        # If the model (object) was already exported, only update the keyframe list.
        emodel = self.ExportedObjects.get(key)
        if emodel != None:
            if emodel[0] == 'OBJECT':
                # Append to list of (time, matrix) tuples.
                emodel[3].append((self.normalised_time, matrix))
            
            return

        # Special handling for section planes:  If object has the section_plane attribute set, then export it as a section plane.
        if(obj.data != None and obj.data.indigo_mesh.section_plane):
            xml = SectionPlane(matrix.col[3], matrix.col[2], obj.data.indigo_mesh.cull_geometry).build_xml_element()

            model_definition = ('SECTION', xml)

            self.ExportedObjects[key] = model_definition
            self.object_id += 1
            return

        # Special handling for sphere primitives
        if(obj.data != None and obj.data.indigo_mesh.sphere_primitive):
            xml = SpherePrimitive(matrix, obj).build_xml_element()

            model_definition = ('SPHERE', xml)

            self.ExportedObjects[key] = model_definition
            self.object_id += 1
            return

        mesh_name = mesh_definition[0]
        
        # Special handling for exit portals
        if obj.type == 'MESH' and obj.data.indigo_mesh.exit_portal:
            xml = exit_portal(self.scene).build_xml_element(obj, mesh_name, [matrix])
            
            model_definition = ('PORTAL', xml)

            self.ExportedObjects[key] = model_definition
            self.object_id += 1
            return
            
        # Create list of (time, matrix) tuples.
        obj_matrices = [(self.normalised_time, matrix)]

        model_definition = ('OBJECT', obj, mesh_name, obj_matrices, self.scene)

        self.ExportedObjects[key] = model_definition
        self.object_id += 1
Exemplo n.º 4
0
 def check_output_path(self, path):
     efutil.export_path = efutil.filesystem_path(path)
     
     if not os.path.isdir(efutil.export_path):
         parent_dir = os.path.realpath( os.path.join(efutil.export_path, os.path.pardir) )
         if not self.check_write(parent_dir):
             indigo_log('Output path "%s" is not writable' % parent_dir)
             raise Exception('Output path is not writable')
         
         try:
             os.makedirs(efutil.export_path)
         except: 
             indigo_log('Could not create output path %s' % efutil.export_path)
             raise Exception('Could not create output path')
     
     if not self.check_write(efutil.export_path):
         indigo_log('Output path "%s" is not writable' % efutil.export_path)
         raise Exception('Output path is not writable')
     
     igs_filename = '/'.join( (efutil.export_path, self.properties.filename) )
     
     # indigo_log('Writing to %s'%igs_filename)
     
     if efutil.export_path[-1] not in ('/', '\\'):
         efutil.export_path += '/'
     
     try:
         out_file = open(igs_filename, 'w')
         out_file.close()
     except:
         indigo_log('Failed to open output file "%s" for writing: check output path setting' % igs_filename)
         raise Exception('Failed to open output file for writing: check output path setting')
     
     return igs_filename
Exemplo n.º 5
0
 def check_output_path(self, path):
     efutil.export_path = efutil.filesystem_path(path)
     
     if not os.path.isdir(efutil.export_path):
         parent_dir = os.path.realpath( os.path.join(efutil.export_path, os.path.pardir) )
         if not self.check_write(parent_dir):
             indigo_log('Output path "%s" is not writable' % parent_dir)
             raise Exception('Output path is not writable')
         
         try:
             os.makedirs(efutil.export_path)
         except: 
             indigo_log('Could not create output path %s' % efutil.export_path)
             raise Exception('Could not create output path')
     
     if not self.check_write(efutil.export_path):
         indigo_log('Output path "%s" is not writable' % efutil.export_path)
         raise Exception('Output path is not writable')
     
     igs_filename = '/'.join( (efutil.export_path, self.properties.filename) )
     
     # indigo_log('Writing to %s'%igs_filename)
     
     if efutil.export_path[-1] not in ('/', '\\'):
         efutil.export_path += '/'
     
     try:
         out_file = open(igs_filename, 'w')
         out_file.close()
     except:
         indigo_log('Failed to open output file "%s" for writing: check output path setting' % igs_filename)
         raise Exception('Failed to open output file for writing: check output path setting')
     
     return igs_filename
Exemplo n.º 6
0
    def build_xml_element(self, scene):
        xml = self.Element('tonemapping')

        # format needs to be entirely generated at export time
        if self.tonemap_type == 'reinhard':
            xml_format = {
                'reinhard': {
                    'pre_scale': 'reinhard_pre',
                    'post_scale': 'reinhard_post',
                    'burn': 'reinhard_burn',
                }
            }
        elif self.tonemap_type == 'linear':
            xml_format = {
                'linear': {
                    'scale': 'linear_unit',
                }
            }
        elif self.tonemap_type == 'camera':
            if self.camera_response_type == 'preset':
                crf = [self.camera_response_preset]
            elif self.camera_response_file != "" and os.path.exists(
                    efutil.filesystem_path(self.camera_response_file)):
                crf = 'camera_response_file'
            else:
                indigo_log(
                    'WARNING: Invalid camera tonemapping, using default dscs315.txt'
                )
                crf = ['data/camera_response_functions/dscs315.txt']
            xml_format = {
                'camera': {
                    'response_function_path': crf,
                    'ev_adjust': 'camera_ev',
                    'film_iso': [scene.camera.data.indigo_camera.iso]
                }
            }
        else:
            xml_format = {}

        self.build_subelements(scene, xml_format, xml)

        return xml
Exemplo n.º 7
0
 def handleDuplis(self, obj, particle_system=None):
     if self.CheckedDuplis.have(obj): return
     self.CheckedDuplis.add(obj, obj)
     
     try:
         obj.dupli_list_create(self.scene, 'RENDER')
         if not obj.dupli_list:
             raise Exception('cannot create dupli list for object %s' % obj.name)
     except Exception as err:
         indigo_log('%s'%err)
         return
     
     for dupli_ob in obj.dupli_list:
         if dupli_ob.object.type not in self.supported_mesh_types:
             continue
         if not indigo_visible(self.scene, dupli_ob.object, is_dupli=True):
             continue
         
         self.handleMesh(dupli_ob.object)
     
     obj.dupli_list_clear()
Exemplo n.º 8
0
 def handleDuplis(self, obj, particle_system=None):
     if self.CheckedDuplis.have(obj): return
     self.CheckedDuplis.add(obj, obj)
     
     try:
         obj.dupli_list_create(self.scene, 'RENDER')
         if not obj.dupli_list:
             raise Exception('cannot create dupli list for object %s' % obj.name)
     except Exception as err:
         indigo_log('%s'%err)
         return
     
     for dupli_ob in obj.dupli_list:
         if dupli_ob.object.type not in self.supported_mesh_types:
             continue
         if not indigo_visible(self.scene, dupli_ob.object, is_dupli=True):
             continue
         
         self.handleMesh(dupli_ob.object)
     
     obj.dupli_list_clear()
Exemplo n.º 9
0
 def execute(self, context):
     #print("Selected: " + context.active_object.name)
     #print("Filename: %s"%self.properties.filepath)
     
     if not self.properties.filepath:
         indigo_log('Filename not set', message_type='ERROR')
         return {'CANCELLED'}
     
     if self.properties.objectname == '':
         self.properties.objectname = context.active_object.name
     
     try:
         obj = bpy.data.objects[self.properties.objectname]
     except:
         indigo_log('Cannot find mesh data in context', message_type='ERROR')
         return {'CANCELLED'}
     
     mesh = obj.to_mesh(self.scene, True, 'RENDER')
     igmesh_writer.factory(context.scene, obj, self.properties.filepath, mesh, debug=False)
     bpy.data.meshes.remove(mesh)
     
     return {'FINISHED'}
Exemplo n.º 10
0
 def build_xml_element(self, scene):
     xml = self.Element('tonemapping')
     
     # format needs to be entirely generated at export time
     if self.tonemap_type == 'reinhard':
         xml_format = {
             'reinhard': {
                 'pre_scale': 'reinhard_pre',
                 'post_scale': 'reinhard_post',
                 'burn': 'reinhard_burn',
             }
         }
     elif self.tonemap_type == 'linear':
         xml_format = {
             'linear': {
                 'scale': 'linear_unit',
             }
         }
     elif self.tonemap_type == 'camera':
         if self.camera_response_type == 'preset':
             crf = [self.camera_response_preset]
         elif self.camera_response_file!="" and os.path.exists(efutil.filesystem_path(self.camera_response_file)):
             crf = 'camera_response_file'
         else:
             indigo_log('WARNING: Invalid camera tonemapping, using default dscs315.txt')
             crf = ['data/camera_response_functions/dscs315.txt']
         xml_format = {
             'camera': {
                 'response_function_path': crf,
                 'ev_adjust': 'camera_ev',
                 'film_iso': [scene.camera.data.indigo_camera.iso]
             }
         }
     else:
         xml_format = {}
     
     self.build_subelements(scene, xml_format, xml)
     
     return xml
Exemplo n.º 11
0
 def execute(self, context):
     #print("Selected: " + context.active_object.name)
     #print("Filename: %s"%self.properties.filepath)
     
     if not self.properties.filepath:
         indigo_log('Filename not set', message_type='ERROR')
         return {'CANCELLED'}
     
     if self.properties.objectname == '':
         self.properties.objectname = context.active_object.name
     
     try:
         obj = bpy.data.objects[self.properties.objectname]
     except:
         indigo_log('Cannot find mesh data in context', message_type='ERROR')
         return {'CANCELLED'}
     
     mesh = obj.to_mesh(self.scene, True, 'RENDER')
     igmesh_writer.factory(context.scene, obj, self.properties.filepath, mesh, debug=False)
     bpy.data.meshes.remove(mesh)
     
     return {'FINISHED'}
Exemplo n.º 12
0
    def factory(scene, obj, filename, mesh, debug=False):

        debug = False

        if debug:
            start_time = time.time()
            print('igmesh_writer.factory was passed %s' % obj)
            indigo_log('igmesh_writer.factory was passed %s' % obj)

        if obj.type not in ['MESH', 'SURFACE', 'FONT', 'CURVE']:
            raise Exception(
                "Can only export 'MESH', 'SURFACE', 'FONT', 'CURVE' objects")

        (used_mat_indices, use_shading_normals) = igmesh_writer.write_mesh(
            filename, scene, obj, mesh)

        if debug:
            end_time = time.time()
            print('Build + Save took %0.2f sec' % (end_time - start_time))
            indigo_log('Build + Save took %0.5f sec' % (end_time - start_time))

        return (used_mat_indices, use_shading_normals)
Exemplo n.º 13
0
    def handleDuplis(self, obj, particle_system=None):
        try:
            #if obj in self.ExportedDuplis:
            #    indigo_log('Duplis for object %s already exported'%obj)
            #    return

            try:
                obj.dupli_list_create(self.scene, 'RENDER')
                if not obj.dupli_list:
                    raise Exception('cannot create dupli list for object %s' % obj.name)
            except Exception as err:
                indigo_log('%s'%err)
                return
                
            exported_objects = 0

            # Create our own DupliOb list to work around incorrect layers
            # attribute when inside create_dupli_list()..free_dupli_list()
            for dupli_ob in obj.dupli_list:
                if dupli_ob.object.type not in self.supported_mesh_types:
                    continue
                if not indigo_visible(self.scene, dupli_ob.object, is_dupli=True):
                    continue

                do = dupli_ob.object
                dm = dupli_ob.matrix.copy()
                
                # Check for group layer visibility, if the object is in a group
                gviz = len(do.users_group) == 0
                for grp in do.users_group:
                    gviz |= True in [a&b for a,b in zip(do.layers, grp.layers)]
                if not gviz:
                    continue

                exported_objects += 1
                
                self.exportModelElements(
                    do,
                    self.buildMesh(do),
                    dm,
                    dupli_ob,
                    particle_system
                )

            obj.dupli_list_clear()
            
            self.ExportedDuplis[obj] = True
            
            if self.verbose: indigo_log('... done, exported %s duplis' % exported_objects)

        except SystemError as err:
            indigo_log('Error with handleDuplis and object %s: %s' % (obj, err))
Exemplo n.º 14
0
    def execute(self, master_scene):
        try:
            if master_scene is None:
                #indigo_log('Scene context is invalid')
                raise Exception('Scene context is invalid')
            
            #------------------------------------------------------------------------------
            # Init stats
            if self.verbose: indigo_log('Indigo export started ...')
            export_start_time = time.time()
            
            igs_filename = self.check_output_path(self.properties.directory)
            export_scenes = [master_scene.background_set, master_scene]
            
            if self.verbose: indigo_log('Export render settings')
            
            #------------------------------------------------------------------------------
            # Start with render settings, this also creates the root <scene>
            self.scene_xml = master_scene.indigo_engine.build_xml_element(master_scene)
            
            # Export background light if no light exists.
            self.export_default_background_light(export_scenes)
            
            #------------------------------------------------------------------------------
            # Tonemapping
            self.export_tonemapping(master_scene)
            
            #------------------------------------------------------------------------------
            # Materials - always export the default clay material and a null material
            self.export_default_materials(master_scene)
            
            # Initialise values used for motion blur export.
            fps = master_scene.render.fps / master_scene.render.fps_base
            start_frame = master_scene.frame_current
            exposure = 1 / master_scene.camera.data.indigo_camera.exposure
            camera = (master_scene.camera, [])
            
            # Make a relative igs and mesh dir path like "TheAnimation/00002"
            rel_mesh_dir = efutil.scene_filename()
            rel_frame_dir = '%s/%05i' % (rel_mesh_dir, start_frame) #bpy.path.clean_name(master_scene.name), 
            mesh_dir = '/'.join([efutil.export_path, rel_mesh_dir])
            frame_dir = '/'.join([efutil.export_path, rel_frame_dir])
            
            # Initialise GeometryExporter.
            geometry_exporter = geometry.GeometryExporter()
            geometry_exporter.mesh_dir = mesh_dir
            geometry_exporter.rel_mesh_dir = rel_mesh_dir
            geometry_exporter.skip_existing_meshes = master_scene.indigo_engine.skip_existing_meshes
            geometry_exporter.verbose = self.verbose
            
            # Make frame_dir directory if it does not exist yet.
            if not os.path.exists(frame_dir):
                os.makedirs(frame_dir)
            
            if master_scene.indigo_engine.motionblur:
                # When motion blur is on, calculate the number of frames covered by the exposure time
                start_time = start_frame / fps
                end_time = start_time + exposure
                end_frame = math.ceil(end_time * fps)
                
                # end_frame + 1 because range is max excl
                frame_list = [x for x in range(start_frame, end_frame+1)]
            else:
                frame_list = [start_frame]
                
            #indigo_log('frame_list: %s'%frame_list)
            
            #------------------------------------------------------------------------------
            # Process all objects in all frames in all scenes.
            for cur_frame in frame_list:
                # Calculate normalised time for keyframes.
                normalised_time = (cur_frame - start_frame) / fps / exposure
                if self.verbose: indigo_log('Processing frame: %i time: %f'%(cur_frame, normalised_time))
                
                geometry_exporter.normalised_time = normalised_time
                bpy.context.scene.frame_set(cur_frame, 0.0)

                # Add Camera matrix.
                camera[1].append((normalised_time, camera[0].matrix_world.copy()))
            
                for ex_scene in export_scenes:
                    if ex_scene is None: continue
                    
                    if self.verbose: indigo_log('Processing objects for scene %s' % ex_scene.name)
                    geometry_exporter.iterateScene(ex_scene)
            
            #------------------------------------------------------------------------------
            # Export camera
            if self.verbose: indigo_log('Exporting camera')
            self.scene_xml.append(
                camera[0].data.indigo_camera.build_xml_element(master_scene, camera[1])
            )
            
            #------------------------------------------------------------------------------
            # Export light layers
            from indigo.export.light_layer import light_layer_xml
            # TODO:
            # light_layer_count was supposed to export correct indices when there
            # is a background_set with emitters on light layers -
            # however, the re-indexing at material export time is non-trivial for
            # now and probably not worth it.
            #light_layer_count = 0
            for ex_scene in export_scenes:
                if ex_scene is None: continue
                
                # Light layer names
                for layer_name, idx in ex_scene.indigo_lightlayers.enumerate().items():
                    if self.verbose: indigo_log('Light layer %i: %s' % (idx, layer_name))
                    self.scene_xml.append(
                        light_layer_xml().build_xml_element(ex_scene, idx, layer_name)
                    )
                    # light_layer_count += 1
            
            if self.verbose: indigo_log('Exporting lamps')
            
            # use special n==1 case due to bug in indigo <sum> material
            num_lamps = len(geometry_exporter.ExportedLamps)
            
            if num_lamps == 1:
                scene_background_settings = ET.Element('background_settings')
                scene_background_settings_mat = ET.Element('background_material')
                scene_background_settings.append(scene_background_settings_mat)
                
                for ck, ci in geometry_exporter.ExportedLamps.items():
                    for xml in ci:
                        scene_background_settings_mat.append(xml)
                
                self.scene_xml.append(scene_background_settings)
            
            if num_lamps > 1:
                
                scene_background_settings = ET.Element('background_settings')
                scene_background_settings_fmt = {
                    'background_material': {
                        'material': {
                            'name': ['background_material'],
                            'sum': { 'mat': xml_multichild() }
                        }
                    }
                }
                
                for ck, ci in geometry_exporter.ExportedLamps.items():
                    for xml in ci:
                        self.scene_xml.append(xml)
                    
                    scene_background_settings_fmt['background_material']['material']['sum']['mat'].append({
                        'mat_name': [ck],
                        'weight': {'constant': [1]}
                    })
                scene_background_settings_obj = xml_builder()
                scene_background_settings_obj.build_subelements(None, scene_background_settings_fmt, scene_background_settings)
                self.scene_xml.append(scene_background_settings)
            
            #------------------------------------------------------------------------------
            # Export Medium
            from indigo.export.materials.medium import medium_xml
            # TODO:
            # check if medium is currently used by any material and add 
            # basic medium for SpecularMaterial default

            for ex_scene in export_scenes:
                if ex_scene is None: continue
                
                indigo_material_medium = ex_scene.indigo_material_medium
                medium = indigo_material_medium.medium
                
                if len(indigo_material_medium.medium.items()) == 0 : continue
                
                for medium_name, medium_data in medium.items():
                    
                    medium_index = ex_scene.indigo_material_medium.medium.find(medium_name) # more precise if same name
                    
                    indigo_log('Exporting medium: %s ' % (medium_name))
                    self.scene_xml.append(
                        medium_xml(ex_scene, medium_name, medium_index, medium_data).build_xml_element(ex_scene, medium_name, medium_data)
                    )
                indigo_log('Exporting Medium: %s ' % (medium_name))         
                # TODO: 
                # check for unused medium	
            basic_medium = ET.fromstring("""
                                <medium>
                                   <uid>10200137</uid>
		                             <name>basic</name>
			                           <precedence>10</precedence>
			                             <basic>
				                           <ior>1.5</ior>
				                           <cauchy_b_coeff>0</cauchy_b_coeff>
				                           <max_extinction_coeff>1</max_extinction_coeff>
				                           <absorption_coefficient>
					                         <constant>
						                      <uniform>
							                   <value>0</value>
						                      </uniform>
					                         </constant>
				                           </absorption_coefficient>
			                             </basic>
	                            </medium>   
                         """)
            
            self.scene_xml.append(basic_medium)
            
            #------------------------------------------------------------------------------
            # Export used materials.
            if self.verbose: indigo_log('Exporting used materials')
            material_count = 0
            for ck, ci in geometry_exporter.ExportedMaterials.items():
                for xml in ci:
                    self.scene_xml.append(xml)
                material_count += 1
            if self.verbose: indigo_log('Exported %i materials' % material_count)
            
            # Export used meshes.
            if self.verbose: indigo_log('Exporting meshes')
            mesh_count = 0
            for ck, ci in geometry_exporter.MeshesOnDisk.items():
                mesh_name, xml = ci
                self.scene_xml.append(xml)
                mesh_count += 1
            if self.verbose: indigo_log('Exported %i meshes' % mesh_count)
            
            #------------------------------------------------------------------------------
            # We write object instances to a separate file
            oc = 0
            scene_data_xml = ET.Element('scenedata')
            for ck, ci in geometry_exporter.ExportedObjects.items():
                obj_type = ci[0]
                
                if obj_type == 'OBJECT':
                    obj = ci[1]
                    mesh_name = ci[2]
                    obj_matrices = ci[3]
                    scene = ci[4]
                    
                    xml = geometry.model_object(scene).build_xml_element(obj, mesh_name, obj_matrices)
                else:
                    xml = ci[1]
                    
                scene_data_xml.append(xml)
                oc += 1
            
            objects_file_name = '%s/objects.igs' % (
                frame_dir
            )
            
            objects_file = open(objects_file_name, 'wb')
            ET.ElementTree(element=scene_data_xml).write(objects_file, encoding='utf-8')
            objects_file.close()
            # indigo_log('Exported %i object instances to %s' % (oc,objects_file_name))
            scene_data_include = include.xml_include( efutil.path_relative_to_export(objects_file_name) )
            self.scene_xml.append( scene_data_include.build_xml_element(master_scene) )
            
            #------------------------------------------------------------------------------
            # Write formatted XML for settings, materials and meshes
            out_file = open(igs_filename, 'w')
            xml_str = ET.tostring(self.scene_xml, encoding='utf-8').decode()
            
            # substitute back characters protected from entity encoding in CDATA nodes
            xml_str = xml_str.replace('{_LESSTHAN_}', '<')
            xml_str = xml_str.replace('{_GREATERTHAN_}', '>')
            
            xml_dom = MD.parseString(xml_str)
            xml_dom.writexml(out_file, addindent='\t', newl='\n', encoding='utf-8')
            out_file.close()
            
            #------------------------------------------------------------------------------
            # Print stats
            export_end_time = time.time()
            if self.verbose: indigo_log('Total mesh export time: %f seconds' % (geometry_exporter.total_mesh_export_time))
            indigo_log('Export finished; took %f seconds' % (export_end_time-export_start_time))
            
            # Reset to start_frame.
            if len(frame_list) > 1:
                bpy.context.scene.frame_set(start_frame)
            
            return {'FINISHED'}
        
        except Exception as err:
            indigo_log('%s' % err, message_type='ERROR')
            if os.getenv('B25_OBJECT_ANALYSIS', False):
                raise err
            return {'CANCELLED'}
Exemplo n.º 15
0
 def export_tonemapping(self, master_scene):
     if self.verbose: indigo_log('Exporting tonemapping')
     self.scene_xml.append(
         master_scene.camera.data.indigo_tonemapping.build_xml_element(master_scene)
     )
Exemplo n.º 16
0
 def export_tonemapping(self, master_scene):
     if self.verbose: indigo_log('Exporting tonemapping')
     self.scene_xml.append(
         master_scene.camera.data.indigo_tonemapping.build_xml_element(master_scene)
     )
Exemplo n.º 17
0
    def execute(self, master_scene):
        try:
            if master_scene is None:
                #indigo_log('Scene context is invalid')
                raise Exception('Scene context is invalid')
            
            #------------------------------------------------------------------------------
            # Init stats
            if self.verbose: indigo_log('Indigo export started ...')
            export_start_time = time.time()
            
            igs_filename = self.check_output_path(self.properties.directory)
            export_scenes = [master_scene.background_set, master_scene]
            
            if self.verbose: indigo_log('Export render settings')
            
            #------------------------------------------------------------------------------
            # Start with render settings, this also creates the root <scene>
            self.scene_xml = master_scene.indigo_engine.build_xml_element(master_scene)
            
            # Export background light if no light exists.
            self.export_default_background_light(export_scenes)
            
            #------------------------------------------------------------------------------
            # Tonemapping
            self.export_tonemapping(master_scene)
            
            #------------------------------------------------------------------------------
            # Materials - always export the default clay material and a null material
            self.export_default_materials(master_scene)
            
            # Initialise values used for motion blur export.
            fps = master_scene.render.fps / master_scene.render.fps_base
            start_frame = master_scene.frame_current
            exposure = 1 / master_scene.camera.data.indigo_camera.exposure
            camera = (master_scene.camera, [])
            
            # Make a relative igs and mesh dir path like "TheAnimation/00002"
            rel_mesh_dir = efutil.scene_filename()
            rel_frame_dir = '%s/%05i' % (rel_mesh_dir, start_frame) #bpy.path.clean_name(master_scene.name), 
            mesh_dir = '/'.join([efutil.export_path, rel_mesh_dir])
            frame_dir = '/'.join([efutil.export_path, rel_frame_dir])
            
            # Initialise GeometryExporter.
            geometry_exporter = geometry.GeometryExporter()
            geometry_exporter.mesh_dir = mesh_dir
            geometry_exporter.rel_mesh_dir = rel_mesh_dir
            geometry_exporter.skip_existing_meshes = master_scene.indigo_engine.skip_existing_meshes
            geometry_exporter.verbose = self.verbose
            
            # Make frame_dir directory if it does not exist yet.
            if not os.path.exists(frame_dir):
                os.makedirs(frame_dir)
            
            if master_scene.indigo_engine.motionblur:
                # When motion blur is on, calculate the number of frames covered by the exposure time
                start_time = start_frame / fps
                end_time = start_time + exposure
                end_frame = math.ceil(end_time * fps)
                
                # end_frame + 1 because range is max excl
                frame_list = [x for x in range(start_frame, end_frame+1)]
            else:
                frame_list = [start_frame]
                
            #indigo_log('frame_list: %s'%frame_list)
            
            #------------------------------------------------------------------------------
            # Process all objects in all frames in all scenes.
            for cur_frame in frame_list:
                # Calculate normalised time for keyframes.
                normalised_time = (cur_frame - start_frame) / fps / exposure
                if self.verbose: indigo_log('Processing frame: %i time: %f'%(cur_frame, normalised_time))
                
                geometry_exporter.normalised_time = normalised_time
                bpy.context.scene.frame_set(cur_frame, 0.0)

                # Add Camera matrix.
                camera[1].append((normalised_time, camera[0].matrix_world.copy()))
            
                for ex_scene in export_scenes:
                    if ex_scene is None: continue
                    
                    if self.verbose: indigo_log('Processing objects for scene %s' % ex_scene.name)
                    geometry_exporter.iterateScene(ex_scene)
            
            #------------------------------------------------------------------------------
            # Export camera
            if self.verbose: indigo_log('Exporting camera')
            self.scene_xml.append(
                camera[0].data.indigo_camera.build_xml_element(master_scene, camera[1])
            )
            
            #------------------------------------------------------------------------------
            # Export light layers
            from indigo.export.light_layer import light_layer_xml
            # TODO:
            # light_layer_count was supposed to export correct indices when there
            # is a background_set with emitters on light layers -
            # however, the re-indexing at material export time is non-trivial for
            # now and probably not worth it.
            #light_layer_count = 0
            for ex_scene in export_scenes:
                if ex_scene is None: continue
                
                # Light layer names
                for layer_name, idx in ex_scene.indigo_lightlayers.enumerate().items():
                    if self.verbose: indigo_log('Light layer %i: %s' % (idx, layer_name))
                    self.scene_xml.append(
                        light_layer_xml().build_xml_element(ex_scene, idx, layer_name)
                    )
                    # light_layer_count += 1
            
            if self.verbose: indigo_log('Exporting lamps')
            
            # use special n==1 case due to bug in indigo <sum> material
            num_lamps = len(geometry_exporter.ExportedLamps)
            
            if num_lamps == 1:
                scene_background_settings = ET.Element('background_settings')
                scene_background_settings_mat = ET.Element('background_material')
                scene_background_settings.append(scene_background_settings_mat)
                
                for ck, ci in geometry_exporter.ExportedLamps.items():
                    for xml in ci:
                        scene_background_settings_mat.append(xml)
                
                self.scene_xml.append(scene_background_settings)
            
            if num_lamps > 1:
                
                scene_background_settings = ET.Element('background_settings')
                scene_background_settings_fmt = {
                    'background_material': {
                        'material': {
                            'name': ['background_material'],
                            'sum': { 'mat': xml_multichild() }
                        }
                    }
                }
                
                for ck, ci in geometry_exporter.ExportedLamps.items():
                    for xml in ci:
                        self.scene_xml.append(xml)
                    
                    scene_background_settings_fmt['background_material']['material']['sum']['mat'].append({
                        'mat_name': [ck],
                        'weight': {'constant': [1]}
                    })
                scene_background_settings_obj = xml_builder()
                scene_background_settings_obj.build_subelements(None, scene_background_settings_fmt, scene_background_settings)
                self.scene_xml.append(scene_background_settings)
            
            #------------------------------------------------------------------------------
            # Export Medium
            from indigo.export.materials.medium import medium_xml
            # TODO:
            # check if medium is currently used by any material 

            for ex_scene in export_scenes:
                if ex_scene is None: continue
                
                medium = ex_scene.indigo_material_medium.medium
                
                if len(medium.items()) < 0 : continue
                
                for medium_index, medium_data in enumerate(medium):
                    medium_name = medium_data.name
                    indigo_log('Exporting medium: %s ' % (medium_name))
                    self.scene_xml.append(
                        medium_xml(ex_scene, medium_name, medium_index, medium_data).build_xml_element(ex_scene, medium_name, medium_data)
                    )

            basic_medium = ET.fromstring("""
                                <medium>
                                   <uid>"""+str(len(medium)+10)+"""</uid>
		                             <name>Basic medium</name>
			                           <precedence>10</precedence>
			                             <basic>
				                           <ior>1.5</ior>
				                           <cauchy_b_coeff>0</cauchy_b_coeff>
				                           <max_extinction_coeff>1</max_extinction_coeff>
				                           <absorption_coefficient>
					                         <constant>
						                      <uniform>
							                   <value>0</value>
						                      </uniform>
					                         </constant>
				                           </absorption_coefficient>
			                             </basic>
	                            </medium>   
                         """) 
            self.scene_xml.append(basic_medium)

            #------------------------------------------------------------------------------
            # Export used materials.
            if self.verbose: indigo_log('Exporting used materials')
            material_count = 0
            for ck, ci in geometry_exporter.ExportedMaterials.items():
                for xml in ci:
                    self.scene_xml.append(xml)
                material_count += 1
            if self.verbose: indigo_log('Exported %i materials' % material_count)
            
            # Export used meshes.
            if self.verbose: indigo_log('Exporting meshes')
            mesh_count = 0
            for ck, ci in geometry_exporter.MeshesOnDisk.items():
                mesh_name, xml = ci
                self.scene_xml.append(xml)
                mesh_count += 1
            if self.verbose: indigo_log('Exported %i meshes' % mesh_count)
            
            #------------------------------------------------------------------------------
            # We write object instances to a separate file
            oc = 0
            scene_data_xml = ET.Element('scenedata')
            for ck, ci in geometry_exporter.ExportedObjects.items():
                obj_type = ci[0]
                
                if obj_type == 'OBJECT':
                    obj = ci[1]
                    mesh_name = ci[2]
                    obj_matrices = ci[3]
                    scene = ci[4]
                    
                    xml = geometry.model_object(scene).build_xml_element(obj, mesh_name, obj_matrices)
                else:
                    xml = ci[1]
                    
                scene_data_xml.append(xml)
                oc += 1
            
            objects_file_name = '%s/objects.igs' % (
                frame_dir
            )
            
            objects_file = open(objects_file_name, 'wb')
            ET.ElementTree(element=scene_data_xml).write(objects_file, encoding='utf-8')
            objects_file.close()
            # indigo_log('Exported %i object instances to %s' % (oc,objects_file_name))
            scene_data_include = include.xml_include( efutil.path_relative_to_export(objects_file_name) )
            self.scene_xml.append( scene_data_include.build_xml_element(master_scene) )
            
            #------------------------------------------------------------------------------
            # Write formatted XML for settings, materials and meshes
            out_file = open(igs_filename, 'w')
            xml_str = ET.tostring(self.scene_xml, encoding='utf-8').decode()
            
            # substitute back characters protected from entity encoding in CDATA nodes
            xml_str = xml_str.replace('{_LESSTHAN_}', '<')
            xml_str = xml_str.replace('{_GREATERTHAN_}', '>')
            
            xml_dom = MD.parseString(xml_str)
            xml_dom.writexml(out_file, addindent='\t', newl='\n', encoding='utf-8')
            out_file.close()
            
            #------------------------------------------------------------------------------
            # Print stats
            export_end_time = time.time()
            if self.verbose: indigo_log('Total mesh export time: %f seconds' % (geometry_exporter.total_mesh_export_time))
            indigo_log('Export finished; took %f seconds' % (export_end_time-export_start_time))
            
            # Reset to start_frame.
            if len(frame_list) > 1:
                bpy.context.scene.frame_set(start_frame)
            
            return {'FINISHED'}
        
        except Exception as err:
            indigo_log('%s' % err, message_type='ERROR')
            if os.getenv('B25_OBJECT_ANALYSIS', False):
                raise err
            return {'CANCELLED'}
Exemplo n.º 18
0
    def render(self, context):
        '''
        Render the scene file, or in our case, export the frame(s)
        and launch an Indigo process.
        '''

        with RENDERENGINE_indigo.render_lock:    # Just render one thing at a time.
            self.renderer            = None
            self.message_thread      = None
            self.stats_thread        = None
            self.framebuffer_thread  = None
            self.render_update_timer = None
            self.rendering           = False

            # force scene update to current rendering frame
            # Not sure why - Yves
            #context.frame_set(context.frame_current)

            #------------------------------------------------------------------------------
            # Export the Scene

            # Get the frame path.
            frame_path = efutil.filesystem_path(context.render.frame_path())

            # Get the filename for the frame sans extension.
            image_out_path = os.path.splitext(frame_path)[0]

            # Generate the name for the scene file(s).
            if context.indigo_engine.use_output_path == True:
                # Get the output path from the frame path.
                output_path = os.path.dirname(frame_path)

                # Generate the output filename
                output_filename = '%s.%s.%05i.igs' % (efutil.scene_filename(), bpy.path.clean_name(context.name), context.frame_current)
            else:
                # Get export path from the indigo_engine.
                export_path = efutil.filesystem_path(context.indigo_engine.export_path)

                # Get the directory name from the output path.
                output_path = os.path.dirname(export_path)

                # Get the filename from the output path and remove the extension.
                output_filename = os.path.splitext(os.path.basename(export_path))[0]

                # Count contiguous # chars and replace them with the frame number.
                # If the hash count is 0 and we are exporting an animation, append the frame numbers.
                hash_count = util.count_contiguous('#', output_filename)
                if hash_count != 0:
                    output_filename = output_filename.replace('#'*hash_count, ('%%0%0ii'%hash_count)%context.frame_current)
                elif self.is_animation:
                    output_filename = output_filename + ('%%0%0ii'%4)%context.frame_current

                # Add .igs extension.
                output_filename += '.igs'


            # The full path of the exported scene file.
            exported_file = '/'.join([
                output_path,
                output_filename
            ])

            # Create output_path if it does not exist.
            if not os.path.exists(output_path):
                os.makedirs(output_path)

            # If an animation is rendered, write an indigo queue file (.igq).
            if self.is_animation:
                igq_filename = '%s/%s.%s.igq'%(output_path, efutil.scene_filename(), bpy.path.clean_name(context.name))

                if context.frame_current == context.frame_start:
                    # Start a new igq file.
                    igq_file = open(igq_filename, 'w')
                    igq_file.write('<?xml version="1.0" encoding="utf-8" standalone="no" ?>\n')
                    igq_file.write('<render_queue>\n')
                else:
                    # Append to existing igq.
                    igq_file = open(igq_filename, 'a')
                    
                rnd = random.Random()
                rnd.seed(context.frame_current)

                # Write igq item.
                igq_file.write('\t<item>\n')
                igq_file.write('\t\t<scene_path>%s</scene_path>\n' % exported_file)
                igq_file.write('\t\t<halt_time>%d</halt_time>\n' % context.indigo_engine.halttime)
                igq_file.write('\t\t<halt_spp>%d</halt_spp>\n' % context.indigo_engine.haltspp)
                igq_file.write('\t\t<output_path>%s</output_path>\n' % image_out_path)
                igq_file.write('\t\t<seed>%s</seed>\n' % rnd.randint(1, 1000000))
                igq_file.write('\t</item>\n')

                # If this is the last frame, write the closing tag.
                if context.frame_current == context.frame_end:
                    igq_file.write('</render_queue>\n')

                igq_file.close()

                # Calculate the progress by frame with frame range (fr) and frame offset (fo).
                fr = context.frame_end - context.frame_start
                fo = context.frame_current - context.frame_start
                self.update_progress(fo/fr)

            scene_writer = indigo.operators._Impl_OT_indigo(
                directory = output_path,
                filename = output_filename
            ).set_report(self.report)

            # Write the scene file.
            export_result = scene_writer.execute(context)

            # Return if the export didn't finish.
            if not 'FINISHED' in export_result:
                return

            #------------------------------------------------------------------------------
            # Update indigo defaults config file .
            config_updates = {
                'auto_start': context.indigo_engine.auto_start,
                'console_output': context.indigo_engine.console_output
            }

            if context.indigo_engine.use_console:
                indigo_path = getConsolePath(context)
            else:
                indigo_path = getGuiPath(context)

            if os.path.exists(indigo_path):
                config_updates['install_path'] = getInstallPath(context)

            try:
                for k,v in config_updates.items():
                    efutil.write_config_value('indigo', 'defaults', k, v)
            except Exception as err:
                indigo_log('Saving indigo config failed: %s' % err, message_type='ERROR')

            # Make sure that the Indigo we are going to launch is at least as
            # new as the exporter version.
            version_ok = True
            if not context.indigo_engine.skip_version_check:
                iv = getVersion(context)
                for i in range(3):
                    version_ok &= iv[i]>=bl_info['version'][i]

            #------------------------------------------------------------------------------
            # Conditionally Spawn Indigo.
            if context.indigo_engine.auto_start:

                exe_path = efutil.filesystem_path( indigo_path )

                if not os.path.exists(exe_path):
                    print("Failed to find indigo at '" + str(exe_path) + "'")
                    msg = "Failed to find indigo at '" + str(exe_path) + "'."
                    msg + "\n  "
                    msg += "Please make sure you have Indigo installed, and that the path to indigo in the 'Indigo Render Engine Settings' is set correctly."
                    self.report({'ERROR'}, msg)

                #if not version_ok:
                    #indigo_log("Unsupported version v%s; Cannot start Indigo with this scene" % ('.'.join(['%s'%i for i in iv])), message_type='ERROR')
                    #return

                # if it's an animation, don't execute until final frame
                if self.is_animation and context.frame_current != context.frame_end:
                    return

                # if animation and final frame, launch queue instead of single frame
                if self.is_animation and context.frame_current == context.frame_end:
                    exported_file = igq_filename
                    indigo_args = [
                        exe_path,
                        exported_file
                    ]
                else:
                    indigo_args = [
                        exe_path,
                        exported_file,
                        '-o',
                        image_out_path + '.png'
                    ]

                # Set master or working master command line args.
                if context.indigo_engine.network_mode == 'master':
                    indigo_args.extend(['-n', 'm'])
                elif context.indigo_engine.network_mode == 'working_master':
                    indigo_args.extend(['-n', 'wm'])

                # Set port arg if network rendering is enabled.
                if context.indigo_engine.network_mode in ['master', 'working_master']:
                    indigo_args.extend([
                        '-p',
                        '%i' % context.indigo_engine.network_port
                    ])

                # Set hostname and port arg.
                if context.indigo_engine.network_mode == 'manual':
                    indigo_args.extend([
                        '-h',
                        '%s:%i' % (context.indigo_engine.network_host, context.indigo_engine.network_port)
                ])

                # indigo_log("Starting indigo: %s" % indigo_args)

                # If we're starting a console or should wait for the process, listen to the output.
                if context.indigo_engine.use_console or context.indigo_engine.wait_for_process:
                    f_stdout = subprocess.PIPE
                else:
                    f_stdout = None

                # Launch the Indigo process.
                indigo_proc = subprocess.Popen(indigo_args, stdout=f_stdout)
                indigo_pid = indigo_proc.pid
                indigo_log('Started Indigo process, PID: %i' % indigo_pid)

                # Wait for the render to finish if we use the console or should wait for the process.
                if context.indigo_engine.use_console or context.indigo_engine.wait_for_process:
                    while indigo_proc.poll() == None:
                        indigo_proc.communicate()
                        time.sleep(2)

                    indigo_proc.wait()
                    if not indigo_proc.stdout.closed:
                        indigo_proc.communicate()
                    if indigo_proc.returncode == -1:
                        sys.exit(-1)

            else:
                indigo_log("Scene was exported to %s" % exported_file)

            #------------------------------------------------------------------------------
            # Finished
            return
Exemplo n.º 19
0
    def exportMeshElement(self, obj):
        if OBJECT_ANALYSIS: indigo_log('exportMeshElement: %s' % obj)

        if obj.type in self.supported_mesh_types:
        
            start_time = time.time()
            
            # If this object has already been exported, then don't export it again. 
            exported_mesh = self.ExportedMeshes.get(obj)
            if exported_mesh != None:
                self.total_mesh_export_time += time.time() - start_time
                return exported_mesh
        
            # Create mesh with applied modifiers
            mesh = obj.to_mesh(self.scene, True, 'RENDER')

            # Compute a hash over the mesh data (vertex positions, material names etc..)
            mesh_hash = self.meshHash(obj, mesh)

            # Form a mesh name like "4618cbf0bc13316135d676fffe0a74fc9b0577909246477354da9254"
            # The name cannot contain the objects name, as the name itself is always unique.
            exported_mesh_name = bpy.path.clean_name(mesh_hash)

            # If this mesh has already been exported, then don't export it again
            exported_mesh = self.MeshesOnDisk.get(exported_mesh_name)
            if exported_mesh != None:
                # Important! If an object is matched to a mesh on disk, add to ExportedMeshes.
                # Otherwise the mesh checksum will be computed over and over again.
                self.ExportedMeshes[obj] = exported_mesh
                bpy.data.meshes.remove(mesh)
                self.total_mesh_export_time += time.time() - start_time
                return exported_mesh

            # Make full mesh path.
            mesh_filename = exported_mesh_name + '.igmesh'
            full_mesh_path = efutil.filesystem_path( '/'.join([self.mesh_dir, mesh_filename]) )
            
            #indigo_log('full_mesh_path: %s'%full_mesh_path)

            # pass the full mesh path to write to filesystem if the object is not a proxy
            if hasattr(obj.data, 'indigo_mesh') and not obj.data.indigo_mesh.valid_proxy():
                if os.path.exists(full_mesh_path) and self.skip_existing_meshes:
                    # if skipping mesh write, parse faces to gather used mats
                    used_mat_indices = set()
                    num_smooth = 0
                    for face in mesh.tessfaces:
                        used_mat_indices.add(face.material_index)
                        if face.use_smooth:
                            num_smooth += 1

                    use_shading_normals = num_smooth > 0
                else:
                    # else let the igmesh_writer do its thing
                    (used_mat_indices, use_shading_normals) = igmesh_writer.factory(self.scene, obj, full_mesh_path, mesh, debug=OBJECT_ANALYSIS)
                    self.mesh_uses_shading_normals[full_mesh_path] = use_shading_normals
            else:
                # Assume igmesh has same number of mats as the proxy object
                used_mat_indices = range(len(obj.material_slots))

            # Remove mesh.
            bpy.data.meshes.remove(mesh)
            
            # Export materials used by this mesh
            if len(obj.material_slots) > 0:
                for mi in used_mat_indices:
                    mat = obj.material_slots[mi].material
                    if mat == None or mat.name in self.ExportedMaterials: continue
                    mat_xmls = mat.indigo_material.factory(obj, mat, self.scene)
                    self.ExportedMaterials[mat.name] = mat_xmls

            # .. put the relative path in the mesh element
            filename = '/'.join([self.rel_mesh_dir, mesh_filename])

            #print('MESH FILENAME %s' % filename)

            shading_normals = True
            if full_mesh_path in self.mesh_uses_shading_normals:
                shading_normals = self.mesh_uses_shading_normals[full_mesh_path]

            xml = obj.data.indigo_mesh.build_xml_element(obj, filename, shading_normals, exported_name=exported_mesh_name)

            mesh_definition = (exported_mesh_name, xml)

            self.MeshesOnDisk[exported_mesh_name] = mesh_definition
            self.ExportedMeshes[obj] = mesh_definition
            
            total = time.time() - start_time
            self.total_mesh_export_time += total
            if self.verbose: indigo_log('Mesh Export took: %f s' % total)

            return mesh_definition
Exemplo n.º 20
0
 def build_xml_element(self, scene, matrix_list):
     xml = self.Element('camera')
     
     xml_format = {
         'aperture_radius': [aperture_radius(scene, self)],
         'sensor_width': [scene.camera.data.sensor_width / 1000.0],
         'lens_sensor_dist': [lens_sensor_dist(scene, self)],
         'aspect_ratio': [aspect_ratio(scene, self)],
         'exposure_duration': 'exposure',
     }
     
     if self.whitebalance == 'Custom':
         xml_format['white_point'] = {
             'chromaticity_coordinates': {
                 'x': [self.whitebalanceX],
                 'y': [self.whitebalanceY],
             }
         }
     else:
         xml_format['white_balance'] = 'whitebalance',
     
     ws = get_worldscale(scene)
     
     if(scene.camera.data.type == 'ORTHO'):
         xml_format['camera_type'] = ['orthographic']
         xml_format['sensor_width'] = [scene.camera.data.ortho_scale * ws] # Blender seems to use 'ortho_scale' for the sensor width.
     
     mat = matrix_list[0][1].transposed()
     
     xml_format['pos']        = [ i*ws for i in mat[3][0:3]]
     xml_format['forwards']    = [-i*ws for i in mat[2][0:3]]
     xml_format['up']        = [ i*ws for i in mat[1][0:3]]
     
     if len(matrix_list) > 1:
         # Remove pos, conflicts with keyframes.
         del(xml_format['pos'])
     
         keyframes = exportutil.matrixListToKeyframes(scene, scene.camera, matrix_list)
             
         xml_format['keyframe'] = tuple(keyframes)
     
     if self.autofocus:
         xml_format['autofocus'] = '' # is empty element
         xml_format['focus_distance'] = [10.0]  # any non-zero value will do
     else:
         if scene.camera.data.dof_object is not None:
             xml_format['focus_distance'] = [((scene.camera.location - scene.camera.data.dof_object.location).length*ws)]
         elif scene.camera.data.dof_distance > 0:
             xml_format['focus_distance'] = [scene.camera.data.dof_distance*ws]
         else: #autofocus
             xml_format['autofocus'] = '' # is empty element
             xml_format['focus_distance'] = [10.0]  # any non-zero value will do
     
     if self.ad:
         xml_format.update({
             'aperture_shape': {}
         })
         if self.ad_obstacle != '':
             ad_obstacle = efutil.filesystem_path(self.ad_obstacle)
             if os.path.exists(ad_obstacle):
                 xml_format.update({
                     'obstacle_map': {
                         'path': [efutil.path_relative_to_export(ad_obstacle)]
                     }
                 })
             else:
                 indigo_log('WARNING: Camera Obstacle Map specified, but image path is not valid')
         
         if self.ad_type == 'image':
             ad_image = efutil.filesystem_path(self.ad_image)
             if os.path.exists(ad_image):
                 xml_format['aperture_shape'].update({
                     'image': {
                         'path': [efutil.path_relative_to_export(ad_image)]
                     }
                 })
             else:
                 indigo_log('WARNING: Camera Aperture Diffraction type "Image" selected, but image path is not valid')
         
         elif self.ad_type == 'generated':
             xml_format['aperture_shape'].update({
                 'generated': {
                     'num_blades': [self.ad_blades],
                     'start_angle': [self.ad_angle],
                     'blade_offset': [self.ad_offset],
                     'blade_curvature_radius': [self.ad_curvature]
                 }
             })
         elif self.ad_type == 'circular':
             xml_format['aperture_shape'][self.ad_type] = {}
     
     aspect = aspect_ratio(scene, self)
     if scene.camera.data.shift_x != 0:
         sx = scene.camera.data.shift_x * 0.001*scene.camera.data.sensor_width
         if aspect < 1.0:
             sx /= aspect
         xml_format['lens_shift_right_distance'] = [sx]
         
     if scene.camera.data.shift_y != 0:
         sy = scene.camera.data.shift_y * 0.001*scene.camera.data.sensor_width
         if aspect < 1.0:
             sy /= aspect
         xml_format['lens_shift_up_distance'] = [sy]
     
     self.build_subelements(scene, xml_format, xml)
     
     return xml
Exemplo n.º 21
0
    def render(self, context):
        '''
        Render the scene file, or in our case, export the frame(s)
        and launch an Indigo process.
        '''

        with RENDERENGINE_indigo.render_lock:  # Just render one thing at a time.
            self.renderer = None
            self.message_thread = None
            self.stats_thread = None
            self.framebuffer_thread = None
            self.render_update_timer = None
            self.rendering = False

            # force scene update to current rendering frame
            # Not sure why - Yves
            #context.frame_set(context.frame_current)

            #------------------------------------------------------------------------------
            # Export the Scene

            # Get the frame path.
            frame_path = efutil.filesystem_path(context.render.frame_path())

            # Get the filename for the frame sans extension.
            image_out_path = os.path.splitext(frame_path)[0]

            # Generate the name for the scene file(s).
            if context.indigo_engine.use_output_path == True:
                # Get the output path from the frame path.
                output_path = os.path.dirname(frame_path)

                # Generate the output filename
                output_filename = '%s.%s.%05i.igs' % (
                    efutil.scene_filename(), bpy.path.clean_name(
                        context.name), context.frame_current)
            else:
                # Get export path from the indigo_engine.
                export_path = efutil.filesystem_path(
                    context.indigo_engine.export_path)

                # Get the directory name from the output path.
                output_path = os.path.dirname(export_path)

                # Get the filename from the output path and remove the extension.
                output_filename = os.path.splitext(
                    os.path.basename(export_path))[0]

                # Count contiguous # chars and replace them with the frame number.
                # If the hash count is 0 and we are exporting an animation, append the frame numbers.
                hash_count = util.count_contiguous('#', output_filename)
                if hash_count != 0:
                    output_filename = output_filename.replace(
                        '#' * hash_count,
                        ('%%0%0ii' % hash_count) % context.frame_current)
                elif self.is_animation:
                    output_filename = output_filename + (
                        '%%0%0ii' % 4) % context.frame_current

                # Add .igs extension.
                output_filename += '.igs'

            # The full path of the exported scene file.
            exported_file = '/'.join([output_path, output_filename])

            # Create output_path if it does not exist.
            if not os.path.exists(output_path):
                os.makedirs(output_path)

            # If an animation is rendered, write an indigo queue file (.igq).
            if self.is_animation:
                igq_filename = '%s/%s.%s.igq' % (
                    output_path, efutil.scene_filename(),
                    bpy.path.clean_name(context.name))

                if context.frame_current == context.frame_start:
                    # Start a new igq file.
                    igq_file = open(igq_filename, 'w')
                    igq_file.write(
                        '<?xml version="1.0" encoding="utf-8" standalone="no" ?>\n'
                    )
                    igq_file.write('<render_queue>\n')
                else:
                    # Append to existing igq.
                    igq_file = open(igq_filename, 'a')

                rnd = random.Random()
                rnd.seed(context.frame_current)

                # Write igq item.
                igq_file.write('\t<item>\n')
                igq_file.write('\t\t<scene_path>%s</scene_path>\n' %
                               exported_file)
                igq_file.write('\t\t<halt_time>%d</halt_time>\n' %
                               context.indigo_engine.halttime)
                igq_file.write('\t\t<halt_spp>%d</halt_spp>\n' %
                               context.indigo_engine.haltspp)
                igq_file.write('\t\t<output_path>%s</output_path>\n' %
                               image_out_path)
                igq_file.write('\t\t<seed>%s</seed>\n' %
                               rnd.randint(1, 1000000))
                igq_file.write('\t</item>\n')

                # If this is the last frame, write the closing tag.
                if context.frame_current == context.frame_end:
                    igq_file.write('</render_queue>\n')

                igq_file.close()

                # Calculate the progress by frame with frame range (fr) and frame offset (fo).
                fr = context.frame_end - context.frame_start
                fo = context.frame_current - context.frame_start
                self.update_progress(fo / fr)

            scene_writer = indigo.operators._Impl_OT_indigo(
                directory=output_path,
                filename=output_filename).set_report(self.report)

            # Write the scene file.
            export_result = scene_writer.execute(context)

            # Return if the export didn't finish.
            if not 'FINISHED' in export_result:
                return

            #------------------------------------------------------------------------------
            # Update indigo defaults config file .
            config_updates = {
                'auto_start': context.indigo_engine.auto_start,
                'console_output': context.indigo_engine.console_output
            }

            if context.indigo_engine.use_console:
                indigo_path = getConsolePath(context)
            else:
                indigo_path = getGuiPath(context)

            if os.path.exists(indigo_path):
                config_updates['install_path'] = getInstallPath(context)

            try:
                for k, v in config_updates.items():
                    efutil.write_config_value('indigo', 'defaults', k, v)
            except Exception as err:
                indigo_log('Saving indigo config failed: %s' % err,
                           message_type='ERROR')

            # Make sure that the Indigo we are going to launch is at least as
            # new as the exporter version.
            version_ok = True
            if not context.indigo_engine.skip_version_check:
                iv = getVersion(context)
                for i in range(3):
                    version_ok &= iv[i] >= bl_info['version'][i]

            #------------------------------------------------------------------------------
            # Conditionally Spawn Indigo.
            if context.indigo_engine.auto_start:

                exe_path = efutil.filesystem_path(indigo_path)

                if not os.path.exists(exe_path):
                    print("Failed to find indigo at '" + str(exe_path) + "'")
                    msg = "Failed to find indigo at '" + str(exe_path) + "'."
                    msg + "\n  "
                    msg += "Please make sure you have Indigo installed, and that the path to indigo in the 'Indigo Render Engine Settings' is set correctly."
                    self.report({'ERROR'}, msg)

                #if not version_ok:
                #indigo_log("Unsupported version v%s; Cannot start Indigo with this scene" % ('.'.join(['%s'%i for i in iv])), message_type='ERROR')
                #return

                # if it's an animation, don't execute until final frame
                if self.is_animation and context.frame_current != context.frame_end:
                    return

                # if animation and final frame, launch queue instead of single frame
                if self.is_animation and context.frame_current == context.frame_end:
                    exported_file = igq_filename
                    indigo_args = [exe_path, exported_file]
                else:
                    indigo_args = [
                        exe_path, exported_file, '-o', image_out_path + '.png'
                    ]

                # Set master or working master command line args.
                if context.indigo_engine.network_mode == 'master':
                    indigo_args.extend(['-n', 'm'])
                elif context.indigo_engine.network_mode == 'working_master':
                    indigo_args.extend(['-n', 'wm'])

                # Set port arg if network rendering is enabled.
                if context.indigo_engine.network_mode in [
                        'master', 'working_master'
                ]:
                    indigo_args.extend(
                        ['-p', '%i' % context.indigo_engine.network_port])

                # Set hostname and port arg.
                if context.indigo_engine.network_mode == 'manual':
                    indigo_args.extend([
                        '-h',
                        '%s:%i' % (context.indigo_engine.network_host,
                                   context.indigo_engine.network_port)
                    ])

                # indigo_log("Starting indigo: %s" % indigo_args)

                # If we're starting a console or should wait for the process, listen to the output.
                if context.indigo_engine.use_console or context.indigo_engine.wait_for_process:
                    f_stdout = subprocess.PIPE
                else:
                    f_stdout = None

                # Launch the Indigo process.
                indigo_proc = subprocess.Popen(indigo_args, stdout=f_stdout)
                indigo_pid = indigo_proc.pid
                indigo_log('Started Indigo process, PID: %i' % indigo_pid)

                # Wait for the render to finish if we use the console or should wait for the process.
                if context.indigo_engine.use_console or context.indigo_engine.wait_for_process:
                    while indigo_proc.poll() == None:
                        indigo_proc.communicate()
                        time.sleep(2)

                    indigo_proc.wait()
                    if not indigo_proc.stdout.closed:
                        indigo_proc.communicate()
                    if indigo_proc.returncode == -1:
                        sys.exit(-1)

            else:
                indigo_log("Scene was exported to %s" % exported_file)

            #------------------------------------------------------------------------------
            # Finished
            return
Exemplo n.º 22
0
    def write_mesh(filename, scene, obj, mesh):

        profile = False

        exportDummyUVs = True

        if profile:
            total_start_time = time.time()

        if len(mesh.tessfaces) < 1:
            raise UnexportableObjectException('Object %s has no faces!' %
                                              obj.name)

        if len(mesh.vertices) < 1:
            raise UnexportableObjectException('Object %s has no verts!' %
                                              obj.name)

        render_uvs = [uvt for uvt in mesh.tessface_uv_textures]
        num_uv_sets = len(render_uvs)

        # Open file to write to
        file = open(filename, 'wb')

        # Write magic number
        write_uint32(file, 5456751)

        # Write format version
        write_uint32(file, 3)

        # Write num UV mappings
        if num_uv_sets == 0 and exportDummyUVs:
            write_uint32(file, 1)
        else:
            write_uint32(file, num_uv_sets)

        #total_tris = 0
        '''
        used_mat_indices = set()
        for face in mesh.tessfaces:
            #total_tris += len(face.vertices) - 2
            used_mat_indices.add(face.material_index)
            
            
        #indigo_log('B1') # TEMP
        
        # Get list of used materials

        mats = []
        if len(obj.material_slots) > 0:
            # need to attach all mats up to max used index
            for mi in range(max(used_mat_indices) + 1): #sorted([mi for mi in used_mat_indices]):
                mat = obj.material_slots[mi].material
                if mat == None: continue
                mats.append(mat)
        '''
        #used_mat_indices = rang(obj.material_slots)

        used_mat_indices = set()
        mats = []

        num_mats = len(obj.material_slots)
        for mi in range(num_mats):
            mats.append(obj.material_slots[mi].material)
            used_mat_indices.add(mi)

        if profile:
            indigo_log('used_mat_indices: %s' % str(used_mat_indices))

        if len(mats) == 0:
            # Write num used materials
            write_uint32(file, 1)

            # Write material name
            write_string(file, 'blendigo_clay')
        else:
            # Count number of actual materials.
            count = 0
            for m in mats:
                if m == None: continue
                count += 1

            # Write num used materials
            write_uint32(file, count)

            for m in mats:
                if m == None: continue
                # Write material name
                write_string(file, m.indigo_material.get_name(m))

        # Write num uv set expositions.  Note that in v2, these aren't actually read, so can just write zero.
        write_uint32(file, 0)

        start_time = time.time()

        num_smooth = 0
        for face in mesh.tessfaces:  # for each face
            if face.use_smooth:
                num_smooth += 1

        #indigo_log('num smooth: %i, num flat: %i' % (num_smooth, num_flat))

        vertices = []
        normals = []

        for v in mesh.vertices:
            vertices.append(v.co)

        # If we need shading normals, write them all out
        if num_smooth != 0:
            for v in mesh.vertices:
                normals.append(v.normal)

        # write vertices
        write_list_of_vec3s(file, vertices)

        # write vertex normals
        write_list_of_vec3s(file, normals)

        del vertices
        del normals

        if profile:
            indigo_log('Writing vertices and vertex normals: %0.5f sec' %
                       (time.time() - start_time))
        '''
        # Write UVs
        uv_list = []

        #igo.add_num_uv_pairs(4*len(mesh.tessfaces)*num_uv_sets)
        
        start_time = time.time()

        if num_uv_sets > 0:
            # UVs are interleaved thus -
            # face[0].uv[0].co[0]
            # face[0].uv[1].co[0]
            # ..
            # face[0].uv[*].co[1]
            # ..
            # face[1].uv[*].co[*]
            for face in mesh.tessfaces:
                add_blank_uv4 = len(face.vertices) == 3
                for uv_coord_idx in range(4):
                    for uv_index in range(num_uv_sets):
                        if add_blank_uv4 and uv_coord_idx == 3:
                            uv_list.append(tuple([0,0]))
                            #igo.add_uv_pair_fast(tuple([0,0]))
                        else:
                            uv_list.append(tuple(render_uvs[uv_index].data[face.index].uv[uv_coord_idx]))
                            #igo.add_uv_pair_fast(tuple(render_uvs[uv_index].data[face.index].uv[uv_coord_idx]))
                            
                
        indigo_log('Making UV list time : %0.5f sec' % (time.time() - start_time))
        
        write_list_of_vec2s(file, uv_list)
        '''

        if profile:
            indigo_log('num_uv_sets : %i' % num_uv_sets)
            indigo_log('len(mesh.tessfaces) : %i' % len(mesh.tessfaces))
            #indigo_log('4*len(mesh.tessfaces)*num_uv_sets : %i sec' % (4*len(mesh.tessfaces)*num_uv_sets))
            #indigo_log('8*4*len(mesh.tessfaces)*num_uv_sets : %i sec' % (8*4*len(mesh.tessfaces)*num_uv_sets))

        start_time = time.time()
        uv_start_time = time.time()

        uv_data = []

        if num_uv_sets > 0:
            for uv_index in range(num_uv_sets):  # For each UV set
                layer_uvs = render_uvs[uv_index]
                for face in mesh.tessfaces:  # For each face
                    face_uvs = layer_uvs.data[face.index]
                    if len(face.vertices) == 3:
                        uv_data.extend([
                            face_uvs.uv[0], face_uvs.uv[1], face_uvs.uv[2],
                            (0, 0)
                        ])
                    else:
                        uv_data.extend([
                            face_uvs.uv[0], face_uvs.uv[1], face_uvs.uv[2],
                            face_uvs.uv[3]
                        ])
        elif exportDummyUVs:
            uv_data.extend([(0, 0)])

        if profile:
            indigo_log('    Making UV list time : %0.5f sec' %
                       (time.time() - start_time))
        start_time = time.time()

        # Write UV layout
        write_uint32(file, 1)  # UV_LAYOUT_LAYER_VERTEX = 1;

        # Write UV data
        write_list_of_vec2s(file, uv_data)

        del uv_data  # Free uv_data mem

        if profile:
            indigo_log('    Writing UVs: %0.5f sec' %
                       (time.time() - start_time))
            indigo_log('Total UV time: %0.5f sec' %
                       (time.time() - uv_start_time))

        # Write triangles
        start_time = time.time()

        tri_data = []  # A list of integers
        quad_data = []  # A list of integers

        if num_uv_sets > 0:
            for face in mesh.tessfaces:
                uv_idx = face.index * 4
                fv = face.vertices

                if len(face.vertices) == 3:  # if this is a triangle
                    tri_data.extend([
                        fv[0], fv[1], fv[2], uv_idx, uv_idx + 1, uv_idx + 2,
                        face.material_index
                    ])
                else:  # Else if this is a quad
                    quad_data.extend([
                        fv[0], fv[1], fv[2], fv[3], uv_idx, uv_idx + 1,
                        uv_idx + 2, uv_idx + 3, face.material_index
                    ])
        else:
            for face in mesh.tessfaces:
                fv = face.vertices
                if len(face.vertices) == 3:  # if this is a triangle
                    tri_data.extend(
                        [fv[0], fv[1], fv[2], 0, 0, 0, face.material_index])
                else:  # Else if this is a quad
                    quad_data.extend([
                        fv[0], fv[1], fv[2], fv[3], 0, 0, 0, 0,
                        face.material_index
                    ])

        ####### Write triangles #######
        # Write num triangles

        num_tris = len(
            tri_data
        ) // 7  # NOTE: // is integer division, which we want.  There are 7 uints per triangle.
        write_uint32(file, num_tris)

        tri_array = array.array('i', tri_data)
        tri_array.tofile(file)

        del tri_data  # Free tri data

        if profile:
            indigo_log('Writing triangle time: %0.5f sec' %
                       (time.time() - start_time))

        ####### Write quads #######
        # Write num quads
        num_quads = len(
            quad_data
        ) // 9  # NOTE: // is integer division, which we want.  There are 9 uints per quad.
        write_uint32(file, num_quads)

        quad_array = array.array('i', quad_data)
        quad_array.tofile(file)

        # Close the file we have been writing to.
        file.close()

        use_shading_normals = num_smooth > 0

        if profile:
            total_time = time.time() - total_start_time
            indigo_log('Total mesh writing time: %0.5f sec' % (total_time))

        return (used_mat_indices, use_shading_normals)