Newer
Older
if not me_materials or me_materials[material_index] is None: # No materials
for i1, i2, i3 in indicies:
file.write(',\n\t\t<%d,%d,%d>' % (fv[i1], fv[i2], fv[i3])) # vert count
else:
material = me_materials[material_index]
for i1, i2, i3 in indicies:
if me.vertex_colors and material.use_vertex_color_paint:
# Colour per vertex - vertex colour
col1 = cols[i1]
col2 = cols[i2]
col3 = cols[i3]
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:
# Colour per material - flat material colour
diffuse_color = material.diffuse_color
ci1 = ci2 = ci3 = vertCols[diffuse_color[0], diffuse_color[1], diffuse_color[2], f.material_index][0]
file.write(',\n\t\t<%d,%d,%d>, %d,%d,%d' % (fv[i1], fv[i2], fv[i3], ci1, ci2, ci3)) # vert count
Maurice Raybaud
committed
file.write('\n\t}\n')
# normal_indices indicies
file.write('\tnormal_indices {\n')
file.write('\t\t%d' % (len(me.faces) + quadCount)) # faces count
for fi, fv in enumerate(faces_verts):
if len(fv) == 4:
indicies = (0, 1, 2), (0, 2, 3)
else:
indicies = ((0, 1, 2),)
for i1, i2, i3 in indicies:
file.write(',\n\t\t<%d,%d,%d>' %\
(uniqueNormals[verts_normals[fv[i1]]][0],\
uniqueNormals[verts_normals[fv[i2]]][0],\
uniqueNormals[verts_normals[fv[i3]]][0])) # vert count
else:
idx = uniqueNormals[faces_normals[fi]][0]
file.write(',\n\t\t<%d,%d,%d>' % (idx, idx, idx)) # vert count
Maurice Raybaud
committed
file.write('\n\t}\n')
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
if uv_layer:
file.write('\tuv_indices {\n')
file.write('\t\t%d' % (len(me.faces) + quadCount)) # faces count
for fi, fv in enumerate(faces_verts):
if len(fv) == 4:
indicies = (0, 1, 2), (0, 2, 3)
else:
indicies = ((0, 1, 2),)
uv = uv_layer[fi]
if len(faces_verts[fi]) == 4:
uvs = tuple(uv.uv1), tuple(uv.uv2), tuple(uv.uv3), tuple(uv.uv4)
else:
uvs = tuple(uv.uv1), tuple(uv.uv2), tuple(uv.uv3)
for i1, i2, i3 in indicies:
file.write(',\n\t\t<%d,%d,%d>' %\
(uniqueUVs[uvs[i1]][0],\
uniqueUVs[uvs[i2]][0],\
try:
material = me.materials[0] # dodgy
writeObjectMaterial(material)
except IndexError:
print(me)
#Importance for radiosity sampling added here:
file.write('\tradiosity { importance %3g }\n' % importance)
file.write('}\n') # End of mesh block
Maurice Raybaud
committed
file.write('%s\n' % name) # Use named declaration to allow reference e.g. for baking. MR
bpy.data.meshes.remove(me)
def exportWorld(world):
render = scene.render
matrix = global_matrix * camera.matrix_world
#############Maurice####################################
#These lines added to get sky gradient (visible with PNG output)
if world:
#For simple flat background:
if not world.use_sky_blend:
#Non fully transparent background could premultiply alpha and avoid anti-aliasing display issue:
if render.alpha_mode == 'PREMUL' or render.alpha_mode == 'PREMUL' :
file.write('background {rgbt<%.3g, %.3g, %.3g, 0.75>}\n' % (tuple(world.horizon_color)))
#Currently using no alpha with Sky option:
elif render.alpha_mode == 'SKY':
file.write('background {rgbt<%.3g, %.3g, %.3g, 0>}\n' % (tuple(world.horizon_color)))
#StraightAlpha:
else:
file.write('background {rgbt<%.3g, %.3g, %.3g, 1>}\n' % (tuple(world.horizon_color)))
#For Background image textures
for t in world.texture_slots: #risk to write several sky_spheres but maybe ok.
if t and t.texture.type == 'IMAGE': #and t.use: #No enable checkbox for world textures yet (report it?)
image_filename = path_image(t.texture.image.filepath)
if t.texture.image.filepath != image_filename: t.texture.image.filepath = image_filename
if image_filename != '' and t.use_map_blend:
texturesBlend = image_filename
#colvalue = t.default_value
t_blend = t
#commented below was an idea to make the Background image oriented as camera taken here: http://news.povray.org/povray.newusers/thread/%3Cweb.4a5cddf4e9c9822ba2f93e20@news.povray.org%3E/
#mappingBlend = (" translate <%.4g,%.4g,%.4g> rotate z*degrees(atan((camLocation - camLookAt).x/(camLocation - camLookAt).y)) rotate x*degrees(atan((camLocation - camLookAt).y/(camLocation - camLookAt).z)) rotate y*degrees(atan((camLocation - camLookAt).z/(camLocation - camLookAt).x)) scale <%.4g,%.4g,%.4g>b" % (t_blend.offset.x / 10 ,t_blend.offset.y / 10 ,t_blend.offset.z / 10, t_blend.scale.x ,t_blend.scale.y ,t_blend.scale.z))#replace 4/3 by the ratio of each image found by some custom or existing function
#using camera rotation valuesdirectly from blender seems much easier
Maurice Raybaud
committed
if t_blend.texture_coords=='ANGMAP':
mappingBlend = ("")
else:
mappingBlend = (" translate <%.4g-0.5,%.4g-0.5,%.4g-0.5> rotate<0,0,0> scale <%.4g,%.4g,%.4g>" % (t_blend.offset.x / 10 ,t_blend.offset.y / 10 ,t_blend.offset.z / 10, t_blend.scale.x*0.85 , t_blend.scale.y*0.85 , t_blend.scale.z*0.85 ))
#The initial position and rotation of the pov camera is probably creating the rotation offset should look into it someday but at least background won't rotate with the camera now.
#Putting the map on a plane would not introduce the skysphere distortion and allow for better image scale matching but also some waay to chose depth and size of the plane relative to camera.
file.write('sky_sphere {\n')
file.write('\tpigment {\n')
file.write("\t\timage_map{%s \"%s\" %s}\n\t}\n\t%s\n" % (imageFormat(texturesBlend),texturesBlend,imgMapBG(t_blend),mappingBlend))
file.write('}\n')
#file.write('\t\tscale 2\n')
#file.write('\t\ttranslate -1\n')
#For only Background gradient
if world.use_sky_blend:
file.write('sky_sphere {\n')
file.write('\tpigment {\n')
file.write('\t\tgradient y\n')#maybe Should follow the advice of POV doc about replacing gradient for skysphere..5.5
if render.alpha_mode == 'STRAIGHT':
file.write('\t\t\t[0.0 rgbt<%.3g, %.3g, %.3g, 1>]\n' % (tuple(world.horizon_color)))
file.write('\t\t\t[1.0 rgbt<%.3g, %.3g, %.3g, 1>]\n' % (tuple(world.zenith_color)))
elif render.alpha_mode == 'PREMUL':
file.write('\t\t\t[0.0 rgbt<%.3g, %.3g, %.3g, 0.99>]\n' % (tuple(world.horizon_color)))
file.write('\t\t\t[1.0 rgbt<%.3g, %.3g, %.3g, 0.99>]\n' % (tuple(world.zenith_color))) #aa premult not solved with transmit 1
file.write('\t\t\t[0.0 rgbt<%.3g, %.3g, %.3g, 0>]\n' % (tuple(world.horizon_color)))
file.write('\t\t\t[1.0 rgbt<%.3g, %.3g, %.3g, 0>]\n' % (tuple(world.zenith_color)))
file.write('\t\t}\n')
file.write('\t}\n')
file.write('}\n')
#sky_sphere alpha (transmit) is not translating into image alpha the same way as "background"
scene.pov_radio_enable=1
#Maybe change the above to scene.pov_radio_enable = world.light_settings.use_indirect_light ?
###############################################################
if mist.use_mist:
file.write('fog {\n')
file.write('\tdistance %.6f\n' % mist.depth)
file.write('\tcolor rgbt<%.3g, %.3g, %.3g, %.3g>\n' % (tuple(world.horizon_color) + (1 - mist.intensity,)))
#file.write('\tfog_offset %.6f\n' % mist.start)
#file.write('\tfog_alt 5\n')
#file.write('\tturbulence 0.2\n')
#file.write('\tturb_depth 0.3\n')
file.write('\tfog_type 1\n')
file.write('}\n')
if scene.pov_media_enable:
file.write('media {\n')
file.write('\tscattering { 1, rgb %.3g}\n' % scene.pov_media_color)
file.write('\tsamples %.d\n' % scene.pov_media_samples)
file.write('}\n')
def exportGlobalSettings(scene):
file.write('global_settings {\n')
file.write('\tassumed_gamma 1.0\n')
file.write('\tmax_trace_level %d\n' % scene.pov_max_trace_level)
if scene.pov_radio_enable:
file.write('\tradiosity {\n')
file.write("\t\tadc_bailout %.4g\n" % scene.pov_radio_adc_bailout)
file.write("\t\talways_sample %d\n" % scene.pov_radio_always_sample)
file.write("\t\tbrightness %.4g\n" % scene.pov_radio_brightness)
file.write("\t\tcount %d\n" % scene.pov_radio_count)
file.write("\t\terror_bound %.4g\n" % scene.pov_radio_error_bound)
file.write("\t\tgray_threshold %.4g\n" % scene.pov_radio_gray_threshold)
file.write("\t\tlow_error_factor %.4g\n" % scene.pov_radio_low_error_factor)
file.write("\t\tmedia %d\n" % scene.pov_radio_media)
file.write("\t\tminimum_reuse %.4g\n" % scene.pov_radio_minimum_reuse)
file.write("\t\tnearest_count %d\n" % scene.pov_radio_nearest_count)
file.write("\t\tnormal %d\n" % scene.pov_radio_normal)
file.write("\t\tpretrace_start %.3g\n" % scene.pov_radio_pretrace_start)
file.write("\t\tpretrace_end %.3g\n" % scene.pov_radio_pretrace_end)
file.write("\t\trecursion_limit %d\n" % scene.pov_radio_recursion_limit)
file.write('\t}\n')
once=1
for material in bpy.data.materials:
if material.subsurface_scattering.use and once:
file.write("\tmm_per_unit %.6f\n" % (material.subsurface_scattering.scale * (-100) + 15))#In pov, the scale has reversed influence compared to blender. these number should correct that
once=0 #In povray, the scale factor for all subsurface shaders needs to be the same
file.write("\tambient_light rgb<%.3g, %.3g, %.3g>\n" % tuple(world.ambient_color))
if material.pov_photons_refraction or material.pov_photons_reflection:
file.write("\tphotons {\n")
file.write("\t\tspacing 0.003\n")
file.write("\t\tadc_bailout 0.1\n")
file.write("\t\tgather 30, 150\n")
file.write("\t}\n")
file.write('}\n')
# Convert all materials to strings we can access directly per vertex.
writeMaterial(None) # default material
for material in bpy.data.materials:
writeMaterial(material)
exportLamps([l for l in sel if l.type == 'LAMP'])
exportMeta([l for l in sel if l.type == 'META'])
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
exportWorld(scene.world)
exportGlobalSettings(scene)
file.close()
def write_pov_ini(filename_ini, filename_pov, filename_image):
scene = bpy.data.scenes[0]
render = scene.render
x = int(render.resolution_x * render.resolution_percentage * 0.01)
y = int(render.resolution_y * render.resolution_percentage * 0.01)
file = open(filename_ini, 'w')
file.write('Input_File_Name="%s"\n' % filename_pov)
file.write('Output_File_Name="%s"\n' % filename_image)
file.write('Width=%d\n' % x)
file.write('Height=%d\n' % y)
# Needed for border render.
'''
file.write('Start_Column=%d\n' % part.x)
file.write('End_Column=%d\n' % (part.x+part.w))
file.write('Start_Row=%d\n' % (part.y))
file.write('End_Row=%d\n' % (part.y+part.h))
'''
file.write('Bounding_Method=2\n')#The new automatic BSP is faster in most scenes
file.write('Display=1\n')#Activated (turn this back off when better live exchange is done between the two programs (see next comment)
file.write('Output_File_Type=N\n') # PNG, with POV 3.7, can show background color with alpha. In the long run using the Povray interactive preview like bishop 3D could solve the preview for all formats.
#file.write('Output_File_Type=T\n') # TGA, best progressive loading
aa_mapping = {'5': 2, '8': 3, '11': 4, '16': 5} # method 2 (recursive) with higher max subdiv forced because no mipmapping in povray needs higher sampling.
file.write('Sampling_Method=2\n')
file.write('Antialias_Depth=%d\n' % aa_mapping[render.antialiasing_samples])
file.write('Antialias_Threshold=0.1\n')#rather high settings but necessary.
file.write('Jitter=off\n')#prevent animation flicker
Maurice Raybaud
committed
file.write('Version=3.7')
file.close()
class PovrayRender(bpy.types.RenderEngine):
Doug Hammond
committed
DELAY = 0.05
def _export(self, scene):
import tempfile
self._temp_file_in = tempfile.mktemp(suffix='.pov')
self._temp_file_out = tempfile.mktemp(suffix='.png')#PNG with POV 3.7, can show the background color with alpha. In the long run using the Povray interactive preview like bishop 3D could solve the preview for all formats.
#self._temp_file_out = tempfile.mktemp(suffix='.tga')
self._temp_file_ini = tempfile.mktemp(suffix='.ini')
'''
self._temp_file_in = '/test.pov'
self._temp_file_out = '/test.png'#PNG with POV 3.7, can show the background color with alpha. In the long run using the Povray interactive preview like bishop 3D could solve the preview for all formats.
#self._temp_file_out = '/test.tga'
self._temp_file_ini = '/test.ini'
'''
def info_callback(txt):
write_pov(self._temp_file_in, scene, info_callback)
def _render(self):
try:
os.remove(self._temp_file_out) # so as not to load the old file
pass
write_pov_ini(self._temp_file_ini, self._temp_file_in, self._temp_file_out)
print ("***-STARTING-***")
pov_binary = "povray"
Doug Hammond
committed
extra_args = []
regKey = winreg.OpenKey(winreg.HKEY_CURRENT_USER, 'Software\\POV-Ray\\v3.7\\Windows')
if bitness == 64:
pov_binary = winreg.QueryValueEx(regKey, 'Home')[0] + '\\bin\\pvengine64'
else:
pov_binary = winreg.QueryValueEx(regKey, 'Home')[0] + '\\bin\\pvengine'
Doug Hammond
committed
else:
# DH - added -d option to prevent render window popup which leads to segfault on linux
extra_args.append("-d")
if 1:
# TODO, when povray isnt found this gives a cryptic error, would be nice to be able to detect if it exists
try:
Doug Hammond
committed
self._process = subprocess.Popen([pov_binary, self._temp_file_ini] + extra_args) # stdout=subprocess.PIPE, stderr=subprocess.PIPE
print("POVRAY 3.7: could not execute '%s', possibly povray isn't installed" % pov_binary)
import traceback
traceback.print_exc()
print ("***-DONE-***")
return False
else:
# This works too but means we have to wait until its done
os.system('%s %s' % (pov_binary, self._temp_file_ini))
Doug Hammond
committed
# print ("***-DONE-***")
return True
def _cleanup(self):
for f in (self._temp_file_in, self._temp_file_ini, self._temp_file_out):
try:
os.remove(f)
except OSError: #was that the proper error type?
self.update_stats("", "POVRAY 3.7: Exporting data from Blender")
##WIP output format
## if r.file_format == 'OPENEXR':
## fformat = 'EXR'
## render.color_mode = 'RGBA'
## else:
## fformat = 'TGA'
## r.file_format = 'TARGA'
## r.color_mode = 'RGBA'
# compute resolution
x = int(r.resolution_x * r.resolution_percentage * 0.01)
y = int(r.resolution_y * r.resolution_percentage * 0.01)
# Wait for the file to be created
while not os.path.exists(self._temp_file_out):
Doug Hammond
committed
# print("***POV WAITING FOR FILE***")
Doug Hammond
committed
print("***POV INTERRUPTED***")
Doug Hammond
committed
poll_result = self._process.poll()
Doug Hammond
committed
print("***POV PROCESS FAILED : %s ***" % poll_result)
break
time.sleep(self.DELAY)
if os.path.exists(self._temp_file_out):
Doug Hammond
committed
# print("***POV FILE OK***")
Doug Hammond
committed
# print("***POV UPDATING IMAGE***")
result = self.begin_result(0, 0, x, y)
lay = result.layers[0]
# possible the image wont load early on.
try:
lay.load_from_file(self._temp_file_out)
pass
self.end_result(result)
# Update while povray renders
while True:
Doug Hammond
committed
# print("***POV RENDER LOOP***")
Doug Hammond
committed
print("***POV PROCESS FINISHED***")
update_image()
break
# user exit
if self.test_break():
try:
Doug Hammond
committed
print("***POV PROCESS INTERRUPTED***")
pass
break
# Would be nice to redirect the output
# stdout_value, stderr_value = self._process.communicate() # locks
# check if the file updated
new_size = os.path.getsize(self._temp_file_out)
if new_size != prev_size:
update_image()
prev_size = new_size
time.sleep(self.DELAY)
Doug Hammond
committed
else:
print("***POV FILE NOT FOUND***")
print("***POV FINISHED***")