diff --git a/render_povray/__init__.py b/render_povray/__init__.py
index b4843919b859f67960307c4c6c0cb0f90b5dc422..1b7299ecd94a012bc14320d7c4c5b0e3de3e54a2 100644
--- a/render_povray/__init__.py
+++ b/render_povray/__init__.py
@@ -45,6 +45,7 @@ else:
     from . import ui
     from . import render
     from . import update_files
+    
 
 
 ###############################################################################
diff --git a/render_povray/render.py b/render_povray/render.py
index a009c9d5887947570cad0da77ce4d27972d4e969..8b89590749688b1a7bd131d050663539588e2c1a 100644
--- a/render_povray/render.py
+++ b/render_povray/render.py
@@ -1,4 +1,4 @@
- # ***** BEGIN GPL LICENSE BLOCK *****
+ # ***** BEGIN GPL LICENSE BLOCK *****
  #
  # This program is free software; you can redistribute it and/or
  # modify it under the terms of the GNU General Public License
@@ -751,7 +751,7 @@ def write_pov(filename, scene=None, info_callback=None):
 #                for ms in ob.material_slots:
 #                    if ms.material != None and ms.link == 'OBJECT':
 #                        # If there is at least one material slot linked to the object
-#                        # and not the data (mesh), always create a new, “private” data instance.
+#                        # and not the data (mesh), always create a new, �private� data instance.
 #                        return True
 #            return False
         # For objects using local material(s) only!
@@ -790,7 +790,7 @@ def write_pov(filename, scene=None, info_callback=None):
         def store(scene, ob, name, dataname, matrix):
             # The Object needs to be written at least once but if its data is
             # already in data_ref this has already been done.
-            # This func returns the “povray” name of the data, or None
+            # This func returns the �povray� name of the data, or None
             # if no writing is needed.
             if ob.is_modified(scene, 'RENDER'):
                 # Data modified.
@@ -816,9 +816,142 @@ def write_pov(filename, scene=None, info_callback=None):
             ob_num += 1
 
             # XXX I moved all those checks here, as there is no need to compute names
-            #     for object we won’t export here!
+            #     for object we won�t export here!
             if ob.type in {'LAMP', 'CAMERA', 'EMPTY', 'META', 'ARMATURE', 'LATTICE'}:
                 continue
