blender-addons/render_povray/render.py
2023-07-05 09:41:03 +02:00

812 lines
32 KiB
Python
Executable File

# SPDX-License-Identifier: GPL-2.0-or-later
"""Write the POV file using this file's functions and some from other modules then render it."""
import bpy
import subprocess
import os
from sys import platform
#import time
from math import (
pi,
) # maybe move to scenography.py and topology_*****_data.py respectively with smoke and matrix
import mathutils #import less than full
import tempfile # generate temporary files with random names
from bpy.types import Operator
from bpy.utils import register_class, unregister_class
from . import (
scripting,
) # for writing, importing and rendering directly POV Scene Description Language items
from . import render_core
from . import scenography # for atmosphere, environment, effects, lighting, camera
from . import shading # for BI POV shaders emulation
from . import nodes_fn
from . import texturing_procedural # for Blender procedurals to POV patterns emulation
from . import model_all # for mesh based geometry
from . import model_meta_topology # for mesh based geometry
from . import model_curve_topology # for curves based geometry
# from . import model_primitives # for import and export of POV specific primitives
from .scenography import image_format, img_map, img_map_transforms, path_image
from .shading import write_object_material_interior
from .model_primitives import write_object_modifiers
tab_level = 0
tab=""
comments = False
using_uberpov = False
unpacked_images = []
from .render_core import (
preview_dir,
PovRender,
)
def string_strip_hyphen(name):
"""Remove hyphen characters from a string to avoid POV errors."""
return name.replace("-", "")
def safety(name, ref_level_bound):
"""append suffix characters to names of various material declinations.
Material declinations are necessary to POV syntax and used in shading.py
by the pov_has_no_specular_maps function to create the finish map trick and
the suffixes avoid name collisions.
Keyword arguments:
name -- the initial material name as a string
ref_level_bound -- the enum number of the ref_level_bound being written:
ref_level_bound=1 is for texture with No specular nor Mirror reflection
ref_level_bound=2 is for texture with translation of spec and mir levels
for when no map influences them
ref_level_bound=3 is for texture with Maximum Spec and Mirror
"""
# All the try except clause below seems useless as each time
# prefix rewritten even after and outside of it what was the point?
# It may not even be any longer possible to feed no arg from Blender UI
# try:
# if name: # if int(name) > 0: # could be zero if no argument provided
# # and always triggered exception so is this similar ?
# prefix = "shader"
# except BaseException as e:
# print(e.__doc__)
# print('An exception occurred: {}'.format(e))
# prefix = "" # rewritten below...
prefix = "shader_"
name = string_strip_hyphen(name)
if ref_level_bound == 2:
return prefix + name
# implicit else-if (no return yet)
if ref_level_bound == 1:
return prefix + name + "0" # used for 0 of specular map
# implicit else-if (no return yet)
if ref_level_bound == 3:
return prefix + name + "1" # used for 1 of specular map
# -------- end safety string name material
csg_list = []
def is_renderable(ob):
"""test for objects flagged as hidden or boolean operands not to render"""
return not ob.hide_render and ob not in csg_list
def renderable_objects():
"""test for non hidden, non boolean operands objects to render"""
return [ob for ob in bpy.data.objects if is_renderable(ob)]
def non_renderable_objects():
"""Boolean operands only. Not to render"""
return list(csg_list)
def set_tab(tabtype, spaces):
"""Apply the configured indentation all along the exported POV file
Arguments:
tabtype -- Specifies user preference between tabs or spaces indentation
spaces -- If using spaces, sets the number of space characters to use
Returns:
The beginning blank space for each line of the generated pov file
"""
tab_str = ""
match tabtype:
case 'SPACE':
tab_str = spaces * " "
case 'NONE':
tab_str = ""
case 'TAB':
tab_str = "\t"
return tab_str
'''
# below properties not added to __init__ yet to avoid conflicts with material sss scale
# unless it would override then should be interfaced also in scene units property tab
# if scene.pov.sslt_enable:
# file.write(" mm_per_unit %s\n"%scene.pov.mm_per_unit)
# file.write(" subsurface {\n")
# file.write(" samples %s, %s\n"%(scene.pov.sslt_samples_max,scene.pov.sslt_samples_min))
# if scene.pov.sslt_radiosity:
# file.write(" radiosity on\n")
# file.write("}\n")
'''
# def write_object_modifiers(ob, File):
# """Translate some object level POV statements from Blender UI
# to POV syntax and write to exported file """
# # Maybe return that string to be added instead of directly written.
# '''XXX WIP
# import .model_all.write_object_csg_inside_vector
# write_object_csg_inside_vector(ob, file)
# '''
# if ob.pov.hollow:
# File.write("\thollow\n")
# if ob.pov.double_illuminate:
# File.write("\tdouble_illuminate\n")
# if ob.pov.sturm:
# File.write("\tsturm\n")
# if ob.pov.no_shadow:
# File.write("\tno_shadow\n")
# if ob.pov.no_image:
# File.write("\tno_image\n")
# if ob.pov.no_reflection:
# File.write("\tno_reflection\n")
# if ob.pov.no_radiosity:
# File.write("\tno_radiosity\n")
# if ob.pov.inverse:
# File.write("\tinverse\n")
# if ob.pov.hierarchy:
# File.write("\thierarchy\n")
# # XXX, Commented definitions
# '''
# if scene.pov.photon_enable:
# File.write("photons {\n")
# if ob.pov.target:
# File.write("target %.4g\n"%ob.pov.target_value)
# if ob.pov.refraction:
# File.write("refraction on\n")
# if ob.pov.reflection:
# File.write("reflection on\n")
# if ob.pov.pass_through:
# File.write("pass_through\n")
# File.write("}\n")
# if ob.pov.object_ior > 1:
# File.write("interior {\n")
# File.write("ior %.4g\n"%ob.pov.object_ior)
# if scene.pov.photon_enable and ob.pov.target and ob.pov.refraction and ob.pov.dispersion:
# File.write("ior %.4g\n"%ob.pov.dispersion_value)
# File.write("ior %s\n"%ob.pov.dispersion_samples)
# if scene.pov.photon_enable == False:
# File.write("caustics %.4g\n"%ob.pov.fake_caustics_power)
# '''
def tab_write(file, str_o, scene=None):
"""write directly to exported file if user checked autonamed temp files (faster).
Otherwise, indent POV syntax from brackets levels and write to exported file"""
if not scene:
scene = bpy.data.scenes[0]
global tab
tab = set_tab(scene.pov.indentation_character, scene.pov.indentation_spaces)
if scene.pov.tempfiles_enable:
file.write(str_o)
else:
global tab_level
brackets = str_o.count("{") - str_o.count("}") + str_o.count("[") - str_o.count("]")
if brackets < 0:
tab_level = tab_level + brackets
if tab_level < 0:
print("Indentation Warning: tab_level = %s" % tab_level)
tab_level = 0
if tab_level >= 1:
file.write("%s" % tab * tab_level)
file.write(str_o)
if brackets > 0:
tab_level = tab_level + brackets
def write_matrix(file, matrix):
"""Translate some transform matrix from Blender UI
to POV syntax and write to exported file """
tab_write(file,
"matrix <%.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f>\n"
% (
matrix[0][0],
matrix[1][0],
matrix[2][0],
matrix[0][1],
matrix[1][1],
matrix[2][1],
matrix[0][2],
matrix[1][2],
matrix[2][2],
matrix[0][3],
matrix[1][3],
matrix[2][3],
)
)
global_matrix = mathutils.Matrix.Rotation(-pi / 2.0, 4, 'X')
def write_pov(filename, scene=None, info_callback=None):
"""Main export process from Blender UI to POV syntax and write to exported file """
with open(filename, "w") as file:
# Only for testing
if not scene:
scene = bpy.data.scenes[0]
render = scene.render
world = scene.world
global comments
comments = scene.pov.comments_enable and not scene.pov.tempfiles_enable
feature_set = bpy.context.preferences.addons[__package__].preferences.branch_feature_set_povray
global using_uberpov
using_uberpov = feature_set == 'uberpov'
pov_binary = PovRender._locate_binary()
if using_uberpov:
print("Unofficial UberPOV feature set chosen in preferences")
else:
print("Official POV-Ray 3.7 feature set chosen in preferences")
if 'uber' in pov_binary:
print("The name of the binary suggests you are probably rendering with Uber POV engine")
else:
print("The name of the binary suggests you are probably rendering with standard POV engine")
def unique_name(name, name_seq):
"""Increment any generated POV name that could get identical to avoid collisions"""
if name not in name_seq:
name = string_strip_hyphen(name)
return name
name_orig = name
i = 1
while name in name_seq:
name = "%s_%.3d" % (name_orig, i)
i += 1
name = string_strip_hyphen(name)
return name
material_names_dictionary = {}
DEF_MAT_NAME = "" # or "Default"?
# -----------------------------------------------------------------------------
def export_global_settings(scene):
"""write all POV global settings to exported file """
# Imperial units warning
if scene.unit_settings.system == "IMPERIAL":
print("Warning: Imperial units not supported")
tab_write(file, "global_settings {\n")
tab_write(file, "assumed_gamma 1.0\n")
tab_write(file, "max_trace_level %d\n" % scene.pov.max_trace_level)
if scene.pov.global_settings_advanced:
if not scene.pov.radio_enable:
file.write(" adc_bailout %.6f\n" % scene.pov.adc_bailout)
file.write(" ambient_light <%.6f,%.6f,%.6f>\n" % scene.pov.ambient_light[:])
file.write(" irid_wavelength <%.6f,%.6f,%.6f>\n" % scene.pov.irid_wavelength[:])
file.write(" number_of_waves %s\n" % scene.pov.number_of_waves)
file.write(" noise_generator %s\n" % scene.pov.noise_generator)
if scene.pov.radio_enable:
tab_write(file, "radiosity {\n")
tab_write(file, "adc_bailout %.4g\n" % scene.pov.radio_adc_bailout)
tab_write(file, "brightness %.4g\n" % scene.pov.radio_brightness)
tab_write(file, "count %d\n" % scene.pov.radio_count)
tab_write(file, "error_bound %.4g\n" % scene.pov.radio_error_bound)
tab_write(file, "gray_threshold %.4g\n" % scene.pov.radio_gray_threshold)
tab_write(file, "low_error_factor %.4g\n" % scene.pov.radio_low_error_factor)
tab_write(file, "maximum_reuse %.4g\n" % scene.pov.radio_maximum_reuse)
tab_write(file, "minimum_reuse %.4g\n" % scene.pov.radio_minimum_reuse)
tab_write(file, "nearest_count %d\n" % scene.pov.radio_nearest_count)
tab_write(file, "pretrace_start %.3g\n" % scene.pov.radio_pretrace_start)
tab_write(file, "pretrace_end %.3g\n" % scene.pov.radio_pretrace_end)
tab_write(file, "recursion_limit %d\n" % scene.pov.radio_recursion_limit)
tab_write(file, "always_sample %d\n" % scene.pov.radio_always_sample)
tab_write(file, "normal %d\n" % scene.pov.radio_normal)
tab_write(file, "media %d\n" % scene.pov.radio_media)
tab_write(file, "subsurface %d\n" % scene.pov.radio_subsurface)
tab_write(file, "}\n")
once_sss = 1
once_ambient = 1
once_photons = 1
for material in bpy.data.materials:
if material.pov_subsurface_scattering.use and once_sss:
# In pov, the scale has reversed influence compared to blender. these number
# should correct that
tab_write(file,
"mm_per_unit %.6f\n" % (material.pov_subsurface_scattering.scale * 1000.0)
)
# 1000 rather than scale * (-100.0) + 15.0))
# In POV-Ray, the scale factor for all subsurface shaders needs to be the same
# formerly sslt_samples were multiplied by 100 instead of 10
sslt_samples = (11 - material.pov_subsurface_scattering.error_threshold) * 10
tab_write(file, "subsurface { samples %d, %d }\n" % (sslt_samples, sslt_samples / 10))
once_sss = 0
if world and once_ambient:
tab_write(file, "ambient_light rgb<%.3g, %.3g, %.3g>\n" % world.pov.ambient_color[:])
once_ambient = 0
if (
scene.pov.photon_enable
and once_photons
and (
material.pov.refraction_type == "2"
or material.pov.photons_reflection
)
):
tab_write(file, "photons {\n")
tab_write(file, "spacing %.6f\n" % scene.pov.photon_spacing)
tab_write(file, "max_trace_level %d\n" % scene.pov.photon_max_trace_level)
tab_write(file, "adc_bailout %.3g\n" % scene.pov.photon_adc_bailout)
tab_write(file,
"gather %d, %d\n"
% (scene.pov.photon_gather_min, scene.pov.photon_gather_max)
)
if scene.pov.photon_map_file_save_load in {'save'}:
ph_file_name = 'Photon_map_file.ph'
if scene.pov.photon_map_file != '':
ph_file_name = scene.pov.photon_map_file + '.ph'
ph_file_dir = tempfile.gettempdir()
path = bpy.path.abspath(scene.pov.photon_map_dir)
if os.path.exists(path):
ph_file_dir = path
full_file_name = os.path.join(ph_file_dir, ph_file_name)
tab_write(file, 'save_file "%s"\n' % full_file_name)
scene.pov.photon_map_file = full_file_name
if scene.pov.photon_map_file_save_load in {'load'}:
full_file_name = bpy.path.abspath(scene.pov.photon_map_file)
if os.path.exists(full_file_name):
tab_write(file, 'load_file "%s"\n' % full_file_name)
tab_write(file, "}\n")
once_photons = 0
tab_write(file, "}\n")
# sel = renderable_objects() #removed for booleans
if comments:
file.write(
"//----------------------------------------------\n"
"//--Exported with POV-Ray exporter for Blender--\n"
"//----------------------------------------------\n\n"
)
file.write("#version 3.7;\n") # Switch below as soon as 3.8 beta gets easy linked
# file.write("#version 3.8;\n")
file.write(
"#declare Default_texture = texture{pigment {rgb 0.8} " "finish {brilliance 3.8} }\n\n"
)
if comments:
file.write("\n//--Global settings--\n\n")
export_global_settings(scene)
if comments:
file.write("\n//--Custom Code--\n\n")
scripting.export_custom_code(file)
if comments:
file.write("\n//--Patterns Definitions--\n\n")
local_pattern_names = []
for texture in bpy.data.textures: # ok?
if texture.users > 0:
current_pat_name = string_strip_hyphen(bpy.path.clean_name(texture.name))
# string_strip_hyphen(patternNames[texture.name]) #maybe instead of the above
local_pattern_names.append(current_pat_name)
# use above list to prevent writing texture instances several times and assign in mats?
if (
texture.type not in {'NONE', 'IMAGE'} and texture.pov.tex_pattern_type == 'emulator'
) or (texture.type in {'NONE', 'IMAGE'} and texture.pov.tex_pattern_type != 'emulator'):
file.write("\n#declare PAT_%s = \n" % current_pat_name)
file.write(texturing_procedural.export_pattern(texture))
file.write("\n")
if comments:
file.write("\n//--Background--\n\n")
scenography.export_world(file, scene.world, scene, global_matrix, tab_write)
if comments:
file.write("\n//--Cameras--\n\n")
scenography.export_camera(file, scene, global_matrix, render, tab_write)
if comments:
file.write("\n//--Lamps--\n\n")
for ob in bpy.data.objects:
if ob.type == 'MESH':
for mod in ob.modifiers:
if mod.type == 'BOOLEAN' and mod.object not in csg_list:
csg_list.append(mod.object)
if csg_list:
csg = False
sel = non_renderable_objects()
# export non rendered boolean objects operands
model_all.objects_loop(
file,
scene,
sel,
csg,
material_names_dictionary,
unpacked_images,
tab_level,
tab_write,
info_callback,
)
csg = True
sel = renderable_objects()
scenography.export_lights(
[L for L in sel if (L.type == 'LIGHT' and L.pov.object_as != 'RAINBOW')],
file,
scene,
global_matrix,
tab_write,
)
if comments:
file.write("\n//--Rainbows--\n\n")
scenography.export_rainbows(
[L for L in sel if (L.type == 'LIGHT' and L.pov.object_as == 'RAINBOW')],
file,
scene,
global_matrix,
tab_write,
)
if comments:
file.write("\n//--Special Curves--\n\n")
for c in sel:
if c.is_modified(scene, 'RENDER'):
continue # don't export as pov curves objects with modifiers, but as mesh
# Implicit else-if (as not skipped by previous "continue")
if c.type == 'CURVE' and (c.pov.curveshape in {'lathe', 'sphere_sweep', 'loft', 'birail'}):
model_curve_topology.export_curves(file, c, tab_write)
if comments:
file.write("\n//--Material Definitions--\n\n")
# write a default pigment for objects with no material (comment out to show black)
file.write("#default{ pigment{ color srgb 0.8 }}\n")
# Convert all materials to strings we can access directly per vertex.
# exportMaterials()
shading.write_material(
file,
using_uberpov,
DEF_MAT_NAME,
tab_write,
comments,
unique_name,
material_names_dictionary,
None,
) # default material
for material in bpy.data.materials:
if material.users > 0:
r, g, b, a = material.diffuse_color[:]
pigment_color = "pigment {rgbt <%.4g,%.4g,%.4g,%.4g>}" % (r, g, b, 1 - a)
if material.pov.material_use_nodes:
# Also make here other pigment_color fallback using BSDF node main color ?
ntree = material.node_tree
pov_mat_name = string_strip_hyphen(bpy.path.clean_name(material.name))
if len(ntree.nodes) == 0:
file.write('#declare %s = texture {%s}\n' % (pov_mat_name, pigment_color))
else:
nodes_fn.write_nodes(pov_mat_name, ntree, file)
for node in ntree.nodes:
if node:
if node.bl_idname == "PovrayOutputNode":
if node.inputs["Texture"].is_linked:
for link in ntree.links:
if link.to_node.bl_idname == "PovrayOutputNode":
pov_mat_name = (
string_strip_hyphen(
bpy.path.clean_name(link.from_node.name)
)
+ "_%s" % pov_mat_name
)
else:
file.write(
'#declare %s = texture {%s}\n' % (pov_mat_name, pigment_color)
)
else:
shading.write_material(
file,
using_uberpov,
DEF_MAT_NAME,
tab_write,
comments,
unique_name,
material_names_dictionary,
material,
)
# attributes are all the variables needed by the other python file...
if comments:
file.write("\n")
model_meta_topology.export_meta(file,
[m for m in sel if m.type == 'META'],
material_names_dictionary,
tab_write,
DEF_MAT_NAME,)
if comments:
file.write("//--Mesh objects--\n")
# tbefore = time.time()
model_all.objects_loop(
file,
scene,
sel,
csg,
material_names_dictionary,
unpacked_images,
tab_level,
tab_write,
info_callback,
)
# totime = time.time() - tbefore
# print("objects_loop took" + str(totime))
# What follow used to happen here:
# export_camera()
# scenography.export_world(file, scene.world, scene, global_matrix, tab_write)
# export_global_settings(scene)
# MR:..and the order was important for implementing pov 3.7 baking
# (mesh camera) comment for the record
# CR: Baking should be a special case than. If "baking", than we could change the order.
if not file.closed:
file.close()
def write_pov_ini(filename_ini, filename_log, filename_pov, filename_image):
"""Write ini file."""
feature_set = bpy.context.preferences.addons[__package__].preferences.branch_feature_set_povray
global using_uberpov
using_uberpov = feature_set == 'uberpov'
# scene = bpy.data.scenes[0]
scene = bpy.context.scene
render = scene.render
x = int(render.resolution_x * render.resolution_percentage * 0.01)
y = int(render.resolution_y * render.resolution_percentage * 0.01)
with open(filename_ini, "w") as file:
file.write("Version=3.7\n")
# write povray text stream to temporary file of same name with _log suffix
# file.write("All_File='%s'\n" % filename_log)
# DEBUG.OUT log if none specified:
file.write("All_File=1\n")
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)
# Border render.
if render.use_border:
file.write("Start_Column=%4g\n" % render.border_min_x)
file.write("End_Column=%4g\n" % render.border_max_x)
file.write("Start_Row=%4g\n" % (1.0 - render.border_max_y))
file.write("End_Row=%4g\n" % (1.0 - render.border_min_y))
file.write("Bounding_Method=2\n") # The new automatic BSP is faster in most scenes
# Activated (turn this back off when better live exchange is done between the two programs
# (see next comment)
file.write("Display=1\n")
file.write("Pause_When_Done=0\n")
# PNG, with POV-Ray 3.7, can show background color with alpha. In the long run using the
# POV-Ray interactive preview like bishop 3D could solve the preview for all formats.
file.write("Output_File_Type=N\n")
# file.write("Output_File_Type=T\n") # TGA, best progressive loading
file.write("Output_Alpha=1\n")
if scene.pov.antialias_enable:
# method 2 (recursive) with higher max subdiv forced because no mipmapping in POV-Ray
# needs higher sampling.
# aa_mapping = {"5": 2, "8": 3, "11": 4, "16": 5}
if using_uberpov:
method = {"0": 1, "1": 2, "2": 3}
else:
method = {"0": 1, "1": 2, "2": 2}
file.write("Antialias=on\n")
file.write("Antialias_Depth=%d\n" % scene.pov.antialias_depth)
file.write("Antialias_Threshold=%.3g\n" % scene.pov.antialias_threshold)
if using_uberpov and scene.pov.antialias_method == '2':
file.write("Sampling_Method=%s\n" % method[scene.pov.antialias_method])
file.write("Antialias_Confidence=%.3g\n" % scene.pov.antialias_confidence)
else:
file.write("Sampling_Method=%s\n" % method[scene.pov.antialias_method])
file.write("Antialias_Gamma=%.3g\n" % scene.pov.antialias_gamma)
if scene.pov.jitter_enable:
file.write("Jitter=on\n")
file.write("Jitter_Amount=%3g\n" % scene.pov.jitter_amount)
else:
file.write("Jitter=off\n") # prevent animation flicker
else:
file.write("Antialias=off\n")
if not file.closed:
file.close()
# --------------------------------------------------------------------------------- #
# ----------------------------------- Operators ----------------------------------- #
# --------------------------------------------------------------------------------- #
class RenderPovTexturePreview(Operator):
"""Export only files necessary to texture preview and render image"""
bl_idname = "tex.preview_update"
bl_label = "Update preview"
def execute(self, context):
tex = bpy.context.object.active_material.active_texture # context.texture
tex_prev_name = string_strip_hyphen(bpy.path.clean_name(tex.name)) + "_prev"
# Make sure Preview directory exists and is empty
if not os.path.isdir(preview_dir):
os.mkdir(preview_dir)
ini_prev_file = os.path.join(preview_dir, "Preview.ini")
input_prev_file = os.path.join(preview_dir, "Preview.pov")
output_prev_file = os.path.join(preview_dir, tex_prev_name)
# ---------------------------------- ini ---------------------------------- #
with open(ini_prev_file, "w") as file_ini:
file_ini.write('Version=3.8\n')
file_ini.write('Input_File_Name="%s"\n' % input_prev_file)
file_ini.write('Output_File_Name="%s.png"\n' % output_prev_file)
file_ini.write('Library_Path="%s"\n' % preview_dir)
file_ini.write('Width=256\n')
file_ini.write('Height=256\n')
file_ini.write('Pause_When_Done=0\n')
file_ini.write('Output_File_Type=N\n')
file_ini.write('Output_Alpha=1\n')
file_ini.write('Antialias=on\n')
file_ini.write('Sampling_Method=2\n')
file_ini.write('Antialias_Depth=3\n')
file_ini.write('-d\n')
if not file_ini.closed:
file_ini.close()
# ---------------------------------- pov ---------------------------------- #
with open(input_prev_file, "w") as file_pov:
pat_name = "PAT_" + string_strip_hyphen(bpy.path.clean_name(tex.name))
file_pov.write("#declare %s = \n" % pat_name)
file_pov.write(texturing_procedural.export_pattern(tex))
file_pov.write("#declare Plane =\n")
file_pov.write("mesh {\n")
file_pov.write(
" triangle {<-2.021,-1.744,2.021>,<-2.021,-1.744,-2.021>,<2.021,-1.744,2.021>}\n"
)
file_pov.write(
" triangle {<-2.021,-1.744,-2.021>,<2.021,-1.744,-2.021>,<2.021,-1.744,2.021>}\n"
)
file_pov.write(" texture{%s}\n" % pat_name)
file_pov.write("}\n")
file_pov.write("object {Plane}\n")
file_pov.write("light_source {\n")
file_pov.write(" <0,4.38,-1.92e-07>\n")
file_pov.write(" color rgb<4, 4, 4>\n")
file_pov.write(" parallel\n")
file_pov.write(" point_at <0, 0, -1>\n")
file_pov.write("}\n")
file_pov.write("camera {\n")
file_pov.write(" location <0, 0, 0>\n")
file_pov.write(" look_at <0, 0, -1>\n")
file_pov.write(" right <-1.0, 0, 0>\n")
file_pov.write(" up <0, 1, 0>\n")
file_pov.write(" angle 96.805211\n")
file_pov.write(" rotate <-90.000003, -0.000000, 0.000000>\n")
file_pov.write(" translate <0.000000, 0.000000, 0.000000>\n")
file_pov.write("}\n")
if not file_pov.closed:
file_pov.close()
# ------------------------------- end write ------------------------------- #
pov_binary = PovRender._locate_binary()
if platform.startswith('win'):
with subprocess.Popen(
["%s" % pov_binary, "/EXIT", "%s" % ini_prev_file],
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
) as p1:
p1.wait()
else:
with subprocess.Popen(
["%s" % pov_binary, "-d", "%s" % ini_prev_file],
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
) as p1:
p1.wait()
tex.use_nodes = True
tree = tex.node_tree
links = tree.links
for n in tree.nodes:
tree.nodes.remove(n)
im = tree.nodes.new("TextureNodeImage")
path_prev = "%s.png" % output_prev_file
im.image = bpy.data.images.load(path_prev)
name = path_prev
name = name.split("/")
name = name[len(name) - 1]
im.name = name
im.location = 200, 200
previewer = tree.nodes.new('TextureNodeOutput')
previewer.label = "Preview"
previewer.location = 400, 400
links.new(im.outputs[0], previewer.inputs[0])
# tex.type="IMAGE" # makes clip extend possible
# tex.extension="CLIP"
return {'FINISHED'}
class RunPovTextRender(Operator):
"""Export files depending on text editor options and render image."""
bl_idname = "text.run"
bl_label = "Run"
bl_context = "text"
bl_description = "Run a render with this text only"
def execute(self, context):
scene = context.scene
scene.pov.text_block = context.space_data.text.name
bpy.ops.render.render()
# empty text name property again
scene.pov.text_block = ""
return {'FINISHED'}
classes = (
#PovRender,
RenderPovTexturePreview,
RunPovTextRender,
)
def register():
for cls in classes:
register_class(cls)
scripting.register()
def unregister():
scripting.unregister()
for cls in reversed(classes):
unregister_class(cls)