Newer
Older
Maurice Raybaud
committed
if ob.pov.curveshape in {'prism'}:
tabWrite("rotate <90,0,0>\n")
tabWrite("scale y*-1\n")
Maurice Raybaud
committed
tabWrite("}\n")
#################################################################
"""write all POV blob primitives and Blender Metas to exported file """
if comments and len(metas) >= 1:
file.write("//--Blob objects--\n\n")
# Get groups of metaballs by blender name prefix.
meta_group = {}
meta_elems = {}
Maurice Raybaud
committed
prefix = ob.name.split(".")[0]
if not prefix in meta_group:
meta_group[prefix] = ob # .data.threshold
elems = [
(elem, ob)
for elem in ob.data.elements
if elem.type
in {'BALL', 'ELLIPSOID', 'CAPSULE', 'CUBE', 'PLANE'}
]
if prefix in meta_elems:
meta_elems[prefix].extend(elems)
Maurice Raybaud
committed
else:
Maurice Raybaud
committed
# empty metaball
Maurice Raybaud
committed
tabWrite("\n//dummy sphere to represent empty meta location\n")
tabWrite(
"sphere {<%.6g, %.6g, %.6g>,0 pigment{rgbt 1} no_image no_reflection no_radiosity photons{pass_through collect off} hollow}\n\n"
% (ob.location.x, ob.location.y, ob.location.z)
) # ob.name > povdataname)
Maurice Raybaud
committed
for mg, ob in meta_group.items():
if len(meta_elems[mg]) != 0:
tabWrite(
"blob{threshold %.4g // %s \n"
% (ob.data.threshold, mg)
)
Maurice Raybaud
committed
for elems in meta_elems[mg]:
elem = elems[0]
loc = elem.co
stiffness = elem.stiffness
if elem.use_negative:
stiffness = -stiffness
Maurice Raybaud
committed
if elem.type == 'BALL':
tabWrite(
"sphere { <%.6g, %.6g, %.6g>, %.4g, %.4g "
% (
loc.x,
loc.y,
loc.z,
elem.radius,
stiffness,
)
)
writeMatrix(
global_matrix @ elems[1].matrix_world
)
Maurice Raybaud
committed
elif elem.type == 'ELLIPSOID':
tabWrite(
"sphere{ <%.6g, %.6g, %.6g>,%.4g,%.4g "
% (
loc.x / elem.size_x,
loc.y / elem.size_y,
loc.z / elem.size_z,
elem.radius,
stiffness,
)
)
tabWrite(
"scale <%.6g, %.6g, %.6g>"
% (elem.size_x, elem.size_y, elem.size_z)
)
writeMatrix(
global_matrix @ elems[1].matrix_world
)
elif elem.type == 'CAPSULE':
tabWrite(
"cylinder{ <%.6g, %.6g, %.6g>,<%.6g, %.6g, %.6g>,%.4g,%.4g "
% (
(loc.x - elem.size_x),
(loc.y),
(loc.z),
(loc.x + elem.size_x),
(loc.y),
(loc.z),
elem.radius,
stiffness,
)
)
# tabWrite("scale <%.6g, %.6g, %.6g>" % (elem.size_x, elem.size_y, elem.size_z))
writeMatrix(
global_matrix @ elems[1].matrix_world
)
Maurice Raybaud
committed
tabWrite("}\n")
elif elem.type == 'CUBE':
tabWrite(
"cylinder { -x*8, +x*8,%.4g,%.4g translate<%.6g,%.6g,%.6g> scale <1/4,1,1> scale <%.6g, %.6g, %.6g>\n"
% (
elem.radius * 2.0,
stiffness / 4.0,
loc.x,
loc.y,
loc.z,
elem.size_x,
elem.size_y,
elem.size_z,
)
)
writeMatrix(
global_matrix @ elems[1].matrix_world
)
Maurice Raybaud
committed
tabWrite("}\n")
tabWrite(
"cylinder { -y*8, +y*8,%.4g,%.4g translate<%.6g,%.6g,%.6g> scale <1,1/4,1> scale <%.6g, %.6g, %.6g>\n"
% (
elem.radius * 2.0,
stiffness / 4.0,
loc.x,
loc.y,
loc.z,
elem.size_x,
elem.size_y,
elem.size_z,
)
)
writeMatrix(
global_matrix @ elems[1].matrix_world
)
tabWrite(
"cylinder { -z*8, +z*8,%.4g,%.4g translate<%.6g,%.6g,%.6g> scale <1,1,1/4> scale <%.6g, %.6g, %.6g>\n"
% (
elem.radius * 2.0,
stiffness / 4.0,
loc.x,
loc.y,
loc.z,
elem.size_x,
elem.size_y,
elem.size_z,
)
)
writeMatrix(
global_matrix @ elems[1].matrix_world
)
Maurice Raybaud
committed
tabWrite("}\n")
Maurice Raybaud
committed
elif elem.type == 'PLANE':
tabWrite(
"cylinder { -x*8, +x*8,%.4g,%.4g translate<%.6g,%.6g,%.6g> scale <1/4,1,1> scale <%.6g, %.6g, %.6g>\n"
% (
elem.radius * 2.0,
stiffness / 4.0,
loc.x,
loc.y,
loc.z,
elem.size_x,
elem.size_y,
elem.size_z,
)
)
writeMatrix(
global_matrix @ elems[1].matrix_world
)
Maurice Raybaud
committed
tabWrite("}\n")
tabWrite(
"cylinder { -y*8, +y*8,%.4g,%.4g translate<%.6g,%.6g,%.6g> scale <1,1/4,1> scale <%.6g, %.6g, %.6g>\n"
% (
elem.radius * 2.0,
stiffness / 4.0,
loc.x,
loc.y,
loc.z,
elem.size_x,
elem.size_y,
elem.size_z,
)
)
writeMatrix(
global_matrix @ elems[1].matrix_world
)
Maurice Raybaud
committed
Maurice Raybaud
committed
try:
material = elems[1].data.materials[
0
] # lame! - blender cant do enything else.
Maurice Raybaud
committed
except:
material = None
if material:
diffuse_color = material.diffuse_color
trans = 1.0 - material.pov.alpha
if (
material.use_transparency
and material.transparency_method == 'RAYTRACE'
):
povFilter = (
material.pov_raytrace_transparency.filter
* (1.0 - material.alpha)
)
trans = (1.0 - material.pov.alpha) - povFilter
Maurice Raybaud
committed
else:
povFilter = 0.0
material_finish = materialNames[material.name]
tabWrite(
"pigment {srgbft<%.3g, %.3g, %.3g, %.3g, %.3g>} \n"
% (
diffuse_color[0],
diffuse_color[1],
diffuse_color[2],
povFilter,
trans,
)
)
tabWrite(
"finish{%s} " % safety(material_finish, Level=2)
)
Maurice Raybaud
committed
else:
tabWrite(
"pigment{srgb 1} finish{%s} "
% (safety(DEF_MAT_NAME, Level=2))
)
Maurice Raybaud
committed
writeObjectMaterial(material, ob)
# writeObjectMaterial(material, elems[1])
tabWrite(
"radiosity{importance %3g}\n"
% ob.pov.importance_value
)
Maurice Raybaud
committed
'''
# important because no elements will break parsing.
elements = [elem for elem in meta.elements if elem.type in {'BALL', 'ELLIPSOID'}]
tabWrite("blob {\n")
tabWrite("threshold %.4g\n" % meta.threshold)
Bastien Montagne
committed
importance = ob.pov.importance_value
material = meta.materials[0] # lame! - blender cant do enything else.
except:
material = None
for elem in elements:
loc = elem.co
stiffness = elem.stiffness
if elem.use_negative:
stiffness = - stiffness
if elem.type == 'BALL':
tabWrite("sphere { <%.6g, %.6g, %.6g>, %.4g, %.4g }\n" %
Bastien Montagne
committed
(loc.x, loc.y, loc.z, elem.radius, stiffness))
# After this wecould do something simple like...
# "pigment {Blue} }"
# except we'll write the color
elif elem.type == 'ELLIPSOID':
# location is modified by scale
tabWrite("sphere { <%.6g, %.6g, %.6g>, %.4g, %.4g }\n" %
(loc.x / elem.size_x,
loc.y / elem.size_y,
loc.z / elem.size_z,
Bastien Montagne
committed
elem.radius, stiffness))
tabWrite("scale <%.6g, %.6g, %.6g> \n" %
Bastien Montagne
committed
(elem.size_x, elem.size_y, elem.size_z))
if material:
diffuse_color = material.diffuse_color
trans = 1.0 - material.pov.alpha
if material.use_transparency and material.transparency_method == 'RAYTRACE':
povFilter = material.pov_raytrace_transparency.filter * (1.0 - material.alpha)
trans = (1.0 - material.pov.alpha) - povFilter
material_finish = materialNames[material.name]
Maurice Raybaud
committed
tabWrite("pigment {srgbft<%.3g, %.3g, %.3g, %.3g, %.3g>} \n" %
Bastien Montagne
committed
(diffuse_color[0], diffuse_color[1], diffuse_color[2],
povFilter, trans))
tabWrite("finish {%s}\n" % safety(material_finish, Level=2))
Maurice Raybaud
committed
tabWrite("pigment {srgb 1} \n")
Bastien Montagne
committed
# Write the finish last.
tabWrite("finish {%s}\n" % (safety(DEF_MAT_NAME, Level=2)))
Maurice Raybaud
committed
writeObjectMaterial(material, elems[1])
writeMatrix(global_matrix @ ob.matrix_world)
Maurice Raybaud
committed
# Importance for radiosity sampling added here
tabWrite("radiosity { \n")
# importance > ob.pov.importance_value
tabWrite("importance %3g \n" % importance)
tabWrite("}\n")
tabWrite("}\n") # End of Metaball block
if comments and len(metas) >= 1:
file.write("\n")
Maurice Raybaud
committed
'''
DEF_OBJ_NAME = "Default"
def exportMeshes(scene, sel, csg):
"""write all meshes as POV mesh2{} syntax to exported file """
# obmatslist = []
# def hasUniqueMaterial():
# # Grab materials attached to object instances ...
# if hasattr(ob, 'material_slots'):
# for ms in ob.material_slots:
# if ms.material is not None and ms.link == 'OBJECT':
# if ms.material in obmatslist:
# return False
# else:
# obmatslist.append(ms.material)
# return True
# def hasObjectMaterial(ob):
# # Grab materials attached to object instances ...
# if hasattr(ob, 'material_slots'):
# for ms in ob.material_slots:
# if ms.material is not 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.
# return True
# return False
Bastien Montagne
committed
# For objects using local material(s) only!
# This is a mapping between a tuple (dataname, materialnames, ...), and the POV dataname.
Bastien Montagne
committed
# As only objects using:
# * The same data.
# * EXACTLY the same materials, in EXACTLY the same sockets.
# ... can share a same instance in POV export.
Bastien Montagne
committed
obmats2data = {}
Bastien Montagne
committed
def checkObjectMaterials(ob, name, dataname):
if hasattr(ob, 'material_slots'):
has_local_mats = False
key = [dataname]
for ms in ob.material_slots:
Bastien Montagne
committed
key.append(ms.material.name)
if ms.link == 'OBJECT' and not has_local_mats:
has_local_mats = True
else:
# Even if the slot is empty, it is important to grab it...
Bastien Montagne
committed
key.append("")
if has_local_mats:
# If this object uses local material(s), lets find if another object
# using the same data and exactly the same list of materials
# (in the same slots) has already been processed...
Bastien Montagne
committed
# Note that here also, we use object name as new, unique dataname for Pov.
key = tuple(key) # Lists are not hashable...
Bastien Montagne
committed
if key not in obmats2data:
obmats2data[key] = name
return obmats2data[key]
return None
data_ref = {}
Bastien Montagne
committed
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.
Bastien Montagne
committed
# This func returns the "povray" name of the data, or None
Bastien Montagne
committed
# if no writing is needed.
if ob.is_modified(scene, 'RENDER'):
# Data modified.
# Create unique entry in data_ref by using object name
# (always unique in Blender) as data name.
data_ref[name] = [(name, MatrixAsPovString(matrix))]
return name
# Here, we replace dataname by the value returned by checkObjectMaterials, only if
# it is not evaluated to False (i.e. only if the object uses some local material(s)).
dataname = checkObjectMaterials(ob, name, dataname) or dataname
if dataname in data_ref:
# Data already known, just add the object instance.
data_ref[dataname].append((name, MatrixAsPovString(matrix)))
# No need to write data
return None
else:
# Data not yet processed, create a new entry in data_ref.
data_ref[dataname] = [(name, MatrixAsPovString(matrix))]
return dataname
# if LuxManager.CurrentScene.name == 'preview':
# return 1, 1, 1, 1.0
# else:
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
flowtype = -1
smoke_obj = bpy.data.objects[smoke_obj_name]
domain = None
# Search smoke domain target for smoke modifiers
for mod in smoke_obj.modifiers:
if mod.name == 'Smoke':
if mod.smoke_type == 'FLOW':
if mod.flow_settings.smoke_flow_type == 'BOTH':
flowtype = 2
else:
if mod.flow_settings.smoke_flow_type == 'SMOKE':
flowtype = 0
else:
if mod.flow_settings.smoke_flow_type == 'FIRE':
flowtype = 1
if mod.smoke_type == 'DOMAIN':
domain = smoke_obj
smoke_modifier = mod
eps = 0.000001
if domain is not None:
# if bpy.app.version[0] >= 2 and bpy.app.version[1] >= 71:
# Blender version 2.71 supports direct access to smoke data structure
set = mod.domain_settings
channeldata = []
for v in set.density_grid:
channeldata.append(v.real)
print(v.real)
## Usage en voxel texture:
# channeldata = []
# if channel == 'density':
# for v in set.density_grid:
# channeldata.append(v.real)
# for v in set.flame_grid:
# channeldata.append(v.real)
resolution = set.resolution_max
big_res = []
big_res.append(set.domain_resolution[0])
big_res.append(set.domain_resolution[1])
big_res.append(set.domain_resolution[2])
if set.use_high_resolution:
big_res[0] = big_res[0] * (set.amplify + 1)
big_res[1] = big_res[1] * (set.amplify + 1)
big_res[2] = big_res[2] * (set.amplify + 1)
# else:
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
# p = []
##gather smoke domain settings
# BBox = domain.bound_box
# p.append([BBox[0][0], BBox[0][1], BBox[0][2]])
# p.append([BBox[6][0], BBox[6][1], BBox[6][2]])
# set = mod.domain_settings
# resolution = set.resolution_max
# smokecache = set.point_cache
# ret = read_cache(smokecache, set.use_high_resolution, set.amplify + 1, flowtype)
# res_x = ret[0]
# res_y = ret[1]
# res_z = ret[2]
# density = ret[3]
# fire = ret[4]
# if res_x * res_y * res_z > 0:
##new cache format
# big_res = []
# big_res.append(res_x)
# big_res.append(res_y)
# big_res.append(res_z)
# else:
# max = domain.dimensions[0]
# if (max - domain.dimensions[1]) < -eps:
# max = domain.dimensions[1]
# if (max - domain.dimensions[2]) < -eps:
# max = domain.dimensions[2]
# big_res = [int(round(resolution * domain.dimensions[0] / max, 0)),
# int(round(resolution * domain.dimensions[1] / max, 0)),
# int(round(resolution * domain.dimensions[2] / max, 0))]
# if set.use_high_resolution:
# big_res = [big_res[0] * (set.amplify + 1), big_res[1] * (set.amplify + 1),
# big_res[2] * (set.amplify + 1)]
# if channel == 'density':
# channeldata = density
# if channel == 'fire':
# channeldata = fire
# sc_fr = '%s/%s/%s/%05d' % (efutil.export_path, efutil.scene_filename(), bpy.context.scene.name, bpy.context.scene.frame_current)
# if not os.path.exists( sc_fr ):
# os.makedirs(sc_fr)
#
# smoke_filename = '%s.smoke' % bpy.path.clean_name(domain.name)
# smoke_path = '/'.join([sc_fr, smoke_filename])
#
# with open(smoke_path, 'wb') as smoke_file:
# # Binary densitygrid file format
# #
# # File header
# smoke_file.write(b'SMOKE') #magic number
# smoke_file.write(struct.pack('<I', big_res[0]))
# smoke_file.write(struct.pack('<I', big_res[1]))
# smoke_file.write(struct.pack('<I', big_res[2]))
# Density data
# smoke_file.write(struct.pack('<%df'%len(channeldata), *channeldata))
#
# LuxLog('Binary SMOKE file written: %s' % (smoke_path))
# return big_res[0], big_res[1], big_res[2], channeldata
mydf3 = df3.df3(big_res[0], big_res[1], big_res[2])
sim_sizeX, sim_sizeY, sim_sizeZ = mydf3.size()
for x in range(sim_sizeX):
for y in range(sim_sizeY):
for z in range(sim_sizeZ):
mydf3.set(
x,
y,
z,
channeldata[
((z * sim_sizeY + y) * sim_sizeX + x)
],
)
mydf3.exportDF3(smokePath)
print('Binary smoke.df3 file written in preview directory')
if comments:
file.write("\n//--Smoke--\n\n")
# Note: We start with a default unit cube.
# This is mandatory to read correctly df3 data - otherwise we could just directly use bbox
# coordinates from the start, and avoid scale/translate operations at the end...
file.write("box{<0,0,0>, <1,1,1>\n")
file.write(" pigment{ rgbt 1 }\n")
file.write(" hollow\n")
file.write(" interior{ //---------------------\n")
file.write(" media{ method 3\n")
file.write(
" emission <1,1,1>*1\n"
) # 0>1 for dark smoke to white vapour
file.write(" <1,1,1>*0.1\n")
file.write(
" density{density_file df3 \"%s\"\n"
% (smokePath)
)
file.write(" color_map {\n")
file.write(" [0.00 rgb 0]\n")
file.write(" [0.05 rgb 0]\n")
file.write(" [0.20 rgb 0.2]\n")
file.write(" [0.30 rgb 0.6]\n")
file.write(" [0.40 rgb 1]\n")
file.write(" [1.00 rgb 1]\n")
file.write(" } // end color_map\n")
file.write(" } // end of density\n")
file.write(
" samples %i // higher = more precise\n"
% resolution
)
file.write(
" } // end of media --------------------------\n"
)
# START OF TRANSFORMATIONS
# Size to consider here are bbox dimensions (i.e. still in object space, *before* applying
# loc/rot/scale and other transformations (like parent stuff), aka matrix_world).
bbox = smoke_obj.bound_box
dim = [
abs(bbox[6][0] - bbox[0][0]),
abs(bbox[6][1] - bbox[0][1]),
abs(bbox[6][2] - bbox[0][2]),
]
# We scale our cube to get its final size and shapes but still in *object* space (same as Blender's bbox).
file.write("scale<%.6g,%.6g,%.6g>\n" % (dim[0], dim[1], dim[2]))
# We offset our cube such that (0,0,0) coordinate matches Blender's object center.
file.write(
"translate<%.6g,%.6g,%.6g>\n"
% (bbox[0][0], bbox[0][1], bbox[0][2])
)
# We apply object's transformations to get final loc/rot/size in world space!
# Note: we could combine the two previous transformations with this matrix directly...
writeMatrix(global_matrix @ smoke_obj.matrix_world)
# END OF TRANSFORMATIONS
# file.write(" interpolate 1\n")
# file.write(" frequency 0\n")
# file.write(" }\n")
# file.write("}\n")
Bastien Montagne
committed
ob_num = 0
# subtract original from the count of their instances as were not counted before 2.8
if not (ob.is_instancer and ob.original != ob):
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!
if ob.type in {
'LIGHT',
'CAMERA', #'EMPTY', #empties can bear dupligroups
'META',
'ARMATURE',
'LATTICE',
}:
for mod in ob.modifiers:
if mod and hasattr(mod, 'smoke_type'):
smokeFlag = True
if mod.smoke_type == 'DOMAIN':
break # don't render domain mesh or flow emitter mesh, skip to next object.
if not smokeFlag:
# Export Hair
renderEmitter = True
if hasattr(ob, 'particle_systems'):
renderEmitter = False
if ob.show_instancer_for_render:
for pSys in ob.particle_systems:
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)
):
texturedHair = 0
if (
ob.material_slots[
pSys.settings.material - 1
].material
and ob.active_material is not None
):
pmaterial = ob.material_slots[
pSys.settings.material - 1
].material
for th in pmaterial.texture_slots:
if th and th.use:
if (
(
th.texture.type
== 'IMAGE'
and th.texture.image
)
or th.texture.type
!= 'IMAGE'
):
if th.use_map_color_diffuse:
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.0
)
strandEnd = (
pmaterial.strand.tip_size
/ 200.0
)
strandShape = pmaterial.strand.shape
else:
pmaterial = (
"default"
) # No material assigned in blender, use default one
strandStart = 0.01
strandEnd = 0.01
strandShape = 0.0
# Set the number of particles to render count rather than 3d view display
# pSys.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,
steps = pSys.settings.display_step
steps = (
3 ** steps
) # or (power of 2 rather than 3) + 1 # Formerly : len(particle.hair_keys)
totalNumberOfHairs = (
pSys.settings.count
+ pSys.settings.rendered_child_count
)
# hairCounter = 0
file.write(
'#declare HairArray = array[%i] {\n'
% totalNumberOfHairs
)
for pindex in range(0, totalNumberOfHairs):
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
# 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' % (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
initCo = ob.matrix_world.inverted() @ (
pSys.co_hair(
ob, particle_no=pindex, step=0
)
)
if (
ob.material_slots[
pSys.settings.material - 1
].material
and ob.active_material is not None
):
pmaterial = ob.material_slots[
pSys.settings.material - 1
].material
for th in pmaterial.texture_slots:
if (
th
and th.use
and th.use_map_color_diffuse
):
# treat POV textures as bitmaps
if (
th.texture.type
== 'IMAGE'
and th.texture.image
and th.texture_coords
== 'UV'
and ob.data.uv_textures
is not None
): # or (th.texture.pov.tex_pattern_type != 'emulator' and th.texture_coords == 'UV' and ob.data.uv_textures is not None):
image = th.texture.image
image_width = image.size[
0
]
image_height = image.size[
1
]
image_pixels = image.pixels[
:
]
uv_co = pSys.uv_on_emitter(
mod,
pSys.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
]
initColor = (r, g, b, a)
else:
# only overwrite variable for each competing texture for now
initColor = th.texture.evaluate(
(
initCo[0],
initCo[1],
initCo[2],
)
)
for step in range(0, steps):
co = ob.matrix_world.inverted() @ (
pSys.co_hair(
ob,
particle_no=pindex,
step=step,
)
)
# for controlPoint in particle.hair_keys:
if pSys.settings.clump_factor != 0:
hDiameter = (
pSys.settings.clump_factor
/ 200.0
* random.uniform(0.5, 1)
)
elif step == 0:
hDiameter = strandStart
2839
2840
2841
2842
2843
2844
2845
2846
2847
2848
2849
2850
2851
2852
2853
2854
2855
2856
2857
2858
2859
2860
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
hDiameter += (
strandEnd - strandStart
) / (
pSys.settings.display_step
+ 1
) # XXX +1 or not?
if (
step == 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'
% (
co[0],
co[1],
co[2],
abs(hDiameter),
)
)
file.write(
'<%.6g,%.6g,%.6g>,%.7g,\n'
% (
co[0],
co[1],
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'
% (
co[0],
co[1],
co[2],
abs(hDiameter),
)
)
# All coordinates except the last need a following comma.
if step != steps - 1:
file.write(',\n')
else:
if texturedHair:
# Write pigment and alpha (between Pov and Blender alpha 0 and 1 are reversed)
file.write(
'\npigment{ color srgbf < %.3g, %.3g, %.3g, %.3g> }\n'
% (
initColor[0],
initColor[1],
initColor[2],
1.0 - initColor[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 != totalNumberOfHairs:
file.write(',\n')
else:
file.write('\n')
# End the array declaration.
if not texturedHair:
# 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'
% totalNumberOfHairs
)
file.write(' object {HairArray[I]')
if not texturedHair:
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')
writeMatrix(global_matrix @ ob.matrix_world)
file.write('}')
print(
'Totals hairstrands written: %i'
% totalNumberOfHairs