Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender-addons.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'render_povray/object_particles.py')
-rwxr-xr-xrender_povray/object_particles.py255
1 files changed, 255 insertions, 0 deletions
diff --git a/render_povray/object_particles.py b/render_povray/object_particles.py
new file mode 100755
index 00000000..2d4f0dcc
--- /dev/null
+++ b/render_povray/object_particles.py
@@ -0,0 +1,255 @@
+# ##### 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
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+"""Get some Blender particle objects translated to POV."""
+
+import bpy
+
+
+def export_hair(file, ob, p_sys, global_matrix, write_matrix):
+ """Get Blender path particles (hair strands) objects translated to POV sphere_sweep unions."""
+ # tstart = time.time()
+ textured_hair = 0
+ if ob.material_slots[p_sys.settings.material - 1].material and ob.active_material is not None:
+ pmaterial = ob.material_slots[p_sys.settings.material - 1].material
+ # XXX Todo: replace by pov_(Particles?)_texture_slot
+ for th in pmaterial.pov_texture_slots:
+ povtex = th.texture # slot.name
+ tex = bpy.data.textures[povtex]
+
+ if th and th.use:
+ if (tex.type == 'IMAGE' and tex.image) or tex.type != 'IMAGE':
+ if th.use_map_color_diffuse:
+ textured_hair = 1
+ if pmaterial.strand.use_blender_units:
+ strand_start = pmaterial.strand.root_size
+ strand_end = pmaterial.strand.tip_size
+ strand_shape = pmaterial.strand.shape
+ else: # Blender unit conversion
+ strand_start = pmaterial.strand.root_size / 200.0
+ strand_end = pmaterial.strand.tip_size / 200.0
+ strand_shape = pmaterial.strand.shape
+ else:
+ pmaterial = "default" # No material assigned in blender, use default one
+ strand_start = 0.01
+ strand_end = 0.01
+ strand_shape = 0.0
+ # Set the number of particles to render count rather than 3d view display
+ # p_sys.set_resolution(scene, ob, 'RENDER') # DEPRECATED
+ # When you render, the entire dependency graph will be
+ # evaluated at render resolution, including the particles.
+ # In the viewport it will be at viewport resolution.
+ # So there is no need fo render engines to use this function anymore,
+ # it's automatic now.
+ steps = p_sys.settings.display_step
+ steps = 2 ** steps # or + 1 # Formerly : len(particle.hair_keys)
+
+ total_number_of_strands = p_sys.settings.count + p_sys.settings.rendered_child_count
+ # hairCounter = 0
+ file.write('#declare HairArray = array[%i] {\n' % total_number_of_strands)
+ for pindex in range(0, total_number_of_strands):
+
+ # 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 p_sys.settings.use_hair_bspline:
+ file.write('b_spline ')
+ file.write(
+ '%i,\n' % (steps + 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' % (steps))
+ # changing world coordinates to object local coordinates by
+ # multiplying with inverted matrix
+ init_coord = ob.matrix_world.inverted() @ (p_sys.co_hair(ob, particle_no=pindex, step=0))
+ if (
+ ob.material_slots[p_sys.settings.material - 1].material
+ and ob.active_material is not None
+ ):
+ pmaterial = ob.material_slots[p_sys.settings.material - 1].material
+ for th in pmaterial.pov_texture_slots:
+ if th and th.use and th.use_map_color_diffuse:
+ povtex = th.texture # slot.name
+ tex = bpy.data.textures[povtex]
+ # treat POV textures as bitmaps
+ if (
+ tex.type == 'IMAGE'
+ and tex.image
+ and th.texture_coords == 'UV'
+ and ob.data.uv_textures is not None
+ ):
+ # or (
+ # tex.pov.tex_pattern_type != 'emulator'
+ # and th.texture_coords == 'UV'
+ # and ob.data.uv_textures is not None
+ # ):
+ image = tex.image
+ image_width = image.size[0]
+ image_height = image.size[1]
+ image_pixels = image.pixels[:]
+ uv_co = p_sys.uv_on_emitter(mod, p_sys.particles[pindex], pindex, 0)
+ x_co = round(uv_co[0] * (image_width - 1))
+ y_co = round(uv_co[1] * (image_height - 1))
+ pixelnumber = (image_width * y_co) + x_co
+ r = image_pixels[pixelnumber * 4]
+ g = image_pixels[pixelnumber * 4 + 1]
+ b = image_pixels[pixelnumber * 4 + 2]
+ a = image_pixels[pixelnumber * 4 + 3]
+ init_color = (r, g, b, a)
+ else:
+ # only overwrite variable for each competing texture for now
+ init_color = tex.evaluate((init_coord[0], init_coord[1], init_coord[2]))
+ for step in range(0, steps):
+ coord = ob.matrix_world.inverted() @ (p_sys.co_hair(ob, particle_no=pindex, step=step))
+ # for controlPoint in particle.hair_keys:
+ if p_sys.settings.clump_factor != 0:
+ hair_strand_diameter = p_sys.settings.clump_factor / 200.0 * random.uniform(0.5, 1)
+ elif step == 0:
+ hair_strand_diameter = strand_start
+ else:
+ hair_strand_diameter += (strand_end - strand_start) / (
+ p_sys.settings.display_step + 1
+ ) # XXX +1 or not? # XXX use strand_shape in formula
+ if step == 0 and p_sys.settings.use_hair_bspline:
+ # Write three times the first point to compensate pov Bezier handling
+ file.write(
+ '<%.6g,%.6g,%.6g>,%.7g,\n'
+ % (coord[0], coord[1], coord[2], abs(hair_strand_diameter))
+ )
+ file.write(
+ '<%.6g,%.6g,%.6g>,%.7g,\n'
+ % (coord[0], coord[1], coord[2], abs(hair_strand_diameter))
+ )
+ # Useless because particle location is the tip, not the root:
+ # file.write(
+ # '<%.6g,%.6g,%.6g>,%.7g'
+ # % (
+ # particle.location[0],
+ # particle.location[1],
+ # particle.location[2],
+ # abs(hair_strand_diameter)
+ # )
+ # )
+ # file.write(',\n')
+ # controlPointCounter += 1
+ # total_number_of_strands += len(p_sys.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' % (coord[0], coord[1], coord[2], abs(hair_strand_diameter))
+ )
+
+ # All coordinates except the last need a following comma.
+
+ if step != steps - 1:
+ file.write(',\n')
+ else:
+ if textured_hair:
+ # Write pigment and alpha (between Pov and Blender,
+ # alpha 0 and 1 are reversed)
+ file.write(
+ '\npigment{ color srgbf < %.3g, %.3g, %.3g, %.3g> }\n'
+ % (init_color[0], init_color[1], init_color[2], 1.0 - init_color[3])
+ )
+ # 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 pindex != total_number_of_strands:
+ file.write(',\n')
+ else:
+ file.write('\n')
+
+ # End the array declaration.
+
+ file.write('}\n')
+ file.write('\n')
+
+ if not textured_hair:
+ # Pick up the hair material diffuse color and create a default POV-Ray hair texture.
+
+ file.write('#ifndef (HairTexture)\n')
+ file.write(' #declare HairTexture = texture {\n')
+ file.write(
+ ' pigment {srgbt <%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 hairstrands (or a subset of them).
+ # By default use every hairstrand, commented line is for hand tweaking test renders.
+ file.write('//Increasing HairStep divides the amount of hair for test renders.\n')
+ file.write('#ifndef(HairStep) #declare HairStep = 1; #end\n')
+ file.write('union{\n')
+ file.write(' #local I = 0;\n')
+ file.write(' #while (I < %i)\n' % total_number_of_strands)
+ file.write(' object {HairArray[I]')
+ if not textured_hair:
+ file.write(' texture{HairTexture}\n')
+ else:
+ file.write('\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 {cylindrical\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')
+
+ write_matrix(global_matrix @ ob.matrix_world)
+
+ file.write('}')
+ print('Totals hairstrands written: %i' % total_number_of_strands)
+ print('Number of tufts (particle systems)', len(ob.particle_systems))
+
+ # Set back the displayed number of particles to preview count
+ # p_sys.set_resolution(scene, ob, 'PREVIEW') #DEPRECATED
+ # When you render, the entire dependency graph will be
+ # evaluated at render resolution, including the particles.
+ # In the viewport it will be at viewport resolution.
+ # So there is no need fo render engines to use this function anymore,
+ # it's automatic now.