+                   
+            # Export Hair
+
+            if hasattr(ob, 'particle_systems') != False:
+                for pSys in ob.particle_systems:
+                    if not pSys.settings.use_render_emitter:
+                        continue #don't render mesh
+                    for mod in [m for m in ob.modifiers if (m is not None) and (m.type == 'PARTICLE_SYSTEM')]:
+                        if (pSys.settings.render_type == 'PATH') and mod.show_render and (pSys.name == mod.particle_system.name):
+                            tstart = time.time()
+                            if ob.active_material is not None:
+                                pmaterial = ob.active_material
+                                if pmaterial.strand.use_blender_units:
+                                    strandStart = pmaterial.strand.root_size
+                                    strandEnd = pmaterial.strand.tip_size
+                                    strandShape = pmaterial.strand.shape
+                                else:  # Blender unit conversion
+                                    strandStart = pmaterial.strand.root_size / 200
+                                    strandEnd = pmaterial.strand.tip_size / 200
+                                    strandShape = pmaterial.strand.shape
+                            else:
+                                pmaterial = "default"  # No material assigned in blender, use default one
+                                strandStart = 0.01
+                                strandEnd = 0.01
+                                strandShape = 0.0
+                                
+                            totalNumberOfHairs = len(pSys.particles)
+                            hairCounter = 0
+                            file.write('#declare HairArray = array[%i] {\n' % totalNumberOfHairs)
+                            for particle in pSys.particles:
+                                if particle.is_exist and particle.is_visible:
+                                    hairCounter += 1
+                                    controlPointCounter = 0
+                                    # Each hair is represented as a separate sphere_sweep in POV-Ray.
+                                    
+                                    file.write('sphere_sweep{')
+                                    if pSys.settings.use_hair_bspline:
+                                        file.write('b_spline ')
+                                        file.write('%i,\n' % (len(particle.hair_keys) + 2))  # +2 because the first point needs tripling to be more than a handle in POV
+
+                                    else:
+                                        file.write('linear_spline ')
+                                        file.write('%i,\n' % (len(particle.hair_keys)))
+                                    for controlPoint in particle.hair_keys:
+                                        if pSys.settings.clump_factor != 0:
+                                            hDiameter = pSys.settings.clump_factor #* random.uniform(0.5, 1)
+                                        elif controlPointCounter == 0:
+                                            hDiameter = strandStart
+                                        else:
+                                            hDiameter += (strandEnd-strandStart)/(len(particle.hair_keys)+1) #XXX +1 or not?
+                                        if controlPointCounter == 0 and pSys.settings.use_hair_bspline:
+                                            # Write three times the first point to compensate pov Bezier handling
+                                            file.write('<%.6g,%.6g,%.6g>,%.7g,\n' % (controlPoint.co[0], controlPoint.co[1], controlPoint.co[2], abs(hDiameter)))
+                                            file.write('<%.6g,%.6g,%.6g>,%.7g,\n' % (controlPoint.co[0], controlPoint.co[1], controlPoint.co[2], abs(hDiameter)))                                          
+											#file.write('<%.6g,%.6g,%.6g>,%.7g' % (particle.location[0], particle.location[1], particle.location[2], abs(hDiameter))) # Useless because particle location is the tip, not the root.
+                                            #file.write(',\n')
+                                        controlPointCounter += 1
+                                        #totalNumberOfHairs += len(pSys.particles)# len(particle.hair_keys)
+                                             
+                                      # Each control point is written out, along with the radius of the
+                                      # hair at that point.
+                                        file.write('<%.6g,%.6g,%.6g>,%.7g' % (controlPoint.co[0], controlPoint.co[1], controlPoint.co[2], abs(hDiameter)))
+
+                                      # All coordinates except the last need a following comma.
+
+                                        if controlPointCounter != len(particle.hair_keys):
+                                            file.write(',\n')
+                                        else:
+                                            # End the sphere_sweep declaration for this hair
+                                            file.write('}\n')
+                                        
+                                      # All but the final sphere_sweep (each array element) needs a terminating comma.
+
+                                    if hairCounter != totalNumberOfHairs:
+                                        file.write(',\n')
+                                    else:
+                                        file.write('\n')
+
+                            # End the array declaration.
+
+                            file.write('}\n')
+                            file.write('\n')
+
+                            # Pick up the hair color and create a default POV-Ray hair texture.
+
+                            file.write('#ifndef (HairTexture)\n')
+                            file.write('  #declare HairTexture = texture {\n')
+                            file.write('    pigment {rgbt <%s,%s,%s,%s>}\n' % (pmaterial.diffuse_color[0], pmaterial.diffuse_color[1], pmaterial.diffuse_color[2], (pmaterial.strand.width_fade + 0.05)))
+                            file.write('  }\n')
+                            file.write('#end\n')
+                            file.write('\n')
+
+                            # Dynamically create a union of the hairs (or a subset of the hairs).
+                            # By default use every 25th hair, which is usually ok for test renders.
+
+                            file.write('#ifndef(HairStep) #declare HairStep = %d; #end\n' % ((totalNumberOfHairs/(totalNumberOfHairs * pSys.settings.draw_percentage / 100))))
+                            file.write('union{\n')
+                            file.write('  #local I = 0;\n')
+                            file.write('  #while (I < %i)\n' % totalNumberOfHairs)
+                            file.write('    object {HairArray[I] texture{HairTexture}\n')
+                            
+                            # Translucency of the hair:
+                            file.write('        hollow\n')
+                            file.write('        double_illuminate\n')
+                            file.write('        interior {\n')
+                            file.write('            ior 1.45\n')
+                            file.write('            media {\n')
+                            file.write('                scattering { 1, 10*<0.73, 0.35, 0.15> /*extinction 0*/ }\n')
+                            file.write('                absorption 10/<0.83, 0.75, 0.15>\n')
+                            file.write('                samples 1\n')
+                            file.write('                method 2\n')
+                            file.write('                density {\n')
+                            file.write('                    color_map {\n')
+                            file.write('                        [0.0 rgb <0.83, 0.45, 0.35>]\n')
+                            file.write('                        [0.5 rgb <0.8, 0.8, 0.4>]\n')
+                            file.write('                        [1.0 rgb <1,1,1>]\n')
+                            file.write('                    }\n')
+                            file.write('                }\n')
+                            file.write('            }\n')
+                            file.write('        }\n')
+                            file.write('    }\n')
+                            
+                            file.write('    #local I = I + HairStep;\n')
+                            file.write('  #end\n')
+                            
+                            writeMatrix(global_matrix * ob.matrix_world)
+
+                            
+                            file.write('}')
+                            print('Totals hairstrands written: %i' % totalNumberOfHairs)
+                            print('Number of tufts (particle systems)', len(ob.particle_systems))
+
+                                
 
             try:
                 me = ob.to_mesh(scene, True, 'RENDER')
@@ -829,14 +962,14 @@ def write_pov(filename, scene=None, info_callback=None):
             importance = ob.pov.importance_value
             me_materials = me.materials
             me_faces = me.tessfaces[:]
-
+            
             if not me or not me_faces:
                 continue
 
 #############################################
             # Generating a name for object just like materials to be able to use it
             # (baking for now or anything else).
-            # XXX I don’t understand that – if we are here, sel if a non-empty iterable,
+            # XXX I don�t understand that ��if we are here, sel if a non-empty iterable,
             #     so this condition is always True, IMO -- mont29
             if sel:
                 name_orig = "OB" + ob.name
diff --git a/render_povray/ui.py b/render_povray/ui.py
index 0fa91a2b2ae9b90a68d5eefe680c9d48698974b3..0af5253ee392f397349506991c158964ff72f6c4 100644
--- a/render_povray/ui.py
+++ b/render_povray/ui.py
@@ -83,6 +83,15 @@ for member in dir(properties_data_lamp):
         pass
 del properties_data_lamp
 
+from bl_ui import properties_particle as properties_particle
+for member in dir(properties_particle):  # add all "particle" panels from blender
+    subclass = getattr(properties_particle, member)
+    try:
+        subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
+    except:
+        pass
+del properties_particle
+
 
 class RenderButtonsPanel():
     bl_space_type = 'PROPERTIES'