Newer
Older
mappingNor = (' translate <%.4g-0.75,%.4g-0.75,%.4g-0.75> scale <%.4g,%.4g,%.4g>\n' % (t_nor.offset.x / 10 ,t_nor.offset.y / 10 ,t_nor.offset.z / 10, t_nor.scale.x / 2.25, t_nor.scale.y / 2.25, t_nor.scale.z / 2.25))
#imageMapNor = ('{bump_map {%s \"%s\" %s mapping}' % (imageFormat(texturesNorm),texturesNorm,imgMap(t_nor)))
fileWriteTab(4, 'normal {uv_mapping bump_map {%s \"%s\" %s bump_size %.4g }%s}\n' % (imageFormat(texturesNorm),texturesNorm,imgMap(t_nor),(t_nor.normal_factor * 10),mappingNor))
#End of slope/ior texture_map
if material.diffuse_shader == 'MINNAERT' or material.diffuse_shader == 'FRESNEL':
fileWriteTab(4, ']\n')
fileWriteTab(3, '}\n')
fileWriteTab(2, '}\n') #THEN IT CAN CLOSE IT --MR
############################################################################################################
fileWriteTab(1, 'face_indices {\n')
fileWriteTab(2, '%d' % (len(me.faces) + quadCount)) # faces count
for fi, f in enumerate(me.faces):
fv = faces_verts[fi]
material_index = f.material_index
if len(fv) == 4:
indicies = (0, 1, 2), (0, 2, 3)
else:
indicies = ((0, 1, 2),)
if vcol_layer:
col = vcol_layer[fi]
if len(fv) == 4:
cols = col.color1, col.color2, col.color3, col.color4
else:
cols = col.color1, col.color2, col.color3
if not me_materials or me_materials[material_index] is None: # No materials
fileWriteTab(0, ',\n')
fileWriteTab(2, '<%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]
fileWriteTab(0, ',\n')
fileWriteTab(2, '<%d,%d,%d>, %d,%d,%d' % (fv[i1], fv[i2], fv[i3], ci1, ci2, ci3)) # vert count
fileWriteTab(1, 'normal_indices {\n')
fileWriteTab(2, '%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:
fileWriteTab(0, ',\n')
fileWriteTab(2, '<%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]
fileWriteTab(0, ',\n')
fileWriteTab(2, '<%d,%d,%d>' % (idx, idx, idx)) # vert count
fileWriteTab(1, 'uv_indices {\n')
fileWriteTab(2, '%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:
fileWriteTab(0, ',\n')
fileWriteTab(2, '<%d,%d,%d>' %\
try:
material = me.materials[0] # dodgy
writeObjectMaterial(material)
except IndexError:
print(me)
fileWriteTab(1, 'radiosity { \n')
fileWriteTab(2, 'importance %3g \n' % importance)
fileWriteTab(1, '}\n')
fileWriteTab(0, '}\n') # End of mesh block
fileWriteTab(0, '%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' :
fileWriteTab(0, 'background {rgbt<%.3g, %.3g, %.3g, 0.75>}\n' % (tuple(world.horizon_color)))
#Currently using no alpha with Sky option:
elif render.alpha_mode == 'SKY':
fileWriteTab(0, 'background {rgbt<%.3g, %.3g, %.3g, 0>}\n' % (tuple(world.horizon_color)))
fileWriteTab(0, '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':
Maurice Raybaud
committed
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.
fileWriteTab(0, 'sky_sphere {\n')
fileWriteTab(1, 'pigment {\n')
fileWriteTab(2, 'image_map{%s \"%s\" %s}\n' % (imageFormat(texturesBlend),texturesBlend,imgMapBG(t_blend)))
fileWriteTab(1, '}\n')
fileWriteTab(1, '%s\n' % (mappingBlend))
fileWriteTab(0, '}\n')
#fileWriteTab(2, 'scale 2\n')
#fileWriteTab(2, 'translate -1\n')
fileWriteTab(0, 'sky_sphere {\n')
fileWriteTab(1, 'pigment {\n')
fileWriteTab(2, 'gradient y\n')#maybe Should follow the advice of POV doc about replacing gradient for skysphere..5.5
fileWriteTab(2, 'color_map {\n')
if render.alpha_mode == 'STRAIGHT':
fileWriteTab(3, '[0.0 rgbt<%.3g, %.3g, %.3g, 1>]\n' % (tuple(world.horizon_color)))
fileWriteTab(3, '[1.0 rgbt<%.3g, %.3g, %.3g, 1>]\n' % (tuple(world.zenith_color)))
elif render.alpha_mode == 'PREMUL':
fileWriteTab(3, '[0.0 rgbt<%.3g, %.3g, %.3g, 0.99>]\n' % (tuple(world.horizon_color)))
fileWriteTab(3, '[1.0 rgbt<%.3g, %.3g, %.3g, 0.99>]\n' % (tuple(world.zenith_color))) #aa premult not solved with transmit 1
fileWriteTab(3, '[0.0 rgbt<%.3g, %.3g, %.3g, 0>]\n' % (tuple(world.horizon_color)))
fileWriteTab(3, '[1.0 rgbt<%.3g, %.3g, %.3g, 0>]\n' % (tuple(world.zenith_color)))
fileWriteTab(2, '}\n')
fileWriteTab(1, '}\n')
fileWriteTab(0, '}\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 ?
###############################################################
fileWriteTab(0, 'fog {\n')
fileWriteTab(1, 'distance %.6f\n' % mist.depth)
fileWriteTab(1, 'color rgbt<%.3g, %.3g, %.3g, %.3g>\n' % (tuple(world.horizon_color) + (1 - mist.intensity,)))
#fileWriteTab(1, 'fog_offset %.6f\n' % mist.start)
#fileWriteTab(1, 'fog_alt 5\n')
#fileWriteTab(1, 'turbulence 0.2\n')
#fileWriteTab(1, 'turb_depth 0.3\n')
fileWriteTab(1, 'fog_type 1\n')
fileWriteTab(0, '}\n')
if scene.pov_media_enable:
fileWriteTab(0, 'media {\n')
fileWriteTab(1, 'scattering { 1, rgb %.3g}\n' % scene.pov_media_color)
fileWriteTab(1, 'samples %.d\n' % scene.pov_media_samples)
fileWriteTab(0, '}\n')
fileWriteTab(0, 'global_settings {\n')
fileWriteTab(1, 'assumed_gamma 1.0\n')
fileWriteTab(1, 'max_trace_level %d\n' % scene.pov_max_trace_level)
fileWriteTab(1, 'radiosity {\n')
fileWriteTab(2, 'adc_bailout %.4g\n' % scene.pov_radio_adc_bailout)
fileWriteTab(2, 'always_sample %d\n' % scene.pov_radio_always_sample)
fileWriteTab(2, 'brightness %.4g\n' % scene.pov_radio_brightness)
fileWriteTab(2, 'count %d\n' % scene.pov_radio_count)
fileWriteTab(2, 'error_bound %.4g\n' % scene.pov_radio_error_bound)
fileWriteTab(2, 'gray_threshold %.4g\n' % scene.pov_radio_gray_threshold)
fileWriteTab(2, 'low_error_factor %.4g\n' % scene.pov_radio_low_error_factor)
fileWriteTab(2, 'media %d\n' % scene.pov_radio_media)
fileWriteTab(2, 'minimum_reuse %.4g\n' % scene.pov_radio_minimum_reuse)
fileWriteTab(2, 'nearest_count %d\n' % scene.pov_radio_nearest_count)
fileWriteTab(2, 'normal %d\n' % scene.pov_radio_normal)
fileWriteTab(2, 'pretrace_start %.3g\n' % scene.pov_radio_pretrace_start)
fileWriteTab(2, 'pretrace_end %.3g\n' % scene.pov_radio_pretrace_end)
fileWriteTab(2, 'recursion_limit %d\n' % scene.pov_radio_recursion_limit)
fileWriteTab(1, '}\n')
once=1
for material in bpy.data.materials:
if material.subsurface_scattering.use and once:
fileWriteTab(1, 'mm_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
fileWriteTab(1, 'ambient_light rgb<%.3g, %.3g, %.3g>\n' % tuple(world.ambient_color))
if material.pov_photons_refraction or material.pov_photons_reflection:
fileWriteTab(1, 'photons {\n')
fileWriteTab(2, 'spacing 0.003\n')
fileWriteTab(2, 'max_trace_level 5\n')
fileWriteTab(2, 'adc_bailout 0.1\n')
fileWriteTab(2, 'gather 30, 150\n')
fileWriteTab(1, '}\n')
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
sel = scene.objects
comments = scene.pov_comments_enable
if comments: file.write('//---------------------------------------------\n//--Exported with Povray exporter for Blender--\n//---------------------------------------------\n')
if comments: file.write('\n//--Global settings and background--\n\n')
exportGlobalSettings(scene)
if comments: file.write('\n')
exportWorld(scene.world)
if comments: file.write('\n//--Cameras--\n\n')
exportCamera()
if comments: file.write('\n//--Lamps--\n\n')
exportLamps([l for l in sel if l.type == 'LAMP'])
if comments: file.write('\n//--Material Definitions--\n\n')
# Convert all materials to strings we can access directly per vertex.
writeMaterial(None) # default material
for material in bpy.data.materials:
writeMaterial(material)
if comments: file.write('\n')
if comments: file.write('//--Meta objects--\n\n') # <- How can this be written only if the scene contains META? Activating a boolean just before meta export and testing it here?
if comments: file.write('\n') # <- How can this be written only if the scene contains META?
if comments: file.write('//--Mesh objecs--\n\n')
#What follow used to happen here:
#exportCamera()
#exportWorld(scene.world)
#exportGlobalSettings(scene)
#...and the order was important for an attempt to implement pov 3.7 baking (mesh camera) comment for the record
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.name, 'w')
file.write("Input_File_Name='%s'\n" % filename_pov.name)
file.write("Output_File_Name='%s'\n" % filename_image.name)
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')
Doug Hammond
committed
DELAY = 0.05
# mktemp is Deprecated since version 2.3, replaced with NamedTemporaryFile() #CR
self._temp_file_in = tempfile.NamedTemporaryFile(suffix='.pov', delete=False)
self._temp_file_out = tempfile.NamedTemporaryFile(suffix='.png', delete=False)#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.NamedTemporaryFile(suffix='.tga', delete=False)
self._temp_file_ini = tempfile.NamedTemporaryFile(suffix='.ini', delete=False)
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.name) # so as not to load the old file
pass
write_pov_ini(self._temp_file_ini, self._temp_file_in, self._temp_file_out)
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
if 1:
# TODO, when povray isnt found this gives a cryptic error, would be nice to be able to detect if it exists
try:
self._process = subprocess.Popen([pov_binary, self._temp_file_ini.name] + extra_args) # stdout=subprocess.PIPE, stderr=subprocess.PIPE
print("POVRAY 3.7: could not execute '%s', possibly povray isn't installed" % pov_binary)
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.name))
return True
def _cleanup(self):
for f in (self._temp_file_in, self._temp_file_ini, self._temp_file_out):
#print('Name: %s' % f.name)
#print('File closed %s' % f.closed)
f.close() # Why do I have to close them again? Without closeing the pov and ini files are not deletable. PNG is not closable!
except OSError: #was that the proper error type?
#print('Couldn't remove/unlink TEMP file %s' % f.name)
self.update_stats('', 'POVRAY 3.7: Exporting data from Blender')
self.update_stats('', 'POVRAY 3.7: Parsing File')
##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.name):
# print('***POV WAITING FOR FILE***')
Doug Hammond
committed
poll_result = self._process.poll()
print('***POV PROCESS FAILED : %s ***' % poll_result)
self.update_stats('', 'POVRAY 3.7: Failed')
if os.path.exists(self._temp_file_out.name):
# print('***POV FILE OK***')
self.update_stats('', 'POVRAY 3.7: Rendering')
result = self.begin_result(0, 0, x, y)
lay = result.layers[0]
# possible the image wont load early on.
try:
pass
self.end_result(result)
# Update while povray renders
while True:
update_image()
break
# user exit
if self.test_break():
try:
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.name)
if new_size != prev_size:
update_image()
prev_size = new_size
time.sleep(self.DELAY)
Doug Hammond
committed
else:
Doug Hammond
committed
print('***POV FINISHED***')
#time.sleep(self.DELAY)