Newer
Older
# 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]))
# 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(" scattering{ 1, // Type\n")
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")
file.write(" } // end of interior\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")
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'}):
continue
smokeFlag=False
for mod in ob.modifiers:
if mod and hasattr(mod, 'smoke_type'):
smokeFlag=True
if (mod.smoke_type == 'DOMAIN'):
exportSmoke(ob.name)
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:
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
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):
tstart = time.time()
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:
texturedHair=1
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):
#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
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))
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
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))
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
#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
else:
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:
# End the array declaration.
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
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)
print('Number of tufts (particle systems)', len(ob.particle_systems))
# Set back the displayed number of particles to preview count
# pSys.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,
if renderEmitter == False:
continue #don't render mesh, skip to next object.
#############################################
# 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,
# so this condition is always True, IMO -- mont29
if ob.data:
Maurice Raybaud
committed
name_orig = "OB" + ob.name
dataname_orig = "DATA" + ob.data.name
elif ob.is_instancer:
if ob.instance_type == 'COLLECTION':
name_orig = "OB" + ob.name
dataname_orig = "DATA" + ob.instance_collection.name
else:
#hoping only dupligroups have several source datablocks
#ob_dupli_list_create(scene) #deprecated in 2.8
depsgraph = bpy.context.evaluated_depsgraph_get()
for eachduplicate in depsgraph.object_instances:
if eachduplicate.is_instance: # Real dupli instance filtered because original included in list since 2.8
dataname_orig = "DATA" + eachduplicate.object.name
#ob.dupli_list_clear() #just don't store any reference to instance since 2.8
elif ob.type == 'EMPTY':
name_orig = "OB" + ob.name
dataname_orig = "DATA" + ob.name
Maurice Raybaud
committed
else:
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
name_orig = DEF_OBJ_NAME
dataname_orig = DEF_OBJ_NAME
name = string_strip_hyphen(bpy.path.clean_name(name_orig))
dataname = string_strip_hyphen(bpy.path.clean_name(dataname_orig))
## for slot in ob.material_slots:
## if slot.material is not None and slot.link == 'OBJECT':
## obmaterial = slot.material
#############################################
if info_callback:
info_callback("Object %2.d of %2.d (%s)" % (ob_num, len(sel), ob.name))
#if ob.type != 'MESH':
# continue
# me = ob.data
matrix = global_matrix @ ob.matrix_world
povdataname = store(scene, ob, name, dataname, matrix)
if povdataname is None:
print("This is an instance of " + name)
continue
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
print("Writing Down First Occurrence of " + name)
############################################Povray Primitives
# special exportCurves() function takes care of writing
# lathe, sphere_sweep, birail, and loft except with modifiers
# converted to mesh
if not ob.is_modified(scene, 'RENDER'):
if ob.type == 'CURVE' and (ob.pov.curveshape in
{'lathe', 'sphere_sweep', 'loft'}):
continue #Don't render proxy mesh, skip to next object
if ob.pov.object_as == 'ISOSURFACE':
tabWrite("#declare %s = isosurface{ \n"% povdataname)
tabWrite("function{ \n")
textName = ob.pov.iso_function_text
if textName:
node_tree = bpy.context.scene.node_tree
for node in node_tree.nodes:
if node.bl_idname == "IsoPropsNode" and node.label == ob.name:
for inp in node.inputs:
if inp:
tabWrite("#declare %s = %.6g;\n"%(inp.name,inp.default_value))
text = bpy.data.texts[textName]
for line in text.lines:
split = line.body.split()
if split[0] != "#declare":
tabWrite("%s\n"%line.body)
else:
tabWrite("abs(x) - 2 + y")
tabWrite("}\n")
tabWrite("threshold %.6g\n"%ob.pov.threshold)
tabWrite("max_gradient %.6g\n"%ob.pov.max_gradient)
tabWrite("accuracy %.6g\n"%ob.pov.accuracy)
tabWrite("contained_by { ")
if ob.pov.contained_by == "sphere":
tabWrite("sphere {0,%.6g}}\n"%ob.pov.container_scale)
else:
tabWrite("box {-%.6g,%.6g}}\n"%(ob.pov.container_scale,ob.pov.container_scale))
if ob.pov.all_intersections:
tabWrite("all_intersections\n")
else:
if ob.pov.max_trace > 1:
tabWrite("max_trace %.6g\n"%ob.pov.max_trace)
povMatName = "Default_texture"
if ob.active_material:
#povMatName = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
try:
material = ob.active_material
writeObjectMaterial(material, ob)
except IndexError:
print(me)
#tabWrite("texture {%s}\n"%povMatName)
tabWrite("scale %.6g\n"%(1/ob.pov.container_scale))
tabWrite("}\n")
continue #Don't render proxy mesh, skip to next object
if ob.pov.object_as == 'SUPERELLIPSOID':
tabWrite("#declare %s = superellipsoid{ <%.4f,%.4f>\n"%(povdataname,ob.pov.se_n2,ob.pov.se_n1))
povMatName = "Default_texture"
if ob.active_material:
#povMatName = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
try:
material = ob.active_material
writeObjectMaterial(material, ob)
except IndexError:
print(me)
#tabWrite("texture {%s}\n"%povMatName)
write_object_modifiers(scene,ob,file)
tabWrite("}\n")
continue #Don't render proxy mesh, skip to next object
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
if ob.pov.object_as == 'SUPERTORUS':
rMajor = ob.pov.st_major_radius
rMinor = ob.pov.st_minor_radius
ring = ob.pov.st_ring
cross = ob.pov.st_cross
accuracy=ob.pov.st_accuracy
gradient=ob.pov.st_max_gradient
############Inline Supertorus macro
file.write("#macro Supertorus(RMj, RMn, MajorControl, MinorControl, Accuracy, MaxGradient)\n")
file.write(" #local CP = 2/MinorControl;\n")
file.write(" #local RP = 2/MajorControl;\n")
file.write(" isosurface {\n")
file.write(" function { pow( pow(abs(pow(pow(abs(x),RP) + pow(abs(z),RP), 1/RP) - RMj),CP) + pow(abs(y),CP) ,1/CP) - RMn }\n")
file.write(" threshold 0\n")
file.write(" contained_by {box {<-RMj-RMn,-RMn,-RMj-RMn>, < RMj+RMn, RMn, RMj+RMn>}}\n")
file.write(" #if(MaxGradient >= 1)\n")
file.write(" max_gradient MaxGradient\n")
file.write(" #else\n")
file.write(" evaluate 1, 10, 0.1\n")
file.write(" #end\n")
file.write(" accuracy Accuracy\n")
file.write(" }\n")
file.write("#end\n")
############
tabWrite("#declare %s = object{ Supertorus( %.4g,%.4g,%.4g,%.4g,%.4g,%.4g)\n"%(povdataname,rMajor,rMinor,ring,cross,accuracy,gradient))
povMatName = "Default_texture"
if ob.active_material:
#povMatName = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
try:
material = ob.active_material
writeObjectMaterial(material, ob)
except IndexError:
print(me)
#tabWrite("texture {%s}\n"%povMatName)
write_object_modifiers(scene,ob,file)
tabWrite("rotate x*90\n")
tabWrite("}\n")
continue #Don't render proxy mesh, skip to next object
if ob.pov.object_as == 'PLANE':
tabWrite("#declare %s = plane{ <0,0,1>,1\n"%povdataname)
povMatName = "Default_texture"
if ob.active_material:
#povMatName = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
try:
material = ob.active_material
writeObjectMaterial(material, ob)
except IndexError:
print(me)
#tabWrite("texture {%s}\n"%povMatName)
write_object_modifiers(scene,ob,file)
#tabWrite("rotate x*90\n")
tabWrite("}\n")
continue #Don't render proxy mesh, skip to next object
if ob.pov.object_as == 'BOX':
tabWrite("#declare %s = box { -1,1\n"%povdataname)
povMatName = "Default_texture"
if ob.active_material:
#povMatName = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
try:
material = ob.active_material
writeObjectMaterial(material, ob)
except IndexError:
print(me)
#tabWrite("texture {%s}\n"%povMatName)
write_object_modifiers(scene,ob,file)
#tabWrite("rotate x*90\n")
tabWrite("}\n")
continue #Don't render proxy mesh, skip to next object
if ob.pov.object_as == 'CONE':
br = ob.pov.cone_base_radius
cr = ob.pov.cone_cap_radius
bz = ob.pov.cone_base_z
cz = ob.pov.cone_cap_z
tabWrite("#declare %s = cone { <0,0,%.4f>,%.4f,<0,0,%.4f>,%.4f\n"%(povdataname,bz,br,cz,cr))
povMatName = "Default_texture"
if ob.active_material:
#povMatName = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
try:
material = ob.active_material
writeObjectMaterial(material, ob)
except IndexError:
print(me)
#tabWrite("texture {%s}\n"%povMatName)
write_object_modifiers(scene,ob,file)
#tabWrite("rotate x*90\n")
tabWrite("}\n")
continue #Don't render proxy mesh, skip to next object
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
if ob.pov.object_as == 'CYLINDER':
r = ob.pov.cylinder_radius
x2 = ob.pov.cylinder_location_cap[0]
y2 = ob.pov.cylinder_location_cap[1]
z2 = ob.pov.cylinder_location_cap[2]
tabWrite("#declare %s = cylinder { <0,0,0>,<%6f,%6f,%6f>,%6f\n"%(
povdataname,
x2,
y2,
z2,
r))
povMatName = "Default_texture"
if ob.active_material:
#povMatName = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
try:
material = ob.active_material
writeObjectMaterial(material, ob)
except IndexError:
print(me)
#tabWrite("texture {%s}\n"%povMatName)
#cylinders written at origin, translated below
write_object_modifiers(scene,ob,file)
#tabWrite("rotate x*90\n")
tabWrite("}\n")
continue #Don't render proxy mesh, skip to next object
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
if ob.pov.object_as == 'HEIGHT_FIELD':
data = ""
filename = ob.pov.hf_filename
data += '"%s"'%filename
gamma = ' gamma %.4f'%ob.pov.hf_gamma
data += gamma
if ob.pov.hf_premultiplied:
data += ' premultiplied on'
if ob.pov.hf_smooth:
data += ' smooth'
if ob.pov.hf_water > 0:
data += ' water_level %.4f'%ob.pov.hf_water
#hierarchy = ob.pov.hf_hierarchy
tabWrite('#declare %s = height_field { %s\n'%(povdataname,data))
povMatName = "Default_texture"
if ob.active_material:
#povMatName = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
try:
material = ob.active_material
writeObjectMaterial(material, ob)
except IndexError:
print(me)
#tabWrite("texture {%s}\n"%povMatName)
write_object_modifiers(scene,ob,file)
tabWrite("rotate x*90\n")
tabWrite("translate <-0.5,0.5,0>\n")
tabWrite("scale <0,-1,0>\n")
tabWrite("}\n")
continue #Don't render proxy mesh, skip to next object
if ob.pov.object_as == 'SPHERE':
tabWrite("#declare %s = sphere { 0,%6f\n"%(povdataname,ob.pov.sphere_radius))
povMatName = "Default_texture"
if ob.active_material:
#povMatName = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
try:
material = ob.active_material
writeObjectMaterial(material, ob)
except IndexError:
print(me)
#tabWrite("texture {%s}\n"%povMatName)
write_object_modifiers(scene,ob,file)
#tabWrite("rotate x*90\n")
tabWrite("}\n")
continue #Don't render proxy mesh, skip to next object
if ob.pov.object_as == 'TORUS':
tabWrite("#declare %s = torus { %.4f,%.4f\n"%(povdataname,ob.pov.torus_major_radius,ob.pov.torus_minor_radius))
povMatName = "Default_texture"
if ob.active_material:
#povMatName = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
try:
material = ob.active_material
writeObjectMaterial(material, ob)
except IndexError:
print(me)
#tabWrite("texture {%s}\n"%povMatName)
write_object_modifiers(scene,ob,file)
tabWrite("rotate x*90\n")
tabWrite("}\n")
continue #Don't render proxy mesh, skip to next object
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
if ob.pov.object_as == 'PARAMETRIC':
tabWrite("#declare %s = parametric {\n"%povdataname)
tabWrite("function { %s }\n"%ob.pov.x_eq)
tabWrite("function { %s }\n"%ob.pov.y_eq)
tabWrite("function { %s }\n"%ob.pov.z_eq)
tabWrite("<%.4f,%.4f>, <%.4f,%.4f>\n"%(ob.pov.u_min,ob.pov.v_min,ob.pov.u_max,ob.pov.v_max))
if ob.pov.contained_by == "sphere":
tabWrite("contained_by { sphere{0, 2} }\n")
else:
tabWrite("contained_by { box{-2, 2} }\n")
tabWrite("max_gradient %.6f\n"%ob.pov.max_gradient)
tabWrite("accuracy %.6f\n"%ob.pov.accuracy)
tabWrite("precompute 10 x,y,z\n")
tabWrite("}\n")
continue #Don't render proxy mesh, skip to next object
if ob.pov.object_as == 'POLYCIRCLE':
#TODO write below macro Once:
#if write_polytocircle_macro_once == 0:
file.write("/****************************\n")
file.write("This macro was written by 'And'.\n")
file.write("Link:(http://news.povray.org/povray.binaries.scene-files/)\n")
file.write("****************************/\n")
file.write("//from math.inc:\n")
file.write("#macro VPerp_Adjust(V, Axis)\n")
file.write(" vnormalize(vcross(vcross(Axis, V), Axis))\n")
file.write("#end\n")
file.write("//Then for the actual macro\n")
file.write("#macro Shape_Slice_Plane_2P_1V(point1, point2, clip_direct)\n")
file.write("#local p1 = point1 + <0,0,0>;\n")
file.write("#local p2 = point2 + <0,0,0>;\n")
file.write("#local clip_v = vnormalize(clip_direct + <0,0,0>);\n")
file.write("#local direct_v1 = vnormalize(p2 - p1);\n")
file.write("#if(vdot(direct_v1, clip_v) = 1)\n")
file.write(' #error "Shape_Slice_Plane_2P_1V error: Can\'t decide plane"\n')
file.write("#end\n\n")
file.write("#local norm = -vnormalize(clip_v - direct_v1*vdot(direct_v1,clip_v));\n")
file.write("#local d = vdot(norm, p1);\n")
file.write("plane{\n")
file.write("norm, d\n")
file.write("}\n")
file.write("#end\n\n")
file.write("//polygon to circle\n")
file.write("#macro Shape_Polygon_To_Circle_Blending(_polygon_n, _side_face, _polygon_circumscribed_radius, _circle_radius, _height)\n")
file.write("#local n = int(_polygon_n);\n")
file.write("#if(n < 3)\n")
file.write(" #error ""\n")
file.write("#end\n\n")
file.write("#local front_v = VPerp_Adjust(_side_face, z);\n")
file.write("#if(vdot(front_v, x) >= 0)\n")
file.write(" #local face_ang = acos(vdot(-y, front_v));\n")
file.write("#else\n")
file.write(" #local face_ang = -acos(vdot(-y, front_v));\n")
file.write("#end\n")
file.write("#local polyg_ext_ang = 2*pi/n;\n")
file.write("#local polyg_outer_r = _polygon_circumscribed_radius;\n")
file.write("#local polyg_inner_r = polyg_outer_r*cos(polyg_ext_ang/2);\n")
file.write("#local cycle_r = _circle_radius;\n")
file.write("#local h = _height;\n")
file.write("#if(polyg_outer_r < 0 | cycle_r < 0 | h <= 0)\n")
file.write(' #error "error: each side length must be positive"\n')
file.write("#end\n\n")
file.write("#local multi = 1000;\n")
file.write("#local poly_obj =\n")
file.write("polynomial{\n")
file.write("4,\n")
file.write("xyz(0,2,2): multi*1,\n")
file.write("xyz(2,0,1): multi*2*h,\n")
file.write("xyz(1,0,2): multi*2*(polyg_inner_r-cycle_r),\n")
file.write("xyz(2,0,0): multi*(-h*h),\n")
file.write("xyz(0,0,2): multi*(-pow(cycle_r - polyg_inner_r, 2)),\n")
file.write("xyz(1,0,1): multi*2*h*(-2*polyg_inner_r + cycle_r),\n")
file.write("xyz(1,0,0): multi*2*h*h*polyg_inner_r,\n")
file.write("xyz(0,0,1): multi*2*h*polyg_inner_r*(polyg_inner_r - cycle_r),\n")
file.write("xyz(0,0,0): multi*(-pow(polyg_inner_r*h, 2))\n")
file.write("sturm\n")
file.write("}\n\n")
file.write("#local mockup1 =\n")
file.write("difference{\n")
file.write(" cylinder{\n")
file.write(" <0,0,0.0>,<0,0,h>, max(polyg_outer_r, cycle_r)\n")
file.write(" }\n\n")
file.write(" #for(i, 0, n-1)\n")
file.write(" object{\n")
file.write(" poly_obj\n")
file.write(" inverse\n")
file.write(" rotate <0, 0, -90 + degrees(polyg_ext_ang*i)>\n")
file.write(" }\n")
file.write(" object{\n")
file.write(" Shape_Slice_Plane_2P_1V(<polyg_inner_r,0,0>,<cycle_r,0,h>,x)\n")
file.write(" rotate <0, 0, -90 + degrees(polyg_ext_ang*i)>\n")
file.write(" }\n")
file.write(" #end\n")
file.write("}\n\n")
file.write("object{\n")
file.write("mockup1\n")
file.write("rotate <0, 0, degrees(face_ang)>\n")
file.write("}\n")
file.write("#end\n")
#Use the macro
ngon = ob.pov.polytocircle_ngon
ngonR = ob.pov.polytocircle_ngonR
circleR = ob.pov.polytocircle_circleR
tabWrite("#declare %s = object { Shape_Polygon_To_Circle_Blending(%s, z, %.4f, %.4f, 2) rotate x*180 translate z*1\n"%(povdataname,ngon,ngonR,circleR))
tabWrite("}\n")
continue #Don't render proxy mesh, skip to next object
############################################else try to export mesh
elif ob.is_instancer == False: #except duplis which should be instances groups for now but all duplis later
if ob.type == 'EMPTY':
tabWrite("\n//dummy sphere to represent Empty location\n")
tabWrite("#declare %s =sphere {<0, 0, 0>,0 pigment{rgbt 1} no_image no_reflection no_radiosity photons{pass_through collect off} hollow}\n" % povdataname)
# TODO(sergey): PovRay is a render engine, so should be using dependency graph
# which was given to it via render engine API.
depsgraph = bpy.context.evaluated_depsgraph_get()
ob_eval = ob.evaluated_get(depsgraph)
try:
me = ob_eval.to_mesh()
#XXX Here? identify the specific exception for mesh object with no data
#XXX So that we can write something for the dataname !
except:
# also happens when curves cant be made into meshes because of no-data
continue
importance = ob.pov.importance_value
if me:
me.calc_loop_triangles()
me_materials = me.materials
me_faces = me.loop_triangles[:]
#if len(me_faces)==0:
#tabWrite("\n//dummy sphere to represent empty mesh location\n")
#tabWrite("#declare %s =sphere {<0, 0, 0>,0 pigment{rgbt 1} no_image no_reflection no_radiosity photons{pass_through collect off} hollow}\n" % povdataname)
if not me or not me_faces:
tabWrite("\n//dummy sphere to represent empty mesh location\n")
tabWrite("#declare %s =sphere {<0, 0, 0>,0 pigment{rgbt 1} no_image no_reflection no_radiosity photons{pass_through collect off} hollow}\n" % povdataname)
continue
uv_layers = me.uv_layers
if len(uv_layers) > 0:
if me.uv_layers.active and uv_layers.active.data:
uv_layer = uv_layers.active.data
try:
#vcol_layer = me.vertex_colors.active.data
vcol_layer = me.vertex_colors.active.data
except AttributeError:
vcol_layer = None
faces_verts = [f.vertices[:] for f in me_faces]
faces_normals = [f.normal[:] for f in me_faces]
verts_normals = [v.normal[:] for v in me.vertices]
# Use named declaration to allow reference e.g. for baking. MR
file.write("\n")
tabWrite("#declare %s =\n" % povdataname)
tabWrite("mesh2 {\n")
tabWrite("vertex_vectors {\n")
tabWrite("%d" % len(me.vertices)) # vert count
tabStr = tab * tabLevel
if linebreaksinlists:
file.write(",\n")
file.write(tabStr + "<%.6f, %.6f, %.6f>" % v.co[:]) # vert count
file.write("<%.6f, %.6f, %.6f>" % v.co[:]) # vert count
#tabWrite("<%.6f, %.6f, %.6f>" % v.co[:]) # vert count
file.write("\n")
tabWrite("}\n")
# Build unique Normal list
uniqueNormals = {}
for fi, f in enumerate(me_faces):
fv = faces_verts[fi]
# [-1] is a dummy index, use a list so we can modify in place
if f.use_smooth: # Use vertex normals
for v in fv:
key = verts_normals[v]
uniqueNormals[key] = [-1]
else: # Use face normal
key = faces_normals[fi]
uniqueNormals[key] = [-1]
tabWrite("normal_vectors {\n")
tabWrite("%d" % len(uniqueNormals)) # vert count
idx = 0
tabStr = tab * tabLevel
for no, index in uniqueNormals.items():
if linebreaksinlists:
file.write(",\n")
file.write(tabStr + "<%.6f, %.6f, %.6f>" % no) # vert count
file.write(", ")
file.write("<%.6f, %.6f, %.6f>" % no) # vert count
index[0] = idx
idx += 1
file.write("\n")
tabWrite("}\n")
# Vertex colors
vertCols = {} # Use for material colors also.
if uv_layer:
# Generate unique UV's
uniqueUVs = {}
#n = 0
for f in me_faces: # me.faces in 2.7
uvs = [uv_layer[l].uv[:] for l in f.loops]
for uv in uvs:
uniqueUVs[uv[:]] = [-1]
tabWrite("uv_vectors {\n")
#print unique_uvs
tabWrite("%d" % len(uniqueUVs)) # vert count
idx = 0
tabStr = tab * tabLevel
for uv, index in uniqueUVs.items():
if linebreaksinlists:
file.write(",\n")
file.write(tabStr + "<%.6f, %.6f>" % uv)
file.write("<%.6f, %.6f>" % uv)
index[0] = idx
idx += 1
'''
# Just add 1 dummy vector, no real UV's
tabWrite('1') # vert count
file.write(',\n\t\t<0.0, 0.0>')
'''
file.write("\n")
tabWrite("}\n")
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
if me.vertex_colors:
#Write down vertex colors as a texture for each vertex
tabWrite("texture_list {\n")
tabWrite("%d\n" % (len(me_faces) * 3)) # assumes we have only triangles
VcolIdx=0
if comments:
file.write("\n //Vertex colors: one simple pigment texture per vertex\n")
for fi, f in enumerate(me_faces):
# annoying, index may be invalid
material_index = f.material_index
try:
material = me_materials[material_index]
except:
material = None
if material: #and material.use_vertex_color_paint: #Always use vertex color when there is some for now
cols = [vcol_layer[l].color[:] for l in f.loops]
for col in cols:
key = col[0], col[1], col[2], material_index # Material index!
VcolIdx+=1
vertCols[key] = [VcolIdx]
if linebreaksinlists:
tabWrite("texture {pigment{ color srgb <%6f,%6f,%6f> }}\n" % (col[0], col[1], col[2]))
else:
tabWrite("texture {pigment{ color srgb <%6f,%6f,%6f> }}" % (col[0], col[1], col[2]))
tabStr = tab * tabLevel
if material:
# Multiply diffuse with SSS Color
if material.pov_subsurface_scattering.use:
diffuse_color = [i * j for i, j in zip(material.pov_subsurface_scattering.color[:], material.diffuse_color[:])]
key = diffuse_color[0], diffuse_color[1], diffuse_color[2], \
material_index
vertCols[key] = [-1]
else:
diffuse_color = material.diffuse_color[:]
key = diffuse_color[0], diffuse_color[1], diffuse_color[2], \
material_index
vertCols[key] = [-1]
tabWrite("\n}\n")
# Face indices
tabWrite("\nface_indices {\n")
tabWrite("%d" % (len(me_faces))) # faces count
tabStr = tab * tabLevel
for fi, f in enumerate(me_faces):
fv = faces_verts[fi]
material_index = f.material_index
if vcol_layer:
cols = [vcol_layer[l].color[:] for l in f.loops]
if not me_materials or me_materials[material_index] is None: # No materials
if linebreaksinlists:
file.write(",\n")
# vert count
file.write(tabStr + "<%d,%d,%d>" % (fv[0], fv[1], fv[2]))
else:
file.write(", ")
file.write("<%d,%d,%d>" % (fv[0], fv[1], fv[2])) # vert count
Maurice Raybaud
committed
else:
material = me_materials[material_index]
if me.vertex_colors: #and material.use_vertex_color_paint:
# Color per vertex - vertex color
col1 = cols[0]
col2 = cols[1]
col3 = cols[2]
2932
2933
2934
2935
2936
2937
2938
2939
2940
2941
2942
2943
2944
2945
2946
2947
2948
2949
2950
2951
2952
2953
2954
2955
2956
2957
ci1 = vertCols[col1[0], col1[1], col1[2], material_index][0]
ci2 = vertCols[col2[0], col2[1], col2[2], material_index][0]
ci3 = vertCols[col3[0], col3[1], col3[2], material_index][0]
else:
# Color per material - flat material color
if material.pov_subsurface_scattering.use:
diffuse_color = [i * j for i, j in zip(material.pov_subsurface_scattering.color[:], material.diffuse_color[:])]
else:
diffuse_color = material.diffuse_color[:]
ci1 = ci2 = ci3 = vertCols[diffuse_color[0], diffuse_color[1], \
diffuse_color[2], f.material_index][0]
# ci are zero based index so we'll subtract 1 from them
if linebreaksinlists:
file.write(",\n")
file.write(tabStr + "<%d,%d,%d>, %d,%d,%d" % \
(fv[0], fv[1], fv[2], ci1-1, ci2-1, ci3-1)) # vert count
else:
file.write(", ")
file.write("<%d,%d,%d>, %d,%d,%d" % \
(fv[0], fv[1], fv[2], ci1-1, ci2-1, ci3-1)) # vert count
file.write("\n")
tabWrite("}\n")
# normal_indices indices
tabWrite("normal_indices {\n")
tabWrite("%d" % (len(me_faces))) # faces count
tabStr = tab * tabLevel
for fi, fv in enumerate(faces_verts):
if me_faces[fi].use_smooth:
if linebreaksinlists:
file.write(",\n")
file.write(tabStr + "<%d,%d,%d>" %\
(uniqueNormals[verts_normals[fv[0]]][0],\
uniqueNormals[verts_normals[fv[1]]][0],\
uniqueNormals[verts_normals[fv[2]]][0])) # vert count
else:
file.write(", ")
file.write("<%d,%d,%d>" %\
(uniqueNormals[verts_normals[fv[0]]][0],\
uniqueNormals[verts_normals[fv[1]]][0],\
uniqueNormals[verts_normals[fv[2]]][0])) # vert count
Maurice Raybaud
committed
else:
idx = uniqueNormals[faces_normals[fi]][0]
if linebreaksinlists:
file.write(",\n")
file.write(tabStr + "<%d,%d,%d>" % (idx, idx, idx)) # vert count
else:
file.write(", ")
file.write("<%d,%d,%d>" % (idx, idx, idx)) # vert count
file.write("\n")
tabWrite("}\n")
if uv_layer:
tabWrite("uv_indices {\n")
tabWrite("%d" % (len(me_faces))) # faces count
tabStr = tab * tabLevel
for f in me_faces:
uvs = [uv_layer[l].uv[:] for l in f.loops]
if linebreaksinlists:
file.write(",\n")
file.write(tabStr + "<%d,%d,%d>" % (
uniqueUVs[uvs[0]][0],\
uniqueUVs[uvs[1]][0],\
uniqueUVs[uvs[2]][0]))
else: